今天我的朋友提出了一个我仍然无法解决的挑战:"在PHP中生成一个随机数字序列"
数字排列为拨号盘/模式锁,包含3行3列的1-9个键:
---------------------------
| |
| 1 2 3 |
| |
| 4 5 6 |
| |
| 7 8 9 |
| |
---------------------------
现在,给定长度,我们必须使用以下标准生成所提供长度的随机,非重复数字序列:
生成的序列应遵循特定的方向/模式,仅通过相邻的数字(可能是对角线),例如(长度:8),12569874:
1 2
4 5 6
7 8 9
第一行的数字永远不应该跟第三行的数字相反,反之亦然。列也一样。例如,1后面不能跟8,而6后面不能跟4。
可以从android模式锁系统中轻松猜出更多标准
以下是长度为9的一些示例生成序列:12369874 / 5,142536987等,长度= 6:987532等
我尝试使用rand()
执行此操作:
$chars = "123456789";
$length = 9;
$clen = strlen( $chars )-1;
$id = '';
for ($i = 0; $i < $length; $i++) {
$id .= $chars[mt_rand(0,$clen)];
}
return ($id);
但是,仍然没有运气......
我该如何解决这个问题?
答案 0 :(得分:3)
有一些限制,但这是你的工作。我收到报酬时只处理头痛问题:)。
<pre>
<?php
// Keypad
$grid = [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
];
// Sequence Target Length
$target_length = 5;
// Place to store the Keypad sequence
$points = [];
// Starting Point
$x = rand(0, 2);
$y = rand(0, 2);
// Run through the process until we have the sequence at the desired length
while (count($points) < $target_length):
// Check if the grid keypad entry has been used
if ($grid[$x][$y]):
// Hasn't been used, so stire it
$points[] = $grid[$x][$y];
// Mark it used
$grid[$x][$y] = NULL;
endif;
// Sanity Check, imagine if you will,.... target length of 9, and you hit 6 5 2 1, You'll vault off into the twilight zone without this
if ((!$grid[$x + 1][$y]) && (!$grid[$x][$y + 1]) && (!$grid[$x - 1][$y]) && (!$grid[$x][$y - 1])):
// We have no where to go
break;
endif;
// Start looking for possible values
do {
$test_x = $x;
$test_y = $y;
$dir = rand(0, 3);
switch ($dir):
case (0):
$test_y--; // Up
break;
case (1):
$test_x++; // Right
break;
case (2):
$test_y++; // Down
break;
case (3):
$test_x--; // Left
break;
endswitch;
// Optional Gibberish
echo "Moving from {$x}, {$y} to {$test_x}, {$test_y} --> " . (($grid[$test_x][$test_y] === NULL) ? 'FAILED' : 'OK!') . '<br>';
// Keep going until we find a valid direction
} while ($grid[$test_x][$test_y] === NULL);
// assign the new coords
$x = $test_x;
$y = $test_y;
// repeat
endwhile;
// report
echo implode('-', $points) . "\n";
?>
</pre>
答案 1 :(得分:2)
以下是适用这些规则的解决方案:
以下算法对添加到序列中的每个数字使用递归。每当序列发生&#34;卡住&#34;时,就会发生回溯,并尝试替代路径。如果没有其他选择,可以继续回溯。
保证返回给定长度的路径,前提是给定长度在1到9之间:
function randomSequence($len) {
if ($len < 1 || $len > 9) return []; // No results
$row = [null, 1, 1, 1, 2, 2, 2, 3, 3, 3];
$col = [null, 1, 2, 3, 1, 2, 3, 1, 2, 3];
$neighbors = [[], [2, 4, 5], [1, 4, 5, 6, 3], [2, 5, 6],
[1, 2, 5, 7, 8], [1, 2, 3, 4, 6, 7, 8, 9], [2, 3, 5, 8, 9],
[4, 5, 8], [4, 5, 6, 7, 9], [5, 6, 8]];
// Shuffle the neighbor lists to implement the randomness:
foreach ($neighbors as &$nodes) shuffle($nodes);
$recurse = function ($seq) use (&$len, &$row, &$col, &$neighbors, &$recurse) {
if (count($seq) >= $len) return $seq; // found solution
$last = end($seq);
echo "try " . json_encode(array_keys($seq)) . "\n";
foreach ($neighbors[$last] as $next) {
if (isset($seq[$next])) continue; // Skip if digit already used
$result = $recurse($seq + [$next => $next]);
if (is_array($result)) return $result;
}
};
$choice = rand(1, 9);
return array_keys($recurse([$choice => $choice]));
}
echo "result: " . json_encode(randomSequence(9)) . "\n";
上查看它
答案 2 :(得分:0)
以下是矩阵的伪代码示例,如下所示:
1 2
3 4
# Get which other numbers are "legal moves" from each number.
adjacency = {
1: [2, 3],
2: [1, 4],
3: [1, 4],
4: [2, 3]
}
# Get the length of code required.
n = 8
# Start at a random position;
pos = rand(keys(adjacency))
result = []
while (n > 0)
n -= 1
newpos = rand(adjacency[pos])
result[] = newpos
pos = newpos
print(result.join(', '))
如果您的矩阵变大或者变化很大,您可能需要编写一些代码来生成adjaceny
而不是硬编码。