Python プログラムで動かすフェアリーチェスアプリ開発、連載第 15 回です。
はフェアリー駒を作成しました。今回はさまざまな種類のフェアリーチェスを切り替えられるようにしていきます。
現在の状態では、スクリプトを起動するとすぐに盤面が表示されて遊べる状態になりますが、
この前にいったんゲーム種類を選択する画面を入れます。
選択画面では5行2列、1ページで10種類のゲームを並べることにします。
画面で特定のボタンを押すと、対応するゲームの盤面がセットされてゲームがスタートするようにします。
そのためには、押したボタンによってセットする盤面や駒を変化させることになります。
ゲームを定義する
ゲームによって変化するのは、盤面のサイズ、キャスリングの有無、ポーンのプロモーション先、
どの駒がどこに置かれているのかや、画像IDと駒の対応の情報です。
これらを定義したクラスをゲーム種類ごとに作成します。
これらのクラスの定義をまとめたモジュールgames.py
を作成します。
games.py1'''ゲームの種類によって変わる駒の配置や名前、画像IDを記録したモジュール'''23from pieces import *456class Normal:7'''通常のチェス'''8# 盤面のサイズ9size = 810# キャスリングの有無11castling = True12# プロモーション先13promote2 = [Knight, Bishop, Rook, Queen]14# 駒の配置15placers = {1: [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook],162: [Pawn] * size}17# 画像IDの割り当て18ID = {}19for rk in placers:20for fl in range(size):21if placers[rk][fl] is not None:22ID['W' + placers[rk][fl].abbr] = size * rk + fl23ID['B' + placers[rk][fl].abbr] = -(size * rk + fl)242526class withUnicorn:27'''キングサイドのナイトがユニコーンになったチェス'''28# 盤面のサイズ29size = 830# キャスリングの有無31castling = True32# プロモーション先33promote2 = [Knight, Bishop, Rook, Queen, Unicorn]34# 駒の配置35placers = {1: [Rook, Knight, Bishop, Queen, King, Bishop, Unicorn, Rook],362: [Pawn] * size}37# 画像IDの割り当て38ID = {}39for rk in placers:40for fl in range(size):41if placers[rk][fl] is not None:42ID['W' + placers[rk][fl].abbr] = size * rk + fl43ID['B' + placers[rk][fl].abbr] = -(size * rk + fl)
クラス名は駒クラス名と異なることに注意します。
画像IDには、各種各色の駒に一意的に整数が割り当てられます。
これらのクラスをもとにしてインスタンスを作成し、その属性を元に盤面や駒を設置します。
インスタンス作成のタイミングは、ゲームの種類が決まったとき=特定のボタンが押されたときですが、
ひとまずインスタンスを代入する変数の宣言をしておきます。
main.py1class Game:2def __init__(self):3self.playersturn = W4self.gameboard = {}5self.place_pieces()6# ゲームの種類7self.kind = None8...910def after_deciding_kind(self):11'''ゲーム種類決定後の処理'''12# 駒の配置13self.place_pieces()14# 画像の設定15for name, num in self.kind.ID.items():16set_img(name, name[0], num)1718def place_pieces(self):19for i in range(0, 8):20self.gameboard[(i, 1)] = Pawn(W, 1)21self.gameboard[(i, 6)] = Pawn(B, -1)2223placers = [Rook, Knight, Bishop, Queen, King, Bishop, Unicorn, Rook]2425for i in range(0, 8):26self.gameboard[(i, 0)] = placers[i](W)27self.gameboard[(i, 7)] = placers[i](B)28for fl in range(self.kind.size):29for rk in self.kind.placers:30# None を指定すれば駒が置かれることはなく次のマスへ進む31if self.kind.placers[rk][fl] is not None:32# 白の駒33self.gameboard[(fl, rk - 1)] = self.kind.placers[rk][fl]('W')34# 黒の駒35self.gameboard[(fl, self.kind.size - rk)] = self.kind.placers[rk][fl]('B')36...
after_deciding_kind
メソッドで、インスタンスの属性をもとに駒の配置と画像IDの設定をしています。
Pawn
クラスでは独自にコンストラクタを設定していましたが、
色によって進む方向は明白なので特別に定義する必要はありません。
pieces.py1...23class Pawn(Piece):4abbr = 'P'56def __init__(self, color, direction):7self.color = color8# of course, the smallest piece is the hardest to code. direction should be either 1 or -1, should be -1 if the pawn is traveling "backwards"9self.direction = direction10self.name = color + self.abbr1112def available_moves(self, x, y, gameboard):13self.direction = 1 if self.color == 'W' else -114...
ゲームボタンを表示する
5行2列にボタンを並べる関数を定義します。
utils.py1...2def draw_button(left, right, bottom, top,3letter, back_color=(1.00, 0.81, 0.62), font_color=(0.82, 0.55, 0.28)):4'''ボタンを描画する56Parameters7----------8left, right, bottom, top : float9ボタンの左右下上端の座標.10letter : str11ボタン上に描画する文字.12back_color : tuple or list, default (1.00, 0.81, 0.62)13ボタンの色.14font_color : tuple or list, default (0.82, 0.55, 0.28)15文字の色.16'''17glColor(*back_color)18glBegin(GL_QUADS)19glVertex(left, bottom)20glVertex(left, top)21glVertex(right, top)22glVertex(right, bottom)23glEnd()24glColor(*font_color)25draw_str((left + right) / 2 - 0.1 * len(letter), (bottom + top) / 2, letter, gap=0.2)262728# ゲーム選択画面に表示するゲーム名29game_name_dict = {0: ('Normal Chess', 'Unicorn', 'A', 'B', 'C'),301: ('D', 'E', 'F')}313233def draw_game_menu():34'''ゲーム選択メニューを描画する'''35for i in range(2):36for j in range(5):37if i in game_name_dict and j < len(game_name_dict[i]):38draw_button(4.5*i - 0.5, 4.5*i + 3.0, 6.5 - 1.5*j, 7.5 - 1.5*j,39game_name_dict[i][j])40...
25行目の0.1
や 0.2
という数値は見え方によって調整します。
これを描画イベント内部で使用します。
main.py1from utils import *2...34class Game:5...6def draw(self):7...8if self.kind == None:9draw_game_menu()10else:11if self.time == 1:12self.main()13...14...
これでボタンが表示されました。
ボタンクリックに対応する
ボタンをクリックしたときに、指定のゲーム種類を内部で登録するようにします。
まず、表示位置に対応するゲームクラスを格納するディクショナリを定義します。
games.py1...2# ゲーム選択画面に表示するゲーム3game_dict = {0: (Normal, withUnicorn)}
表示用に使ったA B C ...
はクラスを作っていないので省いています。
これを使ってマウスイベントの処理を書きます。
main.py1...2from games import *3...45class Game:6...7def mouse(self, button, state, x, y):8...9# 左クリック10if (button == GLUT_LEFT_BUTTON11and state == GLUT_DOWN):12try:13# ゲーム種類選択14if self.kind == None:15for i in range(2):16for j in range(5):17if i in game_dict and j < len(game_dict[i]):18if on_square(*self.mousepos, 4.5*i - 0.5, 4.5*i + 3.0, 6.5 - 1.5*j, 7.5 - 1.5*j):19self.kind = game_dict[i][j]()20self.after_deciding_kind()21else:22...23...
これでゲームの選択を実現できました。
ボタンを選択すると盤面と駒が表示されます。
今回の変更は GitHub にて公開しています。
基本的にこれまで解説してきたことを使えば、フェアリー駒の作成やゲーム種類の拡張をすることができるようになります。
あとは特殊な挙動の駒をどう実装するか、などといった細かい話になってきます。
お読みいただきありがとうございました。
ではまた