Python AI – 遊戲



遊戲都是以策略進行的。每個玩家或團隊在開始遊戲之前都會制定策略,並且他們必須根據遊戲中的當前情況改變或制定新的策略。

搜尋演算法

您也需要像上面一樣,將電腦遊戲視為同樣的策略。請注意,搜尋演算法是找出電腦遊戲中策略的演算法。

工作原理

搜尋演算法的目標是找到最佳的一系列移動,以便它們能夠到達最終目的地並獲勝。這些演算法使用每個遊戲都不一樣的獲勝條件集來找到最佳移動。

將電腦遊戲視覺化為樹。我們知道樹有節點。從根開始,我們可以到達最終的獲勝節點,但需要使用最佳的移動。這就是搜尋演算法的工作。此類樹中的每個節點都代表一個未來狀態。搜尋演算法搜尋這棵樹,以便在遊戲的每個步驟或節點做出決策。

組合搜尋

使用搜索演算法的主要缺點是它們本質上是窮舉的,這就是為什麼它們會探索整個搜尋空間以找到解決方案,從而導致資源浪費。如果這些演算法需要搜尋整個搜尋空間以找到最終解決方案,則會更加麻煩。

為了消除此類問題,我們可以使用組合搜尋,它使用啟發式方法來探索搜尋空間,並透過消除可能的錯誤移動來減小搜尋空間的大小。因此,此類演算法可以節省資源。這裡討論了一些使用啟發式方法搜尋空間並節省資源的演算法:

極大極小演算法

這是組合搜尋使用的策略,它使用啟發式方法來加速搜尋策略。可以透過雙人遊戲的例子來理解極大極小策略的概念,在雙人遊戲中,每個玩家都試圖預測對手的下一步行動並試圖最小化該函式。此外,為了獲勝,玩家總是試圖根據當前情況最大化自己的函式。

啟發式方法在這種策略(例如極大極小演算法)中起著重要作用。樹的每個節點都將與一個啟發式函式相關聯。根據該啟發式方法,它將做出決策,朝著最有利於它們的節點移動。

Alpha-Beta 剪枝

極大極小演算法的一個主要問題是它可以探索與之無關的樹的部分,從而導致資源浪費。因此,必須有一種策略來確定樹的哪一部分是相關的,哪一部分是不相關的,並使不相關的部分未被探索。Alpha-Beta 剪枝就是這樣一種策略。

Alpha-Beta 剪枝演算法的主要目標是避免搜尋那些沒有任何解決方案的樹的部分。Alpha-Beta 剪枝的主要概念是使用兩個邊界,名為Alpha(最大下界)和Beta(最小上界)。這兩個引數是限制可能解決方案集的值。它將當前節點的值與 alpha 和 beta 引數的值進行比較,以便它可以移動到具有解決方案的樹的部分並丟棄其餘部分。

Negamax 演算法

此演算法與極大極小演算法沒有區別,但它具有更優雅的實現。使用極大極小演算法的主要缺點是我們需要定義兩個不同的啟發式函式。這些啟發式方法之間的聯絡是,遊戲的一個狀態對一個玩家越有利,對另一個玩家就越不利。在 Negamax 演算法中,兩個啟發式函式的工作由單個啟發式函式完成。

構建機器人來玩遊戲

為了在 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

一個玩井字棋的機器人

井字棋非常熟悉,也是最受歡迎的遊戲之一。讓我們使用 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 .
廣告