【问题标题】:Why code goes to infinite loop? (为什么代码进入无限循环? (
【发布时间】:2012-04-19 14:12:19
【问题描述】:
<?php
$mines = 10;

####
for($x=1; $x<=9; $x++) {
    for($y=1; $y<=9; $y++) {
        $minefield[$x][$y] = 0;
    }
}       

for($i=0; $i<$mines; $i++) {
    $randx = rand(1, 9);
    $randy = rand(1, 9);

    if($minefield[$randx][$randy] == 'X') {
        $i--;
    } else {
        $minefield[$randx][$randy] = 'X';
    }
}

我做错了什么?

【问题讨论】:

  • 你能在 $minefield 上做一个 print_r 吗?
  • $i-- 应该完成什么?是不是像“再试一次,这里已经有地雷了?”
  • @AlexHowansky 他想为地雷设置 10 个独特的位置。当 i-- 已经选择一个有地雷的位置时,它会导致循环“重试”。
  • @Andrew -- 嘿,刚刚意识到......
  • 我觉得这是一个在某种考试中问的好问题。

标签: php loops


【解决方案1】:

将字符串(或资源)与整数进行比较时,首先将字符串转换为数字as per the documentation,然后再进行比较。

因此,这个:

if ($minefield[$randx][$randy] == 'X')

...其中$minefield[$randx][$randy] = 0 等价于:

if (0 == 0) // 0 == (int)'X'

...这总是正确的。因此,您在每次迭代时递增递减$i

【讨论】:

  • 他试过'Y'?它是转换成 ASCII 值还是总是 0?
  • @11684: 也没有涉及 ASCII 转换。 PHP 将字符串转换为数字的规则是丢弃第一个非数字字符之后的所有内容。例如,(int)"Hello 1234" 给出0,而(int)"1234 Hello" 给出1234
  • 谢谢!我还不知道!
【解决方案2】:

我会尝试设置 $minefield[$x][$y] = '0';带引号,这样两种类型都是字符串。可能是个问题。

查看有关此主题的 PHP 手册 Comparing Strings to Numbers

【讨论】:

    【解决方案3】:

    作为准则,我不会在循环内执行 $i--,因为这是一个经典的无限循环生成器。 而是在内部执行另一个循环,不断生成随机地雷,直到它没有击中现有的地雷。

    【讨论】:

      【解决方案4】:

      您的问题还有另一种解决方案。您可以这样设置,并确保在有限的一组坐标中只选择 10 个位置:

      <?php
      
      // build minefield
      $minefield = array();
      for($x=1; $x<=9; $x++) {
          $minefield[$x] = array();
          for($y=1; $y<=9; $y++) {
              $minefield[$x][$y] = 0;
          }
      }
      
      // prepare cartesian func
      function array_cartesian() {
          $_ = func_get_args();
          if(count($_) == 0)
              return array(array());
          $a = array_shift($_);
          $c = call_user_func_array(__FUNCTION__, $_);
          $r = array();
          foreach($a as $v)
              foreach($c as $p)
                  $r[] = array_merge(array($v), $p);
          return $r;
      }
      
      // get coordinates
      $coords = array_cartesian(range(1,9), range(1,9));
      // pick random coordinates' keys
      $chosen_coords = array_rand($coords, 10);
      
      foreach ($chosen_coords as $key) {
          $minefield[$coords[$key][0]][$coords[$key][1]] = 'X';
      }
      

      我知道,它很长,但我可以用 Python 写成 2-3 行。

      附言。笛卡尔积的代码来自这里:https://stackoverflow.com/a/2516779/548696

      【讨论】:

        【解决方案5】:

        问题出在您的第二个循环中。由于索引是随机数,所以可能这些索引的数组值在else 语句中已设置为X,并且随机地,将一次又一次检查相同的索引,因此它将转到if声明,这里是你减去i的地方!

        在循环体中更改循环变量i 的值不是一个好习惯。

        【讨论】:

        • 我确信他知道他自己的代码是如何工作的,但是您所解释的内容不会产生无限循环。这可能会花费比预期更长的时间。
        • @JustinSatyr 它使一个无限循环!因为他将数组的所有值随机设置为X,然后如果它们等于X,他会减去循环变量!
        • 不,这不是无限循环,因为他有 81 个位置和 10 个地雷。因此,最终,他将达到无地雷位置并增加他的变量并继续。最坏的情况,需要几秒钟。
        • @JustinSatyr 也许你是对的,但批准的答案表明问题出在其他问题上......
        【解决方案6】:

        显然是因为您减少了循环计数器:

        if($minefield[$randx][$randy] == 'X') {
            $i--;
        } else {
            $minefield[$randx][$randy] = 'X';
        }
        

        在某一时刻,所有字段都将等于“X”,您将有一个无限循环。

        在for循环中玩索引是个很不好的习惯

        【讨论】:

        • 我的错,跳过了 $mines = 10... 在某些时候循环会结束,但这取决于你的 rand() 的随机性
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-29
        • 1970-01-01
        • 2014-02-13
        • 2021-09-18
        • 2013-12-30
        相关资源
        最近更新 更多