我正在研究一个简单的Tic Tac Toe代码游戏。我已经完成了大部分代码,但我希望AI永远不会丢失。
我已经阅读过minimax算法,但我不明白。如何使用此算法使计算机能够赢或赢但永不丢失?
答案 0 :(得分:8)
解决这类问题的方法是探索可能的未来。通常(对于国际象棋或选秀AI)你会考虑未来一定数量的前进,但因为tic tac toe游戏太短,你可以探索到游戏结束。
所以你创建了一个分支结构:
然后,从最分支的一端(最远的时间)开始,轮到它的玩家(AI或用户)在每个分支点选择哪个未来最好(赢,输或抽)。然后它交给树上方的玩家(离现在更近);每次选择最好的未来为想象转向的玩家,直到最后你在第一个分支点,AI可以看到期货,它会失去,吸引和获胜。它选择一个胜利的未来(或者如果不可用的话)。
请注意,从概念上讲,这就是正在发生的事情,但创建整个树并不是必需的,然后像这样判断它。你可以轻松地工作,虽然树到达最远的时间点,然后选择。
这里,这种方法与递归函数很好地配合。该函数的每个级别都会轮询其所有分支;将可能的未来传递给他们并返回-1,0,+ 1;在每个点选择当前玩家的最高分 。最高级别选择移动而不是实际知道每个未来如何发展,以及他们的表现如何。
我假设在这个伪代码中,+1是AI获胜,0是绘图,-1是用户丢失
determineNextMove(currentStateOfBoard)
currentBestMove= null
currentBestScore= - veryLargeNumber
for each legalMove
score=getFutureScoreOfMove(stateOfBoardAfterLegalMove , AI’sMove)
if score>currentBestScore
currentBestMove=legalMove
currentBestScore=score
end
end
make currentBestMove
end
getFutureScoreOfMove(stateOfBoard, playersTurn)
if no LegalMoves
return 1 if AI wins, 0 if draw, -1 if user wins
end
if playersTurn=AI’sTurn
currentBestScore= - veryLargeNumber //this is the worst case for AI
else
currentBestScore= + veryLargeNumber //this is the worst case for Player
end
for each legalMove
score=getFutureScoreOfMove(stateOfBoardAfterLegalMove , INVERT playersTurn)
if playersTurn ==AI’sTurn AND score>currentBestScore //AI wants positive score
currentBestScore=score
end
if playersTurn ==Users’sTurn AND score<currentBestScore //user wants negative score
currentBestScore=score
end
end
return currentBestScore
end
这个伪代码并不关心起始板是什么(你用当前的主板每次AI移动都称这个功能)并且没有返回未来将采取的路径(我们不能这样做)知道用户是否会以最佳状态播放,因此这些信息毫无用处),但它总会选择朝着人工智能的最佳未来前进的方式。
在这种情况下,你探索到游戏的结尾,很明显哪个最好的未来是(赢,输或抽),但如果你只是去(例如)五个进入未来,你必须找到一些方法来确定;在国际象棋或选秀中,得分是最简单的方法,其中棋子位置是一种有用的增强。
答案 1 :(得分:4)
大约5年前我一直在做这样的事情。我做了研究。在tic tac toe
中,它不需要很长时间,你只需要准备前两三步的模式。
您需要检查游戏方式:
有9个不同的起始位置:
但实际上只有3个是不同的(其他的是旋转的)。
所以在那之后你会看到在一些特定动作之后应该做什么,我认为在这种情况下你不需要任何算法,因为tic tac toe
结束是通过第一次动作来确定的。因此,在这种情况下,您需要一些if-else
或switch
语句和random
生成器。
答案 2 :(得分:1)
制作一个辅助程序来预测用户可以获胜的案例。然后你可以说你的ai做了用户必须做的事情才能获胜。
答案 3 :(得分:1)
tic tac toe
属于一组游戏,如果你知道怎么玩就不会丢失,所以对于这样的游戏你不需要使用树和修改的排序算法。要编写这样的算法,您只需要几个函数:
CanIWin()
检查计算机是否连续2个并且可能获胜。ShouldIBlock()
检查玩家是否连续2并且需要阻止它。必须按此顺序调用这两个函数,如果它返回true
,您需要赢或不让玩家获胜。
之后你需要为移动做其他计算。
一种独有的情况是计算机启动游戏。您需要选择属于最大不同方向的单元格(其中有8个 - 3个水平,垂直和2个对角线)。在这样的算法中,计算机将始终选择中心,因为它有4个方向,你应该添加小的可能性来选择第二个最佳选项,使游戏更具吸引力。
因此,当您遇到某些选定部分的电路板和计算机必须移动的情况时,您需要对每个空闲单元进行评级。 (如果返回第一个或第二个函数true
,您必须在到达此地点之前采取行动!!! )。因此,要对单元格进行评分,您需要计算每个单元格上剩余的打开方向,还需要阻止至少一个对手方向。
之后,您将有几个可能的单元格来标记。因此,您需要检查必要的移动顺序,因为您将有一些选项,可能是其中一个导致您失去。所以在那之后你将设置并且你可以随机选择移动,或选择得分最高的那个。
我必须说类似的事情,就像在帖子开头所说的那样。更大的游戏没有完美的策略,让我们说国际象棋很多都是基于模式,而且也是前瞻性思维策略(对于这样的事情是使用patricia trie)。总而言之,你不需要困难的算法,只需要几个函数来计算你获得的收益以及对手的移动损失。