【问题标题】:Generalize move search algorithm to use recursion推广移动搜索算法以使用递归
【发布时间】:2013-02-19 18:43:02
【问题描述】:

我正在创建一个需要评估棋盘状态的简单 AI 根据定义的策略规则。游戏很像俄罗斯方块: 您需要根据棋盘状态和 下 N 个片段的序列(N 是一个变量)。

换句话说,您必须使用片段队列中的第一个片段(如俄罗斯方块与多个 “下一个”级别)。

对于一步到位,这很简单:

bestMove = function(Board board, piece piece)
{
     possibleMoves = getPossibleMoves(board, piece)
     bestMove = null
     bestScore = -INFINITY
     boardCp = clone(board)     

     for (move in possibleMoves)
     {
         tempBoard = applyMove(boardCp, move)
         if (tempBoard.score > bestScore)
         {
             bestMove = move
             bestScore = tempBoard.score
         }
         boardCp = undoMove(tempBoard, move)
     }

    return move
}

现在,我如何将这个算法推广到 N 个前进? 我不是递归专家,所以感谢您的帮助!

PS:我使用的是 Java,但欢迎使用任何语言或伪代码!

【问题讨论】:

  • 这是java吗?在我看来更像是 javascript。
  • 没关系,我只是尽量避免原始伪代码!
  • 哈哈,只是确保您不希望 java 解释它,现在正在寻找答案。

标签: java algorithm recursion artificial-intelligence


【解决方案1】:

这可以很容易地修改以考虑 N 步。以递归或迭代方式。

bestMove = function(Board board, piece piece, int lookAhead)
{
 possibleMoves = getPossibleMoves(board, piece)
 bestMove = null
 bestScore = -INFINITY
 boardCp = clone(board)     

 for (move in possibleMoves)
 {
    /* just the original code */
     if(lookAhead <= 1) {
         tempBoard = applyMove(boardCp, move)
         if (tempBoard.score > bestScore)
         {
             bestMove = move
             bestScore = tempBoard.score
          }
         boardCp = undoMove(tempBoard, move)
     }

     /* recursion, can be changed to a loop */
     else {
        tempBoard = applyMove(boardCp, move)                // apply
        move2 = bestMove(tempBoard, piece, lookAhead-1)     // dive and get best 
        boardCp = undoMove(tempBoard, move)                 // (1) check how good it actually is
        tempBoard = applyMove(boardCp, move2)
        if (tempBoard.score > bestScore)
         {
             bestMove = move2
             bestScore = tempBoard.score
          }
        boardCp = undoMove(tempBoard, move2)                // generaly I'd refactor both if-else paths and reuse some code
     }
  }

return bestMove
}    

如果你可以从一个函数返回 2 个值,那么 (1) 就没有必要了 - 你需要移动,它就是得分。

顺便说一句。您是否阅读过有关 min-max、alfa-beta(带有修剪)算法的文章?

【讨论】:

  • 我知道如何使用 alpha beta pruning 实现 Min-Max,但我可以申请这个案例吗?
  • 您的伪代码非常适合用于类似 min-max 的算法,这本质上就是您正在做的事情。你到底在问什么?
  • min-max 采用相对分数来评估移动,但在这种情况下,我没有“对手”,这就是为什么我没有尝试应用它......除非我缺少关于这种算法的一些概念。
  • 我并不是说你必须使用任何特定的算法,我只是提到了这两个,因为它们具有相同的递归前瞻概念。顺便提一句。如果你真的需要 a-b 或 min-max 算法。那么你总是可以用恒定的(0)分数/移动来嘲笑对手;-)
【解决方案2】:

纯递归算法。不知道你的下一个作品是如何组织的,所以在这里我使用了一个队列来假设。克隆不是最有效的,所以有点取决于你的数据结构。

 function getBestPossibleScore(Board board, Queue<piece>nextPieces){
         if (nextPieces.isEmpty())
             return board.score;
         piece = piece.pop();
         possibleMoves = getPossibleMoves(board, piece)   

         bestScore = -INFINITY
         boardCp = clone(board)     

         for (move in possibleMoves)
         {
             tempBoard = applyMove(boardCp, move)
             curentScore = getBestPossibleScore(tempBoard,nextPieces.clone());
             if (currentScore > bestScore)
             {            
                 bestScore = currentScore
              }
             boardCp = undoMove(tempBoard, move)
          }

        return board.score+bestScore;
    }
     function getBestMove(Board board, Queue<piece> nextPieces)
        {

         piece = piece.pop();
         possibleMoves = getPossibleMoves(board, piece)   
         bestMove=null;
         bestScore = -INFINITY
         boardCp = clone(board)     

         for (move in possibleMoves)
         {
             tempBoard = applyMove(boardCp, move)
             currentScore = getBestPossibleScore(tempBoard,nextPieces.clone());
             if (currentScore > bestScore)
             {            
                 bestScore = currentScore
                 bestMove=move;
              }
             boardCp = undoMove(tempBoard, move)
          }

        return bestMove
        }

【讨论】:

  • 哼...你的代码看起来像 2-moves 向前看...或者我错过了什么?
  • 它看起来在 nextPieces.size() 前面。它不断弹出最上面的棋子,并检查它的所有动作,然后在每次移动时调用其余棋子,以确定哪个动作将导致最高分
  • 哼...但是对于每个棋盘状态,只有最上面的棋子可用,您无法切换棋子 - 这就像国际象棋的移动变体!我理解递归的速度很慢,但我开始看到它。谢谢!
  • 我认为您的代码有错字,没有递归 - 这就是我感到困惑的原因。在顶部的第一个 for 循环中,我应该是 getBestMove(),而不是 getBestMoveScore()。我说的对吗?
  • 错字,但不是第一招,应该是getBestPossibleScore。
【解决方案3】:

我帮不了你,但我可以向你推荐这个 MinMax algorithm 这是我在 AI 大学课程中使用的。

伪代码,如果有用的话:

function integer minimax(node, depth)
  if node is a terminal node or depth <= 0:
    return the heuristic value of node
  α = -∞
  for child in node:       # evaluation is identical for both players 
    α = max(α, -minimax(child, depth-1))
  return α

此算法资产,对手尽其所能(基于评估函数)

【讨论】:

    【解决方案4】:

    对此采取伪代码方法。我的第一选择始终是带有 alpha beta pruning 的 minimax,因为它是解决与您类似的问题的常用且经过验证的方法。

    但如果你想做一些不同的事情。

    List moves = new list()
    Best board = current board    
    
    While (queue is not empty){
        grab the next item in the queue.
        Implement your algorithm.
        add the move to the move list.
        update the best board
    }
    

    不是最好但非常简单的方法,然后根据队列为您提供移动列表。您只需将棋盘状态从上一个最佳棋盘转移到算法棋盘元素中,然后将队列中的下一个棋盘状态传递到算法的片段参数中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-06
      • 1970-01-01
      • 2015-12-12
      • 1970-01-01
      • 2011-07-13
      相关资源
      最近更新 更多