教 程 目 录



AI与Python - 游戏


游戏采用策略.每个玩家或团队在开始游戏之前都会制定策略,他们必须根据游戏中的当前情况更改或构建新策略.

搜索算法

您必须使用与上述相同的策略来考虑电脑游戏.请注意,搜索算法是计算出游戏策略的算法.

工作原理

搜索算法的目标是找到最佳动作组合,以便他们可以到达最终目的地并获胜.这些算法使用不同的每个游戏条件来获得最佳动作.

将计算机游戏可视化为树.我们知道树有节点.从根开始,我们可以进入最终的获胜节点,但是有最佳的移动.这是搜索算法的工作.这种树中的每个节点都代表一个未来状态.搜索算法搜索此树以在游戏的每个步骤或节点进行决策.

组合搜索

使用搜索算法的主要缺点是因为它们本质上是详尽无遗的,这就是为什么它们探索整个搜索空间以找到导致资源浪费的解决方案的原因.如果这些算法需要搜索整个搜索空间以找到最终解决方案,那将会更麻烦.

为了消除这类问题,我们可以使用组合搜索,它使用启发式探索搜索空间并通过消除可能的错误移动来减小其大小.因此,这种算法可以节省资源.这里讨论了一些使用启发式搜索空间并节省资源的算法 :

Minimax算法

这是使用的策略使用启发式加速搜索策略的组合搜索. Minimax策略的概念可以用两个玩家游戏的例子来理解,其中每个玩家试图预测对手的下一步动作并试图最小化该功能.此外,为了获胜,玩家总是试图根据当前情况最大化自己的功能.

启发式在像Minimax这样的策略中起着重要作用.树的每个节点都有一个与之关联的启发式函数.基于该启发式,它将决定向最有利于他们的节点迈进.

Alpha-Beta修剪

Minimax算法的一个主要问题是它可以探索不相关的树的那些部分,从而导致资源的浪费.因此,必须有一个策略来决定树的哪个部分是相关的,哪个部分是无关紧要的,并且将不相关的部分保留为未开发的. Alpha-Beta修剪就是这样一种策略.

Alpha-Beta修剪算法的主要目标是避免搜索那些没有任何解决方案的树部分. Alpha-Beta修剪的主要概念是使用两个名为 Alpha 的边界,最大下限和 Beta ,最小上限.这两个参数是限制可能解决方案集的值.它将当前节点的值与alpha和beta参数的值进行比较,以便它可以移动到具有解决方案的树的一部分并丢弃其余部分.

Negamax算法

此算法与Minimax算法没有区别,但它具有更优雅的实现.使用Minimax算法的主要缺点是我们需要定义两个不同的启发式函数.这些启发式之间的联系是,对于一个玩家来说游戏的状态越好,对另一个玩家来说就越糟糕.在Negamax算法中,两个启发式函数的相同工作是在单个启发式函数的帮助下完成的.

构建机器人来玩游戏

For建立机器人在AI中玩两个玩家游戏,我们需要安装 easyAI 库.它是一个人工智能框架,提供构建双人游戏的所有功能.您可以在以下命令的帮助下下载 :

pip install easyAI

玩最后一枚硬币的机器人

在这个游戏中,会有一堆硬币.每个玩家必须从那堆中取出一些硬币.游戏的目标是避免将最后一枚硬币放入堆中.我们将使用继承自 easyAI 库的 TwoPlayersGame 类的 LastCoinStanding 类.以下代码显示了此游戏的Python代码 :

导入所需的包,如下所示 :

from easyAI import TwoPlayersGame, id_solve, Human_Player, AI_Player
from easyAI.AI import TT

现在,继承中的类TwoPlayerGame 类来处理游戏的所有操作 :

class LastCoin_game(TwoPlayersGame):
   def __init__(self, players):

现在,定义将要开始游戏的玩家和玩家.

self.players = players
self.nplayer = 1

现在,定义中的硬币数量游戏,这里我们使用15个硬币进行游戏.

self.num_coins = 15

定义玩家在移动中可以获得的最大硬币数.

self.max_coins = 4

现在有一些事情需要定义,如下面的代码所示.定义可能的移动.

def possible_moves(self):
   return [str(a) for a in range(1, self.max_coins + 1)]

