Python プログラムで動かすフェアリーチェスアプリ開発、連載第2回です。
は、既存のチェスのプログラムがどのように動いているか大枠を見てみました。こちらのプログラムです。
今回は実際にコードを修正しつつ、細かい動作についてみていきたいと思います!
なお、このシリーズでは、あまりプログラミングに詳しくない人、はじめたばかりの人にも気軽に読んでもらいたいので、
できるだけ初歩的なところから解説していきたいと思っています。
ただ、基礎理論などは書かれているサイトがたくさんあるので、ここでは応用的な面を重視して書いていきます。
その前に
まず編集しやすくするために、コードを2つのに分けます。
main.py1from pieces import *23uniDict = ...45class Game:6...78Game()
pieces.py1WHITE = "white"2BLACK = "black"34class Piece:5...
ところで、このコード中にあるclass
とかdef
は
例えば、次のコードを走らせても見た目上は何も起きません。
1def f():2print('abc')
しかし、これのあとにf()
と書けば、コマンドラインにabc
とプリントされます。
では、このチェスのコードにおいて一番最初に動き出すのはどこかというと、
一番最後の行のGame()
です。
これによってGame
のインスタンス(クラスをもとに作られた分身のようなもの)が生成され、
その際にコンストラクタ__init__()
が呼び出されます。
コンストラクタは初期化メソッドで、インスタンス生成時に自動で実行されます。
main.py1class Game:2def __init__(self):3self.playersturn = BLACK4self.message = "this is where prompts will go"5self.gameboard = {}6self.placePieces()7print("chess program. enter moves in algebraic notation separated by space")8self.main()910...
次に、コンストラクタの中でmain()
が呼びだされます。
(self
がついてたりついてなかったりするのは、初期の段階ではあまり気にしなくて大丈夫です!おまじないみたいなものだと思ってください)
main.py1...23def main(self):45while True:6self.printBoard()7print(self.message)8self.message = ""9startpos,endpos = self.parseInput()10...
このmain()
の中で、盤面やメッセージを表示したり、ユーザ入力を受け付けたりしているわけです。
そしてこのメソッド内で使うためにいろいろなメソッドが他の場所で定義されています。
それでは、ここからは実際にコードを修正していきましょう。
黒先→白先
チェスでは白が先手です。まずはこちらを修正したいと思います。
Game
中のself.playersturn
がにおいますね。
main.py1...23class Game:4def __init__(self):5self.playersturn = BLACK6self.message = "this is where prompts will go"7self.gameboard = {}8self.placePieces()9print("chess program. enter moves in algebraic notation separated by space")10self.main()11...
ここのself.playersturn = BLACK
をself.playersturn = WHITE
に変えればよさそうです。
できた!
黒のクイーンとキングの位置
本来初期配置では d8 にクイーン、 e8 にキングが来るはずです。
駒の配置に問題があるので、名前だけ見るとplacePieces()
が怪しいですね。
main.py1class Game:2...34def placePieces(self):56for i in range(0,8):7self.gameboard[(i,1)] = Pawn(WHITE,uniDict[WHITE][Pawn],1)8self.gameboard[(i,6)] = Pawn(BLACK,uniDict[BLACK][Pawn],-1)910placers = [Rook,Knight,Bishop,Queen,King,Bishop,Knight,Rook]1112for i in range(0,8):13self.gameboard[(i,0)] = placers[i](WHITE,uniDict[WHITE][placers[i]])14self.gameboard[((7-i),7)] = placers[i](BLACK,uniDict[BLACK][placers[i]])15placers.reverse()16...1718uniDict = {WHITE : {Pawn : "♙", Rook : "♖", Knight : "♘", Bishop : "♗", King : "♔", Queen : "♕" },19BLACK : {Pawn : "♟", Rook : "♜", Knight : "♞", Bishop : "♝", King : "♚", Queen : "♛" }}
なんだか難しそうですが、ちょっとずつ見ていきましょう。
gameboard
は、コンストラクタでself.gameboard = {}
とされているので、
self.gameboard = {}
は、空のディクショナリをつくる文です。
6~8行目を見ると、gameboard
は二要素
Pawn(WHITE,uniDict[WHITE][Pawn],1)
は、Pawn
の
確か、コードの下の方にPawn
クラスがありましたね。
pieces.py1class Pawn(Piece):2def __init__(self,color,name,direction):3self.name = name4self.Color = color5#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"6self.direction = direction
color
は駒の色。
name
は名前ですが、uniDict
で絵文字が指定されることになります。
direction
はポーンが進む方向ですね。(コメントは原文ママ。)
要は、7行目は「盤面のこの位置には白のポーンを置きますよ」と言っているだけです。
8行目も同様。
ということで、6~8行目は、「2ランクに白ポーン、7ランクに黒ポーンを配置」という意味になります。
さて、以降はこれを拡張しただけです。
main.py1placers = [Rook,Knight,Bishop,Queen,King,Bishop,Knight,Rook]23for i in range(0,8):4self.gameboard[(i,0)] = placers[i](WHITE,uniDict[WHITE][placers[i]])5self.gameboard[((7-i),7)] = placers[i](BLACK,uniDict[BLACK][placers[i]])
(行数を改めます。)
4行目では、例えばi
が0
のとき、
(0, 0)
(a1)の位置にplacers[0]
すなわちRook
が置かれます。
uniDict[WHITE][placers[0]]
は♖
になりますね。
さて、問題は5行目です。
例えばi
が0
のとき、
(7, 7)
の位置に駒が置かれます。
これでは黒の駒と白の駒が盤面の中心に関して点対称に配置されていくのがわかりますでしょうか?
i
が3
のとき、placers[3]
はQueen
ですが、
白クイーンは(3, 0)
に置かれ、黒クイーンは(4, 7)
に置かれますね。
本当は(3, 7)
に置きたい。
点対称ではなく、線対称に配置したいのです。
ということで、5行目の((7-i),7)
を、(i, 7)
に変えてしまいましょう!
やったね!
(ところで、メソッドの最後にあったplacers.reverse()
は何がしたいのかよくわかりません。)
今回は比較的簡単に直せるところを直してみました。
他にもいろいろと追加すべき機能はありますが、ひとつずつ取り上げていこうと思います!
ご覧いただきありがとうございました。
それではまた