囲碁は将棋にくらべてもそれを楽しむ人口が少なく、他のゲームの中で考えれば、既に「化石」のようなゲームともいえよう。
それでも小さなころから囲碁に親しんできたぼくからすると、囲碁人口が少しでも増えれば、という思いはある(とはいえ、実際、地方在住の自分のまわりで囲碁をうつ人は80歳前後の人ばかり、というのが現実だが)。
現在、Unityで9x9路盤で、コンピューターと対戦するゲームをつくりスマホで配布する、という最終目標をもっている。既にそのようなスマホアプリは存在するが、将棋等、他のゲームアプリに比べると(囲碁人口が少ないため)数は多くないので、新規に作成する余地はありそう。なによりも、ぼく自身がつくりたい、と思う。
今回は、その手始めとして、人対人の囲碁対戦ゲームをPythonでつくった。Pythonに詳しくないぼくは、以前の経験
( https://qiita.com/tkoji3744/items/08b71054dfba4f93f2c4 )
にならい、ChatGPTに全面的に助けてもらった。
1.提案されたプロジェクト構造
go_types.py
囲碁で使う基本的な型やデータ構造を定義します。
例: Stone(白石/黒石/空点のEnum)、Player(プレイヤー情報)、GameMode(人対人 or 人対ボット)。
go_board.py
囲碁盤のモデルと関連するロジックを記述します。
例:
碁盤の初期化
石の配置
ルールチェック(陣地、アタリ、コウ、セキなどの判定)
go_game.py
対局全体を管理するクラス/モジュールです。
プレイヤーの管理
ターンの進行
終局判定
main.py
プログラムのエントリーポイント。
ここでユーザーインターフェースを統合します(CLI、GUI、またはウェブ)。
bot.py
人対ボットの場合のAIロジック。
シンプルなランダムムーブから始め、後でアルゴリズム(例: モンテカルロ木探索)を追加可能。
今回は、人対人の対戦なので、bot.pyはつくらない。
2.ファイル作成
それぞれのファイルは初期のものをChatGPTでつくってもらい、main.pyで実際に起動しながら、ChatGPTに修正点を提示してなおしてもらった。
例
① main.pyを実行すると碁盤が表示され、交互に黒白とうつことができるようになりました。次は、(1)囲んだ後,石をとる(2)囲まれた中には、石がうてない(自殺手の禁止)(3)(2)の例外で、コウがある、というルールをいれたいです。go_board.pyの書き換えで良いですか?
②囲んでも、画面から囲まれた石がきえません
ChatGPT
囲まれた石が画面から消えない原因として考えられるのは、以下の可能性です:
remove_dead_stones メソッドが正しく呼び出されていない
place_stone メソッド内で石を取り除く処理が適切に動作しているか確認します。
GUI が碁盤の状態を正しく反映していない
石が削除された後、main.py の描画部分で碁盤の状態を再描画する必要があります。
修正案
- go_board.py の確認
以下のコードに問題がないか確認します。
python
def remove_dead_stones(self, stone):
"""
指定した石のグループで囲まれているものを取り除く。
"""
to_remove = []
for y in range(self.size):
for x in range(self.size):
if self.board[y][x] == stone and not self.get_liberties(x, y):
to_remove.append((x, y))
for x, y in to_remove:
self.board[y][x] = Stone.EMPTY
ここで get_liberties が正しく動作し、囲まれた石の座標が to_remove に収集されていることを確認してください。
2.main.py での再描画処理
囲まれた石が削除された後、GUI を再描画する必要があります。以下を追加してください。
def handle_click(self, event):
"""クリック処理"""
x = int(event.x // self.cell_size)
y = int(event.y // self.cell_size)
if self.board.place_stone(x, y, self.current_turn):
self.redraw_board() # すべての石を再描画
self.current_turn = Stone.BLACK if self.current_turn == Stone.WHITE else Stone.WHITE
追加: redraw_board メソッド
def redraw_board(self):
"""碁盤全体を再描画"""
self.canvas.delete("all") # 現在の描画をクリア
self.draw_grid() # 碁盤の目を再描画
for y in range(self.board_size):
for x in range(self.board_size):
stone = self.board.board[y][x]
if stone != Stone.EMPTY:
self.draw_stone(x, y, stone)
この処理では、碁盤全体を消去し、GoBoard の状態に基づいて石を再描画します。
③ うまくいきました。次に欲張りですが、囲んで取った石は、自分の「ごけ」にいれておくことができます(終局の際、相手の「地」にいれる)。この「ごけ」に相当するものを、碁盤の外に描画し、取ったあとその中に取った数の相手の石をいれたものを表示せねばなりません。どうしたらいいでよう?
ChatGPT
囲んだ石を「ごけ」に入れ、それを碁盤の外に描画する仕組みを追加する方法をご案内します。この機能を実現するために、以下の手順を取ります。
目標
取った石を「ごけ」として管理
各プレイヤーの取った石の数をカウントし、保持します。
「ごけ」を碁盤の外に描画
碁盤の隣に「ごけ」を表示し、取られた石の数を更新します。
ゲーム進行中に「ごけ」を更新
石を取った際、自動的に「ごけ」に反映させます。
修正手順
GoBoard クラスに「ごけ」の管理を追加
go_board.py に以下の変更を加えます。
そして、2時間たらずで、下記のようなゲームが完成した。
*連絡いただければ、すべてのソースコードあるいはpython packageをお送りします。
囲碁のルールについては、既製であり、ぼく自身が詳しいので提案がスムーズにできたことが大きいと思う(新作ゲームだと、自分の頭の中のルールがあいまい)。
個人的に感じた今後の課題(人 vs ボット)
1. 終局の判定
さもないと、ボット、が空いている自分の「地」にどんどん、自分でうっていってしまう。
2.そしてボットを強くする
ChatGPTは、最後に今後の展望をしめしてくれた。Unityでつくる9x9路盤にどれだけ役に立つが未知だが、興味深い情報だった。
既存のオープンソース実装の概要
Leela Zero
言語: 主にC++で実装されています。
特徴:
強力な性能を持つ囲碁AI。
モデルの学習済みデータを利用可能。
Pythonと連携するために「外部プロセス」や「通信」を使用できます。
MiniGo
言語: Pythonを使用しています。
特徴:
Googleの研究者によって開発された簡易版AlphaGo/AlphaZero。
TensorFlowを利用しているため、Pythonで直接操作可能。
小規模環境でも利用可能。