Python プログラムで動かすフェアリーチェスアプリ開発、連載第 19 回です。
はキャスリングの条件判定のコードを編集しました。今回は曖昧な場合にキャスリングするかどうかの確認をするようにして、キャスリング時の駒の再配置のコードの編集もしていきます。
キャスリングするかどうか確認
キングがルーク方向に1歩だけ動いたとき、
それがキャスリングを意図してのものか、はたまた単に動いただけなのかが曖昧です。
これをはっきりさせるために、「その動きはキャスリングを意図していますか?」とユーザに尋ねるダイアログを表示させます。
まず、確認が必要な場合とそうでない場合があるので、確認が必要かどうかを示す変数、
そして確認の結果キャスリングすることを選択したかを示す変数を設定します。
main.py1class Game:2def __init__(self):3...4# キャスリング5# キャスリングのポテンシャルが残っているか6self.can_castling = {'W': [True, True], 'B': [True, True]}7# キャスリングするかどうかをプレイヤーに確認するか8self.confirm_castling = False9# キャスリングできる状態にあるか10self.do_castling = False11...
確認が必要な場合とは曖昧な場合、つまりキャスリング完了位置にキングがただ1歩動いた場合ですので、
このときの条件を記述していきます。
main.py1class Game:2...3def castle_or_not(self, piece, endpos):4'''5キャスリングするかしないかを確認するか67Parameters8----------9piece : obj10駒.11endpos : tuple > (int, int)12終了位置.絶対座標.1314Notes15-----16if文の条件式について.1718キングの移動終了位置が,キャスリング終了位置としてありうる4つの位置のうちのいずれかにあてはまる19and (クイーンサイドキャスリングの条件にあてはまる20or キングサイドキャスリングの条件にあてはまる)21and キングの初期位置とキャスリング終了位置のx座標の差 == 122and 移動先に駒がない(=キングが敵駒を取ったのではない)23'''24if (endpos in [(2, 0), (self.kind.size - 2, 0), (2, self.kind.size - 1), (self.kind.size - 2, self.kind.size - 1)]25and (self.castling_requirements(piece, endpos, 0, self.gameboard)26or self.castling_requirements(piece, endpos, 1, self.gameboard))27and abs(self.kind.placers[1].index(King) - endpos[0]) == 128and endpos not in self.gameboard):29self.confirm_castling = True
次に、この判定をマウスクリック時に行わせ、
main.py1class Game:2...3def mouse(self, button, state, x, y):4...5# 駒選択6elif (self.parse_mouse() in self.gameboard7and not self.prom and not self.confirm_castling):8...9# キャスリングするかしないかの確認10if self.kind.castling:11if self.startpos in self.gameboard:12self.castle_or_not(13self.gameboard[self.startpos], self.endpos)14...
キャスリングを確認するときには、吹き出しとボタンで確認ダイアログを作成して表示します。
utils.py1def draw_castling_confirmation(endpos):2'''キャスリング確認ダイアログを表示する'''3draw_balloon(*endpos)4glColor(1.0, 1.0, 1.0)5draw_str(2.0, 4.0, 'Castling?')6draw_button(1.5, 3.0, 3.0, 3.5, 'Yes',7(1.0, 1.0, 1.0), (0.0, 0.0, 0.0))8draw_button(4.0, 5.5, 3.0, 3.5, 'No',9(1.0, 1.0, 1.0), (0.0, 0.0, 0.0))
main.py1class Game:2...3def draw(self):4...5if self.time == 1 and not self.confirm_castling:6self.main()7...8# キャスリングするかどうかの確認9if self.confirm_castling:10draw_castling_confirmation(self.endpos)11...
表示されたボタンをクリックすることで、キャスリングの意図があるかどうかが確認できます。
main.py1class Game:2...3def mouse(self, button, state, x, y):4...5# キャスリングするかしないかの確認6if self.kind.castling:7if self.startpos in self.gameboard:8self.castle_or_not(9self.gameboard[self.startpos], self.endpos)10if self.confirm_castling:11if on_square(*self.mousepos, 1.5, 3.0, 3.0, 4.0):12self.do_castling = True13self.confirm_castling = False14self.time = 015self.moving = True16glutIdleFunc(self.idle_move)17if on_square(*self.mousepos, 4.0, 5.5, 3.0, 4.0):18self.do_castling = False19self.confirm_castling = False20self.time = 021self.moving = True22glutIdleFunc(self.idle_move)23...
これで確認ができるようになりました。
駒の再配置
キャスリングした後には、ルークが特定の位置に移動します。
コードでは、もとの位置にあった駒(=ルーク)を削除して特定の位置に再配置しています。
main.py1def renew_gameboard(self, startpos, endpos, gameboard):2'''3盤面を更新する45Parameters6----------7startpos, endpos : tuple > (int, int)8開始位置,終了位置.絶対座標.9gameboard : dict > {(int, int): obj, ...}10盤面.11'''12color = gameboard[startpos].color13gameboard[endpos] = gameboard[startpos]14del gameboard[startpos]15...16# キャスリング17if (gameboard[endpos].abbr == 'K'18and abs(startpos[0] - endpos[0]) == 2):19# クイーンサイド20# 白21if endpos == (2, 0):22del gameboard[(0, 0)]23gameboard[(3, 0)] = Rook('W')24# 黒25if endpos == (2, 7):26del gameboard[(0, 7)]27gameboard[(3, 7)] = Rook('B')28# キングサイド29# 白30if endpos == (6, 0):31del gameboard[(7, 0)]32gameboard[(5, 0)] = Rook('W')33# 黒34if endpos == (6, 7):35del gameboard[(7, 7)]36gameboard[(5, 7)] = Rook('B')
まず駒の移動先に移動前の駒を移してから、もとの位置を削除しています(キングの動き)。
キャスリングが起こるのはキングが2歩動いたときのみであることを利用して条件文を立て、
位置によってキャスリングが起こる箇所を判定し、ルークを消して別の位置に新たなルークを置いています(ルークの動き)。
キングの動きに関しては、キングが1歩も動かないこともありえるので、startpos != endpos
のときのみdel gameboard[startpos]
を実行するようにします。
そうしないとキングが消えてしまうからです。
ルークの動きのほうは、キャスリング発生の条件を主にdo_castling
によって判定し、
ルークの初期位置にある駒がルークであれば、その駒を消して新たなルークを置いています。
これをもとに拡張して書き換えると、以下のようになります。
main.py1def renew_gameboard(self, startpos, endpos, gameboard):2'''3盤面を更新する45Parameters6----------7startpos, endpos : tuple > (int, int)8開始位置,終了位置.絶対座標.9gameboard : dict > {(int, int): obj, ...}10盤面.11'''12color = gameboard[startpos].color13gameboard[endpos] = gameboard[startpos]14del gameboard[startpos]15if startpos != endpos:16del gameboard[startpos]17...18# キャスリング19# キャスリングできるゲームである20# キャスリング確認中でない21# キャスリングできる22# 終了位置指定がある23if (self.kind.castling24and not self.confirm_castling25and self.do_castling26and None not in endpos):27rook_init_pos = [pos for pos, piece in enumerate(self.kind.placers[1])28if piece == Rook]29size = self.kind.size30piece = gameboard[endpos]31# クイーンサイド32rook_pos = rook_init_pos[0]33# 白34if (endpos == (2, 0)35and piece.color == 'W'36and (rook_pos, 0) in gameboard):37if gameboard[(rook_pos, 0)].abbr == 'R':38del gameboard[(rook_pos, 0)]39gameboard[(3, 0)] = Rook('W')40# 黒41if (endpos == (2, size - 1)42and piece.color == 'B'43and (rook_pos, size - 1) in gameboard):44if gameboard[(rook_pos, size - 1)].abbr == 'R':45del gameboard[(rook_pos, size - 1)]46gameboard[(3, size - 1)] = Rook('B')47# キングサイド48rook_pos = rook_init_pos[1]49# 白50if (endpos == (size - 2, 0)51and piece.color == 'W'52and (rook_pos, 0) in gameboard):53if gameboard[(rook_pos, 0)].abbr == 'R':54del gameboard[(rook_pos, 0)]55gameboard[(size - 3, 0)] = Rook('W')56# 黒57if (endpos == (size - 2, size - 1)58and piece.color == 'B'59and (rook_pos, size - 1) in gameboard):60if gameboard[(rook_pos, size - 1)].abbr == 'R':61del gameboard[(rook_pos, size - 1)]62gameboard[(size - 3, size - 1)] = Rook('B')
これでキャスリングの曖昧性の排除、そして駒の再配置ができるようになりました。
ここ数回分の変更は GitHub で見ることができます。
フェアリーチェスが作れるようになって、
ゲームによって出現する駒が変わるので、
はプロモーションの拡張について書きたいと思います。お読みいただきありがとうございました~
ではまた