定义硬币的移除

def make_move(self, move):
   self.num_coins -= int(move)

定义谁拿了最后一枚硬币.

def win_game(self):
   return self.num_coins <= 0

定义何时停止游戏,即有人获胜.

def is_over(self):
   return self.win()

定义如何计算分数.

def score(self):
   return 100 if self.win_game() else 0

定义剩余的硬币数量.

def show(self):
   print(self.num_coins, 'coins left in the pile')
if __name__ == "__main__":
   tt = TT()
   LastCoin_game.ttentry = lambda self: self.num_coins

使用以下代码块解决游戏 :

r, d, m = id_solve(LastCoin_game,
   range(2, 20), win_score=100, tt=tt)
print(r, d, m)

决定谁将开始游戏

game = LastCoin_game([AI_Player(tt), Human_Player()])
game.play()

你可以找到以下输出和这个游戏的简单游戏 :

d:2, a:0, m:1
d:3, a:0, m:1
d:4, a:0, m:1
d:5, a:0, m:1
d:6, a:100, m:4
1 6 4
15 coins left in the pile
Move #1: player 1 plays 4 :
11 coins left in the pile
Player 2 what do you play ? 2
Move #2: player 2 plays 2 :
9 coins left in the pile
Move #3: player 1 plays 3 :
6 coins left in the pile
Player 2 what do you play ? 1
Move #4: player 2 plays 1 :
5 coins left in the pile
Move #5: player 1 plays 4 :
1 coins left in the pile
Player 2 what do you play ? 1
Move #6: player 2 plays 1 :
0 coins left in the pile

玩Bic Tac Toe的机器人

Tic-Tac-Toe是非常熟悉的,也是最受欢迎的游戏之一.让我们使用Python中的 easyAI 库创建这个游戏.下面的代码是这个游戏的Python代码 :

导出包如图所示 :

from easyAI import TwoPlayersGame, AI_Player, Negamax
from easyAI.Player import Human_Player

TwoPlayerGame继承类类来处理游戏的所有操作 :

class TicTacToe_game(TwoPlayersGame):
   def __init__(self, players):

现在,定义将要开始游戏的玩家和玩家减去;

self.players = players
self.nplayer = 1

定义董事会的类型 :

self.board = [0] * 9

现在有一些事情需要定义如下 :

定义可能的移动

def possible_moves(self):
   return [x + 1 for x, y in enumerate(self.board) if y == 0]

定义玩家的移动:

def make_move(self, move):
   self.board[int(move) - 1] = self.nplayer

为了提升AI,定义玩家何时进行移动:

def umake_move(self, move):
   self.board[int(move) - 1] = 0

定义对手在一条线上有三个的失败条件

def condition_for_lose(self):
   possible_combinations = [[1,2,3], [4,5,6], [7,8,9],
      [1,4,7], [2,5,8], [3,6,9], [1,5,9], [3,5,7]]
   return any([all([(self.board[z-1] == self.nopponent)
      for z in combination]) for combination in possible_combinations])

定义游戏结束的检查

def is_over(self):
   return (self.possible_moves() == []) or self.condition_for_lose()

显示游戏中玩家的当前位置

def show(self):
   print('\n'+'\n'.join([' '.join([['.', 'O', 'X'][self.board[3*j + i]]
      for i in range(3)]) for j in range(3)]))

计算得分.

def scoring(self):
   return -100 if self.condition_for_lose() else 0

定义定义算法的主要方法然后开始游戏 :

if __name__ == "__main__":
   algo = Negamax(7)
   TicTacToe_game([Human_Player(), AI_Player(algo)]).play()

你可以看到以下输出和这个游戏的简单游戏 :

. . .
. . .
. . .
Player 1 what do you play ? 1
Move #1: player 1 plays 1 :
O . .
. . .
. . .
Move #2: player 2 plays 5 :
O . .
. X .
121
. . .
Player 1 what do you play ? 3
Move #3: player 1 plays 3 :
O . O
. X .
. . .
Move #4: player 2 plays 2 :
O X O
. X .
. . .
Player 1 what do you play ? 4
Move #5: player 1 plays 4 :
O X O
O X .
. . .
Move #6: player 2 plays 8 :
O X O
O X .
. X .