讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 26.2 創建一個 Python Battle 機器人 >

26.2 創建一個 Python Battle 機器人

我們來創建一個機器人,以便與 CircleAI 和 RandomAI 戰鬥。第一步是制定一個策略。因為這是我們創建的第一個 Python Battle 機器人,所以我們最好從一個簡單的策略開始。

1. 如果面對著一個敵人,那麼我應該攻擊它。

2. 如果面對著牆,則我應該轉彎。

3. 否則,我繼續向前走。

儘管這不是最高級的策略,但它可能剛好可以打敗 CircleAI。如果它打不過,我們還可以再回來改進它。

第二步是開始編碼機器人。創建一個新 Python 文件(我把它叫作 better_than_circleai.py),然後輸入以下代碼:

class AI:    def __init__(self):pass    def turn(self):pass  

這是所有機器人都必須具備的基礎代碼。在遊戲開始時創建機器人,此時 __init__ 函數會被調用。turn 函數會在每一回合被調用,並決定機器人做什麼。這個類必須叫作 AI,否則 Python Battle 遊戲不知道你的 AI 代碼在哪裡。

編寫機器人的下一步是添加能讓機器人執行我們制定的策略的代碼。你將使用以下函數來控制機器人的移動:

  • self.robot.lookInFront

  • self.robot.turnRight

  • self.robot.turnLeft

  • self.robot.goForth

  • self.robot.attack

這些函數需要採用 self.robot.xx 的形式調用,因為 self 指向 AI 對像本身,而不是 AI 控制的機器人。AI 對象是不會移動或者攻擊的,它只負責告知機器人需要做什麼,具體的移動和攻擊是由機器人對像來執行的。

我們來編寫 turn 方法。移除代碼中的 pass,添加下面的代碼:

self.robot.goForth  

如果你現在測試一下這個機器人,會看到每一回合它都會嘗試向前移動。這會導致它很快撞到遊戲邊界處的「牆」。如果敵人擋住了它的路,則它只會停止移動而已。你可以使用 self.robot.lookInFront 來修復這個問題。如果在正前方有一個可以攻擊的敵人,則這個函數返回 "bot"。修改一下 turn 函數,像這樣:

if self.robot.lookInFront == "bot":    self.robot.attackelse:    self.robot.goForth  

現在,如果在你的機器人前方有敵人擋路,則機器人會攻擊它。但是如果機器人撞「牆」了,則它會停下來。如果前方是「牆」,則 self.robot.lookInFront 會返回 "wall"。將下面的代碼加到 turn 函數中,放在 self.robot.attackelse 之間:

elif self.robot.lookInFront == "wall":    self.robot.turnRight  

現在,如果你運行代碼,則機器人會開始轉圈!當它撞到「牆」的時候會向右轉,當它撞到下一堵「牆」時會再次向右轉,一直這樣運行下去。你更希望機器人在撞「牆」的時候能轉身折返回去,而這需要兩次右轉才能完成。當機器人撞「牆」的時候,它需要右轉一次,然後在一下回合中,再右轉一次。也就是說,你需要機器人記住它現在是在做 U 型轉身。你可以給 AI 設置一個新屬性(變量)來記住它正在做什麼。我們在 __init__ 函數中添加一行代碼:

self.currentlyDoing = "forward"  

這將告訴機器人,當遊戲開始時,它需要向前走。當機器人在做 U 型轉身時,你可以將這個屬性的值改為 "turnRight" 以便告知機器人它需要右轉。修改之後的 turn 函數最終看起來像這樣:

代碼清單 26-1 完成的機器人 AI

class AI:    def __init__(self):self.currentlyDoing = "forward"    def turn(self):if self.robot.lookInFront == "bot":    self.robot.attackelif self.robot.lookInFront == "wall":    self.robot.turnRight    self.currentlyDoing = "turnRight"elif self.currentlyDoing == "turnRight":    self.robot.turnRight    self.currentlyDoing = "forward"else:    self.robot.goForth  

如果你運行這段代碼,可能會發現這個 AI 有一定的缺陷。我們來修改一下以便我們的機器人可以打敗 CircleAI。