Python プログラムで動かすフェアリーチェスアプリ開発、連載第11回です。
はチェスの特殊ルールのひとつ、アンパッサンを実装しました。今回はポーンが昇格して強くなるプロモーションを実装していきます。
プロモーションとは
promotion は英語で昇格という意味です。
ポーンが相手の陣地の最深部(白から見れば8ランク、黒から見れば1ランク)まで進むと、ポーンとキングを除くいずれかの駒に変身します。
どの駒になるかは選択可能ですので、
選択肢を表示して選んでもらう、ユーザとの双方向的なやりとりが必要となります。
動作のプロセスは次のようになります。
- ポーンが最深部にたどり着く
- どの駒にプロモーションするか選択肢を表示する
- ユーザが駒を選択する
- 選択された駒を認識する
- ポーンが選択された駒に変化する
プロモーションの条件を定義
まずはプロモーションの条件を定義します。
main.py1class Game:2def __init__(self):3...4# プロモーションの条件を満たすか5self.prom = False6...7...89def main(self):10...11if None not in startpos + endpos:12try:13target = self.gameboard[startpos]14except:15self.message = "could not find piece; index probably out of range"16target = None17...18self.renew_gameboard(startpos, endpos, self.gameboard)19self.promotion(target, endpos)20if self.is_check(target.color, self.gameboard):21self.message = f"{target.color} player is in check"22...2324def promotion(self, piece, endpos):25'''26プロモーションできるとき,True2728Parameters29----------30piece : obj31駒.32endpos : tuple > (int, int)33終了位置.3435Returns36-------37bool38'''39if (piece.name == 'WP' and endpos[1] == 740or piece.name == 'BP' and endpos[1] == 0):41self.prom = True
動くたびにプロモーションができる状態かどうかを判定し、その結果を変数に入れて管理します。
選択肢を表示する吹き出しを描画
プロモーションするポーンから吹き出しをのばして、その吹き出しの中に選択肢となる駒を描画することにします。
glVertex()
で指定しているのはワールド座標であり、このプログラムでは縦横軸ともに -1.0 ~ 8.0 の値をとるように調整しています()。
utils.py1def draw_balloon(x, y):2'''3プロモーションのときの吹き出しを描画する45Parameters6----------7x, y : int8駒の座標.9'''10glColor(0.5, 0.5, 0.5) # 色の指定11glBegin(GL_QUADS) # 四角形を描画12glVertex(1.0, 2.5)13glVertex(1.0, 4.5)14glVertex(6.0, 4.5)15glVertex(6.0, 2.5)16glEnd()17glBegin(GL_TRIANGLES) # 三角形を描画18glVertex(3.0, 3.5)19glVertex(4.0, 3.5)20glVertex(x, y)21glEnd()
プロモーションできる状態にある、すなわちさきほど設定した変数self.prom
がTrue
となるときに、この吹き出しを描画させます。
main.py1def draw(self):2...3# 可能な移動先の表示4if self.select_dest and None not in self.startpos:5piece = self.gameboard[self.startpos]6draw_available_moves(7self.valid_moves(piece, self.startpos, self.gameboard),8opponent=self.playersturn != piece.color)9# プロモーション10if self.prom:11draw_balloon(*self.endpos)12glDisable(GL_BLEND)13glutSwapBuffers()
ここでいったん動作を見てみましょう。
選択肢として4つの駒をこの吹き出しの上に並べて乗せることになります。
駒の描画はdraw_img()
を使えばできます(定義はにて)。
main.py1def draw(self):2...3# プロモーション4if self.prom:5draw_balloon(*self.endpos)6piece_color = self.gameboard[self.endpos].color7glEnable(GL_TEXTURE_2D)8draw_img(2.0, 3.5, piece_ID[piece_color + 'N'])9draw_img(3.0, 3.5, piece_ID[piece_color + 'B'])10draw_img(4.0, 3.5, piece_ID[piece_color + 'R'])11draw_img(5.0, 3.5, piece_ID[piece_color + 'Q'])12glDisable(GL_TEXTURE_2D)13...
ちなみに、piece_color
はこの時点ではwhite
かblack
になってしまうので、エラーになってしまいます。
駒色の文字列を変更します。
pieces.py1WHITE = "white"2WHITE = "W"3BLACK = "black"4BLACK = "B"
これで選択肢を表示することができました。
選択された駒を認識
どれがクリックされたのかを認識させます。
特定の範囲内をクリックしたときにTrue
となるような関数を作ります。
utils.py1def on_square(x, y, left, right, bottom, top):2'''3left < x < right かつ bottom < y < top のとき,True45Parameters6----------7x, y : float8測定する座標.9left, right, bottom, top : float10ボタンの左右下上端の座標.1112Returns13-------14bool15'''16if left < x < right and bottom < y < top:17return True
これを使って、マウスでクリックした位置をもとに、どの駒が選択されたか認識し、
選択された駒のを生成してポーンと置き換えます。
main.py1def mouse(self, button, state, x, y):2...3self.mousepos = window2world(x, y, WSIZE)4...5# 駒選択6elif (self.parse_mouse() in self.gameboard7and not self.prom):8...9# プロモーション10if self.prom:11piece_color = self.gameboard[self.endpos].color12if on_square(*self.mousepos, 1.5, 2.5, 3.0, 4.0):13self.gameboard[self.endpos] = Knight(piece_color, piece_color + 'N')14self.prom = False15if on_square(*self.mousepos, 2.5, 3.5, 3.0, 4.0):16self.gameboard[self.endpos] = Bishop(piece_color, piece_color + 'B')17self.prom = False18if on_square(*self.mousepos, 3.5, 4.5, 3.0, 4.0):19self.gameboard[self.endpos] = Rook(piece_color, piece_color + 'R')20self.prom = False21if on_square(*self.mousepos, 4.5, 5.5, 3.0, 4.0):22self.gameboard[self.endpos] = Queen(piece_color, piece_color + 'Q')23self.prom = False
これでプロモーションが実装できました!
今回の変更も GitHub に置いておきます。
→ Release codes after 11 articles · midorimici/chess-program-for-python-and-OpenGL
はついに最後の特殊ルール、キャスリングを実装していきます。
お読みいただきありがとうございました。
ではまた