10年ぶりのプログラム「引退したプログラマーがPythonでAIプログラミングに挑戦する」-07:開発_コマを動かす準備

プログラムの方向について

これからコマを動かしていきますが、作ろうとしているプログラムの考えを説明します。

まず、コマを動かす前に、すべてのコマの移動可能先リストを作成します。
そして実際にマウスで動かしたときに、その移動先が、移動可能リストに含まれているかどうかを判断します。
含まれていたら、その移動先への移動を許可します。
含まれていなかったら、無効な移動とします。有効な移動をクリックするまでその人の手番が続きます。(この際、わざわざエラーメッセージを出すことはやりすぎだと思うのでやりません。実際そういうソフトを見たことはありません。)

上記を別のやり方で実装することも可能だと思います。
たとえば、
・まずコマを動かす。
・そのあとで、この移動先が有効可動かどうかを判断する。
というものです。

わたしが最初に提示したやり方ですと、ポーン、ルーク、キング・・とすべてのコマに対して有効な移動先リストを作成します。
一方、後者ですと、移動したコマだけについて、その移動先が有効かどうかを考えます。
一見すると後者の方が処理も早いですし、スッキリしているかもしれません。

しかし、前者を選んだ理由はあります。それは、コマをクリックしたときに「移動可能な場所」をボード上に表示させたいからです。
チェスの場合、ルールを知らない人も多いと思うので、移動可能先を表示することは、極めてユーザーフレンドリーだと考えます。実際、この機能が付いているソフトは多いと思います。これが前者を選択した理由です。

ちなみに、移動可能な場所を表示するとは、こういうことになります。

ではこれから実装を始めます。

移動可能先リストの作成

get_all_possible_movesという関数をクラスの中に作ります。この関数の中で、コマごとのすべての移動可能先のリストを作成します。

方針は下記になります。

・まず、ボード上のすべてのセルをチェックします。
・そのときに、自分の手番と同じ色のコマがあったら、そのコマの移動可能な全てのマスを取得します。
・その取得したマスをリストにセットします。

つまりこのリストは、手番が変わるたびに更新されるということです。

なお、コマの色は、ボード上の値の1文字目で、コマの種類は2文字目です。
たとえばrow=3, col=1のマスにあるコマの色と種類は
コマの色:board[3][1][0]
コマの種類:board[3][1][1]
となります。

コマの種類によって動ける場所は異なります。なので、このget_all_possible_movesの中で、それぞれのコマに応じたサブ関数を用意して呼び出すことにします。

ポーン:get_Pawn_moves
ビショップ:get_Bishop_moves
ナイト:get_Night_moves
ルーク:get_Rook_moves
クイーン:get_Queen_moves
キング:get_King_moves

この関数を呼び出すときに、わたしはif文を使いますが、もしかしたらswitchなどの呼び方もあるかもしれません。


なお、先に少しネタバレをしますと、このget_all_possible_movesで取得されたリストが、有効な移動先リストになるわけではありません。このリストからの、追加削除が必要となります。

削除:理論上は移動可能であっても、チェックがかかっているときには、そのチェックを回避できない動きは全て無効になります。そのような動きはこのリストから削除される必要があります。
(チェックとは、将棋でいうところの、王手のことです。)

追加:チェスには特殊な2つの動きがあります。それは「キャスリング」と「アンパッサン」というものです。この特殊な動きを、このリストに追加する必要があります。(ポーンプロモーションという特殊な動きもありますが、移動可能なリストには影響を及ぼしません。)

そこで、get_valid_movesという関数をつくり、その中で、リストの作成・追加・削除を行います。
作成:get_all_possible_movesの呼び出し
追加:特殊な動き
削除:チェック回避

以上が今回作成するプログラムの方向性です。

chess_engine.py

上記をこれから実装します。

まずはクラスの中で
get_valid_moves
get_all_possible_moves
という関数を作成します。

get_valid_moves

get_valid_moves

get_valid_movesは、いまのところは、get_all_possible_movesを呼ぶだけです。そして移動可能な配列をReturnします。

get_all_possible_moves

get_all_possible_moves

get_all_possible_movesでは、boardの中から、自分の色のコマを探し、そのコマの種類に応じた動きを作成するという流れになります。ちなみにboard、自分の色は同じクラスの中の変数(プロパティ)ですので、引数としては不要です。この作成した値を配列にセットし、get_valid_movesに返す、という仕組みにします。
そして最後のif文のところで、それぞれのコマに応じた関数を呼び出すことになります。その実装は次回行います

chess_main.py

get_valid_movesの呼び出し

次に、このget_valid_movesをchess_mainから呼び出すコーディングをします。

この関数を呼び出す目的は、コマを動かす前に、有効な移動先リストを取得することです。なので呼び出す場所は2箇所です。
1)1手目を打つ前です。つまりwhileループ処理に入る前です。
2)1手打った直後です。相手の手番に変わりますので、リストを再取得する必要があります。

本来はこの2箇所だけでいいのですが、今はZボタンを押すとやり直しがされるようになっています。それゆえに、Zボタン押下後にも、再取得は必要です。

合計で、この3箇所に追加をする必要があります。

valid_movesの呼びだし1
valid_movesの呼び出し2
valid_movesの呼び出し3

移動可能リストとマウスクリックの比較

get_valid_movesを呼び出すと、移動可能なリスト(配列)がReturnされます。この配列の中に、今マウスで動かそうとしている内容が含まれているかどうかを判断します。
マウスクリックで得られる情報は、
移動元のRow+Col
移動先のRow+Col
です。
これは、make_moveを呼ぶときに作成した値です。

比較作業のとき、上記と同じ形式が、移動可能なリストに含まれていると処理が容易です。次回get_all_possible_movesの開発をするときに、この配列に値をセットしますが、そのときには上記を配慮します。

比較処理は、マウスを2回クリックしたあとで行います。ループ処理になるので、別関数を作り、その結果でTrue/Falseを返すこととします。ループ処理の前に、そのリストがブランクだったら、Falseを返すこととします

check_valid_move

この関数をwhile文の中で呼び出して、Trueだった場合にのみmake_moveを呼び出すこととします。そして、クリック内容をクリアします。

whileの中での呼び出し

実行

この状態で実行をしますと、マウスを動かせないと思います。その理由は、Returnされる配列がブランクだからです。

デバッグのために、普通の動きと、間違った動きの2個を登録してみます。
普通の動きとしては、左下のポーンを1つ前に進めるというものにします。
間違った動きとしては、一番左上のルークを、一番右下に動かすというものにします。

データの強制追加

この状態であれば動かすことはできます。

次回からは、
ポーン
ナイト
ビショップ
ルーク
クイーン
キング
の順番でコーディングをしていきます。

今回は以上となります。


使用しているチェスのコマは、下記からダウンロードしました。
By jurgenwesterhof (adapted from work of Cburnett) - http://commons.wikimedia.org/wiki/Template:SVG_chess_pieces, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=35634436

この記事が気に入ったらサポートをしてみませんか?