递归函数无限循环

我正在进行一个个人项目,一个玩四子棋的机器人。所以我编写的管理机器人移动的递归函数出现了严重问题。没有抛出任何错误,我能看到的任何调试信息也没有告诉我任何有用的东西。此外,我确定我没有溢出堆栈,我的php.ini文件也设置正确。这个脚本只是运行(消耗合理的内存量)并且永远不会返回。应该只发生大约2400次函数调用,所以这个脚本应该在一两秒内返回。这让我困惑了好几天。我认为有些东西我没有充分研究。另外,我应该提到游戏棋盘是一个简单的二维数组,用来模拟一个7×7的棋盘。ai_move_helper是递归函数,我就是搞不明白为什么它不能正常工作。

// 这个类是一个CodeIgniter库class ConnectFour{    public function __construct()    {        // 这些是昂贵的操作,这将给服务器足够的时间        set_time_limit(0);        ini_set('memory_limit', '2048M');    }    public $board_width     = 7;    public $board_length    = 7;    public $game_array      = array();    public $depth_limit     = 3;            // 这个函数从CI控制器获取人类的移动($game board)            // 并返回应用新AI移动后的棋盘    public function ai_player_move($game_array, $active_players_move)    {        $this->game_array = $game_array;                    $this->game_array = $this->calculate_ai_move($active_players_move);        return $this->game_array;       }    public function calculate_ai_move($active_players_move)    {        $move_weight_array = array();        $prime_game_board = array();        // 我们硬编码活跃玩家,因为此时我们知道是AI        // 这里我们还需要启动移动计算器        for($q = 0; $q < $this->board_length; $q++)        {            // MAGIC NUMBERS是活跃玩家!!!            $prime_game_board[] = $this->apply_prime_move($q, 2, $this->game_array);            $move_weight_array[] = $this->ai_move_helper($prime_game_board[$q], 2, 0);          }        //选择你的移动        for($u = 0; $u < $this->board_length; $u)        {            if($move_weight_array[$u][0] == 1)            {                return $prime_game_board[$u];                           }        }        // 否则返回一个随机的可接受移动        $random = rand(0, 6);        return $prime_game_board[$random];    }    public function ai_move_helper($game_board, $active_player, $depth)    {        // 构建在这个递归层级需要的对象        $depth = $depth + 1;        $score_object                               = new stdClass;        $move_array                                 = array();        $game_boards_generated_at_this_level        = array();         $new_game_boards_generated_at_this_level    = array();        $return_end_state_detected                  = 0;        $score_agregate                             = array();                  if($this->depth_limit < $depth)        {            $score_agregate[0] = 0;             $score_agregate[1] = 0;            return $score_agregate;         }        $active_player = ($active_player == 1) ? 2 : 1;        // 检查可能的移动        for($i=0; $i < $this->board_width; $i++)        {            // 计算所有可能的递归(所有下一步移动)            $game_boards_generated_at_this_level[$i] = $this->apply_ai_move($i, $active_player, $game_board);            // 这是递归层级            $score_agregate = $this->ai_move_helper($game_boards_generated_at_this_level[$i]->game_board, $active_player, $depth);                      }        // 检查是否有更多移动或者是否是返回的时候        foreach($game_boards_generated_at_this_level as $game_state)        {            //只为玩家二(AI)计算分数的总和            if($active_player == 2)            {                $score_agregate[0] = $score_agregate[0] + $game_state->score_array[0];                 $score_agregate[1] = $score_agregate[1] + $game_state->score_array[1];                          }        }        return $score_agregate;    }    public function apply_ai_move($move, $active_players_move, $board_to_use)    {        $board_for_function     = array();        $location_of_new_pieces = 0;        $return_object          = new stdClass;        // 这确保了这个函数是以正确的棋盘被调用        if(!empty($board_to_use))        {            $board_for_function = $board_to_use;        } else {            $board_for_function = $this->game_array;        }        // 检查这个移动是否可能        if(!$this->move_possible($move, $board_for_function))        {            $return_object->game_board      = NULL;            $return_object->score_array     = NULL;            return $return_object;        }        // 这个函数的一部分应用一个有效的移动        foreach($board_for_function[$move] as $column_key => $column_space)        {            // 检查是否在空行的边缘            if(!array_key_exists(($location_of_new_pieces + 1), $board_for_function[$move]) && $column_space == '_')            {                $board_for_function[$move][$location_of_new_pieces] = ($active_players_move == 1) ? 'x' : 'o';                break;            }            // 检查下一个位置是否也有东西            if($column_space != '_')            {                // 检查棋盘的边缘以确保存在                if(array_key_exists(($location_of_new_pieces - 1), $board_for_function))                {                    $board_for_function[$move][$location_of_new_pieces - 1] = ($active_players_move == 1) ? 'x' : 'o';                    break;                } else {                    echo "well fuck...1"; exit;                }            }            $location_of_new_pieces++;        }        $return_object->game_board = $board_for_function;        // 现在检查这个状态是否是赢、输或平局        $test_for_complete = $this->check_for_winner_or_draw($board_for_function, $active_players_move);        // 这是平局        if($test_for_complete == -1)        {            $return_object->score_array = array(0, 1);        } else if($test_for_complete > 3) {            $return_object->score_array = array(1, 0);        } else {            $return_object->score_array = array(0, 0);        }        return $return_object;    }    public function apply_prime_move($move, $active_players_move, $board_to_use)    {        $location_of_new_pieces = 0;        foreach($board_to_use[$move] as $column_key => $column_space)        {            // 检查是否在空行的边缘            if(!array_key_exists(($location_of_new_pieces + 1), $board_to_use[$move]) && $column_space == '_')            {                $board_to_use[$move][$location_of_new_pieces] = ($active_players_move == 1) ? 'x' : 'o';                break;            }            // 检查下一个位置是否也有东西            if($column_space != '_')            {                // 检查棋盘的边缘以确保存在                if(array_key_exists(($location_of_new_pieces - 1), $board_to_use))                {                    $board_to_use[$move][$location_of_new_pieces - 1] = ($active_players_move == 1) ? 'x' : 'o';                    break;                } else {                    echo "well fuck...1"; exit;                }            }            $location_of_new_pieces++;        }        return $board_to_use;    }    public function move_possible($move, $game_board)    {        // 检查这个移动是否会掉出棋盘        if($game_board[$move][0] != "_")        {            return FALSE;        } else {            return TRUE;        }    }    public function check_for_winner_or_draw($game_array, $active_player_move)    {        $present_possible_winner    = "";        $count_to_win               = 0;        $game_not_a_draw            = FALSE;        for($i = 0; $i < $this->board_length; $i++)        {            for($j = 0; $j < $this->board_width; $j++)            {                // 开始检查赢家                if($game_array[$i][$j] != "_")                {                    $present_possible_winner = $game_array[$i][$j];                     // 水平检查赢家                    for($x = 0; $x < 4; $x++)                    {                        if($j+$x < $this->board_width)                        {                            if($game_array[$i][$j+$x] == $present_possible_winner)                            {                                $count_to_win = $count_to_win + 1;                            }                        }                    }                    if($count_to_win > 3)                    {                        return $present_possible_winner;    // 这个玩家赢了                    } else {                        $count_to_win = 0;                    }                    // 垂直检查赢家                    for($y = 0; $y < 4; $y++)                    {                        if($i+$y < $this->board_width)                        {                            if($game_array[$i+$y][$j] == $present_possible_winner)                            {                                $count_to_win = $count_to_win + 1;                            }                        }                    }                    if($count_to_win > 3)                    {                        return $present_possible_winner;    // 这个玩家赢了                    } else {                        $count_to_win = 0;                    }                    // 检查从上到下的对角线赢家                    for($z = 0; $z < 4; $z++)                    {                        if(($i+$z < $this->board_width) && ($j+$z < $this->board_length))                        {                            if($game_array[$i+$z][$j+$z] == $present_possible_winner)                            {                                $count_to_win = $count_to_win + 1;                            }                        }                    }                    if($count_to_win > 3)                    {                        return $present_possible_winner;    // 这个玩家赢了                    } else {                        $count_to_win = 0;                    }                    // 检查从下到上的对角线赢家                    for($w = 0; $w < 4; $w++)                    {                        if(($i+$w < $this->board_width) && ($j-$w >= 0))                        {                            if($game_array[$i+$w][$j-$w] == $present_possible_winner)                            {                                $count_to_win = $count_to_win + 1;                            }                        }                    }                    if($count_to_win > 3)                    {                        return $present_possible_winner;    // 这个玩家赢了                    } else {                        $count_to_win = 0;                    }                }            }        }        // 检查是否为平局并相应返回        for($i = 0; $i < $this->board_length; $i++)        {            for($j = 0; $j < $this->board_width; $j++)            {                if($game_array[$i][$j] == "_")                {                    $game_not_a_draw = TRUE;                }            }        }        if(!$game_not_a_draw)        {            return -1;        }        return 0;    }            // 这是一个我为这个脚本编写的私有调试函数    public function debug($value = NULL, $name = NULL, $exit = NULL)    {        if(!empty($name))        {            echo $name . "<br />";                      }        echo "<pre>";        var_dump($value);        echo "</pre>";        if($exit)        {            exit;        }    }}

回答:

我找到了:计算AI移动的函数中有一个无限循环…

 //选择你的移动    for($u = 0; $u < $this->board_length; $u)    {        if($move_weight_array[$u][0] == 1)        {            return $prime_game_board[$u];                       }    }

应该改为

 //选择你的移动    for($u = 0; $u < $this->board_length; $u++)    {        if($move_weight_array[$u][0] == 1)        {            return $prime_game_board[$u];                       }    }

我得继续工作了…

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注