はじめに
前回の続きです。前編では2手目まで条件式で指示を与えていました。
3手目からはミニマックス法もどきで、コンピュータ側の全通りの手を調べて勝つ手があればそれを打ちます。次のプレイヤーのターンも全通り調べて、負ける手があればそこには打たないようにします。(深さが2層のミニマックス法です)
コンピュータを完璧にしてプレイヤーがまったく勝てないと面白くないと思うので(本当は邪魔くさい)ある条件の負ける手は打ってしまうように考えます。
3手目以降
- 「元の位置(self.koma_no)」から大きさ(self.koma)を調べる
- 「元の位置(self.koma_no)」候補は最大6つ
- 「移動先(self.masu_no)」候補は最大9つ
- 合計54パターンを総調べ
- 勝てる手があればその位置に打つ
- 次の相手の手まで読む
- 負ける手があればその手は打たない
- 勝負が決まらなければ・・・
- 負ける手しかなければ・・・
この流れで考えていきます。
先手・後手 共通
「元の位置(self.koma_no)」から大きさ(self.koma)を調べる
# 「元の位置(self.koma_no)」から大きさ(self.koma)を調べる for i in range(9): if str(self.board[i])[0] == "2": if document[str(i)].classList.contains("red_l"): self.koma_no = str(i) self.koma = "red_l" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return elif document[str(i)].classList.contains("red_m"): self.koma_no = str(i) self.koma = "red_m" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return elif document[str(i)].classList.contains("red_s"): self.koma_no = str(i) self.koma = "red_s" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return if document["box6"].classList.contains("red_l"): self.koma_no = "box6" self.koma = "red_l" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return if document["box5"].classList.contains("red_m"): self.koma_no = "box5" self.koma = "red_m" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return if document["box2"].classList.contains("red_m"): self.koma_no = "box2" self.koma = "red_m" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return if document["box4"].classList.contains("red_s"): self.koma_no = "box4" self.koma = "red_s" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return if document["box1"].classList.contains("red_s"): self.koma_no = "box1" self.koma = "red_s" # 仮で打ってみる self.max_value() if self.masu_no != 9 and self.masu_no >= 0: return
「元の位置(self.koma_no)」候補は最大6つ
「移動先(self.masu_no)」候補は最大9つ
合計54パターンを総調べ
for j in range(9): # 盤面をコピー self.board_2 = self.board[:] # 盤面を記録 if self.koma == "red_s": if self.board_2[j] < 1: self.board_2[j] += 2 if self.koma_no[0:3] != "box": self.board_2[int(self.koma_no)] -= 2 elif self.koma == "red_m": if self.board_2[j] < 10: self.board_2[j] += 20 if self.koma_no[0:3] != "box": self.board_2[int(self.koma_no)] -= 20 elif self.koma == "red_l": if self.board_2[j] < 100: self.board_2[j] += 200 if self.koma_no[0:3] != "box": self.board_2[int(self.koma_no)] -= 200
勝てる手があればその位置に打つ
# 「元の位置」の駒を消す document[self.koma_no].classList.remove(self.koma) # 駒を打つ document[str(self.masu_no)].classList.add(self.koma) # 盤面を記録 if self.koma == "red_s": self.board[self.masu_no] += 2 if self.koma_no[0:3] != "box": self.board[int(self.koma_no)] -= 2 elif self.koma == "red_m": self.board[self.masu_no] += 20 if self.koma_no[0:3] != "box": self.board[int(self.koma_no)] -= 20 elif self.koma == "red_l": self.board[self.masu_no] += 200 if self.koma_no[0:3] != "box": self.board[int(self.koma_no)] -= 200
次の相手の手まで読む
# 「元の位置(self.koma_no)」から大きさ(self.koma)を調べる if document["box9"].classList.contains("blue_l"): self.koma_no2 = "box9" self.koma2 = "blue_l" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -100 return if document["box12"].classList.contains("blue_l"): self.koma_no2 = "box12" self.koma2 = "blue_l" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -100 return if document["box8"].classList.contains("blue_m"): self.koma_no2 = "box8" self.koma2 = "blue_m" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -10 return if document["box11"].classList.contains("blue_m"): self.koma_no2 = "box11" self.koma2 = "blue_m" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -10 return if document["box7"].classList.contains("blue_s"): self.koma_no2 = "box7" self.koma2 = "blue_s" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -1 return if document["box10"].classList.contains("blue_s"): self.koma_no2 = "box10" self.koma2 = "blue_s" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -1 return ''' # ここをコメント解除するとコンピュータが強くなりすぎる for i in range(9): if str(self.board[i])[0] == "1": if document[str(i)].classList.contains("blue_l"): self.koma_no2 = str(i) self.koma2 = "blue_l" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -100 return elif document[str(i)].classList.contains("blue_m"): self.koma_no2 = str(i) self.koma2 = "blue_m" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -10 return elif document[str(i)].classList.contains("blue_s"): self.koma_no2 = str(i) self.koma2 = "blue_s" # 仮で打ってみる self.min_value2() if self.masu_no != 9: self.masu_no = -1 return '''
負ける手があればその手は打たない
# 赤が打てるか調べる if (self.koma == "red_l" and self.board[j] < 100) \ or (self.koma == "red_m" and self.board[j] < 10) \ or (self.koma == "red_s" and self.board[j] < 1): # 悪い手は打たない if self.koma_no == "4" and self.koma == "red_l" and j == 7: pass else: self.koma_no1 = self.koma_no self.koma1 = self.koma self.masu_no1 = j self.masu_no = 9 # 盤面をコピー self.board_1 = self.board_2[:] # 相手のターンへ self.min_value() # 次で負けなければそこに打つ if self.masu_no == 9: self.koma_no0 = self.koma_no1 self.koma0 = self.koma1 self.masu_no0 = self.masu_no1 elif self.masu_no1 < 9: # 負ける手しかない場合用 self.koma_no3 = self.koma_no1 self.koma3 = self.koma1 self.masu_no3 = self.masu_no1 self.board_3 = self.board_2[:]
勝負が決まらなければ・・・
負ける手しかなければ・・・
if self.masu_no == 9: # 勝負が決まらない場合 self.koma_no = self.koma_no0 self.koma = self.koma0 self.masu_no = self.masu_no0 document[self.koma_no].classList.remove(self.koma) timer.set_timeout(self.AI_set, 100) elif self.masu_no >= 0: # 勝てる手がある場合 document[self.koma_no].classList.remove(self.koma) timer.set_timeout(self.AI_set, 100) elif self.masu_no < 0 and self.masu_no0 == 9: # 負ける手しかない場合 self.koma_no = self.koma_no3 self.koma = self.koma3 self.masu_no = self.masu_no3 document[self.koma_no].classList.remove(self.koma) timer.set_timeout(self.AI_set, 100) elif self.masu_no < 0 and self.masu_no0 >= 0: # 負ける手がある場合 self.koma_no = self.koma_no0 self.koma = self.koma0 self.masu_no = self.masu_no0 document[self.koma_no].classList.remove(self.koma) timer.set_timeout(self.AI_set, 100) else: alert("これが出たらバグ!else:") alert(self.koma_no + " , " + self.koma + " , " + str(self.masu_no)) alert(self.koma_no0 + " , " + self.koma0 + " , " + str(self.masu_no0))
まとめ
それなりに強いコンピュータが出来上がりました。2手目までは指示を与えることでランダム性がでて楽しめると思います。コンピュータの弱点としては「2手目まで『小』の駒にはかぶせてこない」「勝敗が見つからなかった場合の手があまい」「プレイヤーが盤面上の駒を移動する手は読まない」などがあります。
いろいろ調べているとAIを最初にゲームに使ったのはナムコの「パックマン」らしいです。また「ゼビウス」ではプレイヤーの上手さによって難易度が変わったらしいです。(初めて知りました)
プレイヤーの実力により難易度を変化させるのはすごく良いアイデアです。プレイヤーの連勝した数で徐々にコンピュータを強くする、連敗したら徐々にコンピュータを弱くするようにすれば、誰でも楽しめる三目並べが出来そうです。
↓よかったらポチッとしていってください。