我們來創建一個機器人,以便與 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.attack
和 else
之間:
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。