游戲(賭勝負(fù))采用策略進(jìn)行。 每個(gè)球員或球隊(duì)在開始比賽前都會制定一個(gè)戰(zhàn)略,他們必須根據(jù)目前的比賽情況改變或制定新的戰(zhàn)略。
考慮電腦游戲也采用與上述相同的策略。 請注意,搜索算法是計(jì)算電腦游戲策略的算法。
怎么運(yùn)行的
搜索算法的目標(biāo)是找到最優(yōu)的一組移動(dòng),以便他們可以到達(dá)最終目的地并獲勝。 這些算法使用勝出的一組條件,每場比賽都有所不同,以找到最佳的移動(dòng)方式。
將電腦游戲形象化為樹。 我們都知道樹有節(jié)點(diǎn)。 從根開始,可以進(jìn)入最終的獲勝節(jié)點(diǎn),但是具有最佳的移動(dòng)路徑。 這是搜索算法的工作。 這種樹中的每個(gè)節(jié)點(diǎn)代表未來的狀態(tài)。 搜索算法搜索這棵樹,在游戲的每個(gè)步驟或節(jié)點(diǎn)做出決定。
使用搜索算法的主要缺點(diǎn)是它們本質(zhì)上是窮盡的,這就是為什么他們探索整個(gè)搜索空間以找到導(dǎo)致資源浪費(fèi)的解決方案。如果這些算法需要搜索整個(gè)搜索空間以找到最終解決方案,那將更加麻煩。
要消除這樣的問題,可以使用組合搜索,它使用啟發(fā)式來探索搜索空間,并通過消除可能的錯(cuò)誤動(dòng)作來減小其大小。 因此,這樣的算法可以節(jié)省資源。 這里討論了一些使用啟發(fā)式搜索空間并節(jié)省資源的算法 -
這是組合搜索使用啟發(fā)式策略加快搜索策略的策略。 Minimax策略的概念可以通過兩個(gè)玩家游戲的例子來理解,其中每個(gè)玩家都試圖預(yù)測對手的下一步行動(dòng)并嘗試最小化該功能。 而且,為了獲勝,玩家總是會根據(jù)當(dāng)前的情況嘗試最大化自己的功能。
啟發(fā)式在像Minimax這樣的策略中扮演著重要的角色。 樹的每個(gè)節(jié)點(diǎn)都會有一個(gè)與之相關(guān)的啟發(fā)式函數(shù)。 基于這種啟發(fā)式方法,它將決定向最有利于他們的節(jié)點(diǎn)邁進(jìn)。
Minimax算法的一個(gè)主要問題是它可以探索那些無關(guān)的樹的部分,導(dǎo)致資源的浪費(fèi)。 因此,必須有一個(gè)策略來決定樹的哪一部分是相關(guān)的,哪一個(gè)是無關(guān)緊要的,并且將不相關(guān)的部分留給未開發(fā)的部分。 Alpha-Beta修剪就是這樣一種策略。
Alpha-Beta修剪算法的主要目標(biāo)是避免搜索樹中沒有任何解決方案的那些部分。 Alpha-Beta修剪的主要概念是使用名為Alpha的兩個(gè)邊界(最大下界)和Beta,即最小上界。 這兩個(gè)參數(shù)是限制可能解決方案集合的值。 它將當(dāng)前節(jié)點(diǎn)的值與alpha和beta參數(shù)的值進(jìn)行比較,以便它可以移動(dòng)到具有解決方案的樹部分并丟棄其余部分。
這個(gè)算法與Minimax算法沒有區(qū)別,但它具有更優(yōu)雅的實(shí)現(xiàn)。 使用Minimax算法的主要缺點(diǎn)是需要定義兩個(gè)不同的啟發(fā)式函數(shù)。 這些啟發(fā)式之間的聯(lián)系是,對于一個(gè)玩家來說游戲的狀態(tài)越好,對另一個(gè)玩家來說就越糟糕。 在Negamax算法中,兩個(gè)啟發(fā)函數(shù)的相同工作是在單個(gè)啟發(fā)式函數(shù)的幫助下完成的。
要在AI中構(gòu)建機(jī)器人玩兩個(gè)玩家游戲,需要安裝easyAI庫。 這是一個(gè)人工智能框架,提供了構(gòu)建雙人游戲的所有功能。 可以通過以下命令下載它 -
pip install easyAI
在這場比賽中,會有一堆硬幣。 每個(gè)玩家必須從該堆中取出一些硬幣。這場比賽的目標(biāo)是避免拿下最后一枚硬幣。 我們將使用繼承自easyAI庫的TwoPlayersGame類的LastCoinStanding類。 以下代碼顯示了此游戲的Python代碼 -
如下所示導(dǎo)入所需的軟件包 -
from easyAI import TwoPlayersGame, id_solve, Human_Player, AI_Player
from easyAI.AI import TT
現(xiàn)在,繼承TwoPlayerGame類中的類來處理游戲的所有操作 -
class LastCoin_game(TwoPlayersGame):
def __init__(self, players):
定義要玩家并開始游戲。
self.players = players
self.nplayer = 1
定義游戲中的硬幣數(shù)量,這里使用15個(gè)硬幣進(jìn)行游戲。
self.num_coins = 15
定義玩家在移動(dòng)中可以獲得的最大硬幣數(shù)量。
self.max_coins = 4
現(xiàn)在有一些東西需要定義,如下面的代碼所示。 定義可能的移動(dòng)。
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
定義何時(shí)停止游戲,即何時(shí)有人獲勝。
def is_over(self):
return self.win()
定義如何計(jì)算分?jǐn)?shù)。
def score(self):
return 100 if self.win_game() else 0
定義堆中剩余的硬幣數(shù)量。
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()
下面的輸出演示這個(gè)游戲的簡單玩法 -
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
Tic-Tac-Toe非常熟悉,是最受歡迎的游戲之一。我們通過使用Python中的easyAI庫來創(chuàng)建這個(gè)游戲。 以下代碼是這款游戲的Python代碼 -
如下所示導(dǎo)入軟件包 -
from easyAI import TwoPlayersGame, AI_Player, Negamax
from easyAI.Player import Human_Player
繼承TwoPlayerGame中的類來處理游戲的所有操作 -
class TicTacToe_game(TwoPlayersGame):
def __init__(self, players):
現(xiàn)在,定義玩家并開始游戲 -
self.players = players
self.nplayer = 1
定義板的類型 -
self.board = [0] * 9
定義可能的舉措(動(dòng)作)
def possible_moves(self):
return [x + 1 for x, y in enumerate(self.board) if y == 0]
定義一個(gè)玩家的舉措(動(dòng)作) -
def make_move(self, move):
self.board[int(move) - 1] = self.nplayer
定義一個(gè)玩家何時(shí)進(jìn)行移動(dòng) -
def umake_move(self, move):
self.board[int(move) - 1] = 0
定義輸條件是對手在一條線上有三個(gè) -
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])
定義游戲結(jié)束的條件 -
def is_over(self):
return (self.possible_moves() == []) or self.condition_for_lose()
顯示玩家在游戲中的當(dāng)前位置 -
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)]))
計(jì)算分?jǐn)?shù)代碼 -
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()
可以看到下面的輸出和這個(gè)游戲的簡單玩法 -
. . .
. . .
. . .
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 .