[ English | 日本語]
reversiはリバーシ(オセロ)のPython用ライブラリです。
手軽にリバーシAIをプログラミングして、アプリケーションが作れます。
- 概要
- 動作環境
- インストール方法
- アンインストール方法
- サンプル
- ライブラリの活用事例
- ライブラリの使い方
- tkinterアプリケーションの遊び方
- コンソールアプリケーションの遊び方
- インストールがうまくいかない場合
- 参考書籍
- 参考サイト
- 脚注
- ライセンス
reversiはPythonで作られた1Pythonで使えるリバーシのライブラリです。
reversiをインストールすると、リバーシAIのプログラミングを手軽に試せるようになります。
他にも、以下のような用途に使えます。
- アプリケーションを作って、自作したAIと対戦し遊ぶ
- シミュレータを使って、AI同士をたくさん対戦させ強さを調べる
また、本ライブラリを使って作成したWindows版アプリケーションも用意しています。
こちらはダウンロード後、インストール不要で、すぐにリバーシのゲームを無料でプレイできます。
- Windows、Ubuntu、MacOS
- ディスプレイサイズ 1366x768 以上
- プロセッサ 1.6GHz 以上
- メモリ 4.00GB 以上
- Python 3.7.6(MacOSは3.11)以上
- cython 0.29.15
- pyinstaller 3.6
- cython 0.29.15
- Microsoft Visual C++ 2019(Python3.7以外のWindowsの場合)
- Python 3.7.6をインストールして下さい。
- 下記を実行してreversiをインストールして下さい。
$ pip install git+https://github.com/y-tetsu/reversi
reversiをアンインストールする場合は、下記を実行して下さい。
$ pip uninstall reversi
reversiをインストール後、任意のフォルダで下記コマンドを実行すると、サンプルをコピーできます。
$ install_reversi_examples
コピーされるサンプルは下記のとおりです。
- 01_tkinter_app.py - tkinterを使ったGUIアプリケーション(#遊び方)
- 02_console_app.py - コンソール上で遊ぶアプリケーション(#遊び方)
- 03_create_exe.bat - GUIアプリケーションのexeファイルを作成するバッチファイル
- 04_reversi_simulator.py - AI同士を対戦させて結果を表示するシミュレータ
- 05_manual_strategy.py - 自作したAIを実装するサンプル
- 06_table_strategy.py - テーブルによる重みづけで手を選ぶAIを実装するサンプル
- 07_minmax_strategy.py - MinMax法で手を選ぶAIを実装するサンプル
- 08_alphabeta_strategy.py - AlphaBeta法で手を選ぶAIを実装するサンプル
- 09_genetic_algorithm.py - 遺伝的アルゴリズムを使ってテーブルの重みを求めるサンプル
- 10_variant_board_solver.py - 変則ボードの解析ツール
サンプルの実行方法はそれぞれ下記のとおりです。
$ cd reversi_examples
$ python 01_tkinter_app.py
$ python 02_console_app.py
$ 03_create_exe.bat
$ python 04_reversi_simulator.py
$ python 05_manual_strategy.py
$ python 06_table_strategy.py
$ python 07_minmax_strategy.py
$ python 08_alphabeta_strategy.py
$ python 09_genetic_algorithm.py
$ python 10_variant_board_solver.py
本ライブラリを活用して実現できた事例をいくつかご紹介します。
- 「Google音声認識ライブラリを使用して、音声オセロを作成」https://qiita.com/shirox22/items/b9ea6d6c90a172cb9968
- 「自作したリバーシAIでEdaxに挑む!」https://qiita.com/y-tetsu/items/2d5a199e401aa846891f
- 「リバーシの全消しパターンを見てみたい!」https://qiita.com/y-tetsu/items/6856dc50f1b130b26a56
- 「天下一リバーシAI武道会」https://qiita.com/y-tetsu/items/2a32a157567655fa12ac
- 「リバーシの最短全滅手順を幅優先探索であぶり出す!」https://qiita.com/y-tetsu/items/2ec05d184bf6cf9ac869
本ライブラリの基本的な使い方を、コーディング例を元に説明します。
まず最初に、リバーシのGUIアプリケーションを起動させる方法を示します。
下記のコードを実行して下さい。
from reversi import Reversi
Reversi().start()
上記のようにアプリケーションが起動し、そのまま二人対戦で遊ぶ事ができます。
(この場合、選択できるプレイヤーはユーザ操作のみとなります)
次に、AIをアプリケーションに追加する方法を示します。
例として、ライブラリにあらかじめ組み込まれている下記AIをアプリケーションに追加します。
- ランダムな手を打つAI :
Random
- できるだけ多く石が取れる手を打つAI :
Greedy
from reversi import Reversi
from reversi.strategies import Random, Greedy
Reversi(
{
'RANDOM': Random(),
'GREEDY': Greedy(),
}
).start()
上記を実行すると、ユーザ操作に加えて"RANDOM"と"GREEDY"をプレイヤーとして選択できるようになります。
組み込みのAIは、すべてreversi.strategies
よりインポートすることができます。
他に使用可能なAIについての詳細はAIクラス編を参照して下さい。
また、追加するプレイヤーの情報(以後、"プレイヤー情報")は、下記フォーマットに従って下さい。
プレイヤー名については任意に設定可能です。
{
'プレイヤー名1': AIクラスのオブジェクト1,
'プレイヤー名2': AIクラスのオブジェクト2,
'プレイヤー名3': AIクラスのオブジェクト3,
}
続いて、本ライブラリを使って独自のAIを自作し、アプリケーションに追加する方法を示します。
下記のようにコーディングすると、AIクラスが完成します。
from reversi.strategies import AbstractStrategy
class OriginalAI(AbstractStrategy):
def next_move(self, color, board):
#
# 次の一手(X, Y)を決めるロジックをコーディングして下さい。
#
return (X, Y)
next_move
メソッドには特定の手番および盤面の時に、どこに石を打つか(次の一手)を返すロジックを実装します。
next_move
メソッドの引数は下記を参照して下さい。
引数 | 説明 |
---|---|
color 変数 |
black かwhite のstr 型の文字列が渡され、それぞれ黒番か白番かを判別することができます。 |
board オブジェクト |
リバーシの盤面情報を持ったオブジェクトが渡されます。黒と白の石の配置情報のほか、石が置ける位置の取得などゲームを進行するために必要となる、パラメータやメソッドを持っています。 |
なお、戻り値の(X, Y)座標は盤面左上を(0, 0)とした時の値となります。
盤面サイズが8の場合の各マス目の座標を下図に示します。
board
オブジェクトについてはここでは簡単のため、
石が置ける位置を取得するget_legal_moves
メソッドと、
盤面のサイズを取得するsize
パラメータの、2つを取り上げます。
より詳しい説明はboardオブジェクトの使い方を参照して下さい。
ある盤面の石が置ける位置(座標)はboard
オブジェクトのget_legal_moves
メソッドで取得できます。
get_legal_moves
呼び出し時の引数には、黒か白のどちらかの手番(color
変数)を与えて下さい。
legal_moves = board.get_legal_moves(color)
get_legal_moves
の戻り値"石が置ける座標のリスト"となっています。
初期状態(盤面サイズ8)での黒手番の結果は下記のとおりです。
[(3, 2), (2, 3), (5, 4), (4, 5)]
本アプリケーションは、盤面のサイズとして4~26までの偶数が選べる仕様となっております。 必要に応じて、いずれの場合でも動作するよう盤面のサイズを考慮するようにして下さい。
盤面のサイズは下記で取得できます。
size = board.size
それでは、AIの作成例として4角が取れる時は必ず取り、
そうでない時はランダムに打つ、Corner
というAIを実装する例を示します(プレイヤー名は"CORNER"とします)。
import random
from reversi import Reversi
from reversi.strategies import AbstractStrategy
class Corner(AbstractStrategy):
def next_move(self, color, board):
size = board.size
legal_moves = board.get_legal_moves(color)
for corner in [(0, 0), (0, size-1), (size-1, 0), (size-1, size-1)]:
if corner in legal_moves:
return corner
return random.choice(legal_moves)
Reversi({'CORNER': Corner()}).start()
上記を実行すると、対戦プレイヤーに"CORNER"が選択可能となります。
実際に対戦してみると、角が取れる時に必ず取ってくることが分かると思います。
本ライブラリのシミュレータを使うと、AI同士を複数回対戦させて勝率を出すことができます。
自作したAIの強さを測るために活用して下さい。
また、AIの打つ手が特定の盤面に対して固定となる場合は、別途後述のrandom_openingパラメータを設定することで、結果の偏りを減らせます。
シミュレータの実行例として、 これまでに登場した"RANDOM"、"GREEDY"、"CORNER"を総当たりで対戦させ、結果を表示するまでを示します。
下記を実行すると、シミュレーションを開始します。
from reversi import Simulator
if __name__ == '__main__':
simulator = Simulator(
{
'RANDOM': Random(),
'GREEDY': Greedy(),
'CORNER': Corner(),
},
'./simulator_setting.json',
)
simulator.start()
シミュレータは必ずメインモジュール(__main__)内で実行するようにして下さい。
シミュレータの引数には、"プレイヤー情報"と"シミュレータの設定ファイル"を指定して下さい。
シミュレータの設定ファイル(JSON形式)の作成例は下記のとおりです。
Simulatorの第二引数に、本ファイル名(上記例では./simulator_setting.json
ですが任意)を指定して下さい。
{
"board_size": 8,
"matches": 100,
"processes": 1,
"parallel": "player",
"random_opening": 0,
"player_names": [
"RANDOM",
"GREEDY",
"CORNER"
],
"perfect_check": false
}
パラメータ名 | 説明 |
---|---|
board_size | 盤面のサイズを指定して下さい。 |
board_name | 通常とは異なる形状の盤面を使用する場合は、盤面の名前("Diamond"や"Heart"など)を指定して下さい。選べる名前はコンソールアプリケーションの遊び方を参照して下さい。なお、本パラメータ指定時は、盤面サイズは8固定となり、board_size の値は無視されます。 |
matches | AI同士の対戦回数を指定して下さい。100を指定した場合、AIの各組み合わせにつき先手と後手で100試合ずつ対戦する動作となります。 |
processes | 並列実行数を指定して下さい。お使いのPCのコア数に合わせて、設定を大きくするほど、シミュレーション結果が早く得られる場合があります。 |
parallel | 並列実行する単位を指定して下さい。"player"(デフォルト)を指定した場合、AI対戦の組み合わせ毎に並列処理を実施します。また、"game"を指定した場合は、matchesの対戦回数をprocessesの数で分割して並列処理を実施します。シミュレートするAI対戦の組み合わせの数が、お使いのPCのコア数より少ない場合は、"game"を指定することで、より早く結果を得られる場合があります。 |
random_opening | 対戦開始から指定した手数までは、AI同士ランダムな手を打ち試合を進行します。指定された手数を超えるとAIは本来の手を打ちます。対戦開始の状況をランダムに振ることで、結果の偏りを減らしAIの強さを測りやすくします。不要な場合は0を指定して下さい。 |
player_names | 対戦させたいAI名をリストアップして下さい。指定する場合は第一引数の"プレイヤー情報"に含まれるものの中から選択して下さい。省略すると第一引数の"プレイヤー情報"と同一と扱います。リストアップされた全てのAI同士の総当たり戦を行います。 |
perfect_check | 有効にする場合はtrueを指定して下さい。全てのマスが同じ色の石で決着がついた場合に棋譜を残します。結果の棋譜は"./perfect_win.txt"に出力されます。 |
シミュレーション結果はシミュレーション実行後(startメソッド実行後)、下記のようにprint表示で確認できます。
print(simulator)
ライブラリ組み込みのAIを用いたプレイヤー"RANDOM"、"GREEDY"と、 自作のAIによる"CORNER"の、それぞれを対戦させるようシミュレータを実行して、 結果を出力するまでのコード例を下記に示します。
import random
from reversi import Simulator
from reversi.strategies import AbstractStrategy, Random, Greedy
class Corner(AbstractStrategy):
def next_move(self, color, board):
size = board.size
legal_moves = board.get_legal_moves(color)
for corner in [(0, 0), (0, size-1), (size-1, 0), (size-1, size-1)]:
if corner in legal_moves:
return corner
return random.choice(legal_moves)
if __name__ == '__main__':
simulator = Simulator(
{
'RANDOM': Random(),
'GREEDY': Greedy(),
'CORNER': Corner(),
},
'./simulator_setting.json',
)
simulator.start()
print(simulator)
"RANDOM"、"GREEDY"、"CORNER"を総当たりで、先手/後手それぞれ100回ずつ対戦したところ、下記の結果になりました。
Size : 8
| RANDOM GREEDY CORNER
---------------------------------------------------------------------------------------------------------
RANDOM | ------ 32.5% 21.5%
GREEDY | 66.0% ------ 29.5%
CORNER | 76.0% 68.5% ------
---------------------------------------------------------------------------------------------------------
| Total | Win Lose Draw Match
------------------------------------------------------------
RANDOM | 27.0% | 108 284 8 400
GREEDY | 47.8% | 191 202 7 400
CORNER | 72.2% | 289 102 9 400
------------------------------------------------------------
ランダムに打つよりも毎回多めに取る方が、さらにそれよりも角は必ず取る方が、より有利になりそうだという結果が得られました。
次に、ボードの形状を通常の8x8から変更した場合の結果についても見てみます。先ほどのJSONファイルに、以下のとおりboard_name
パラメータを追加しました。
{
"board_size": 8,
"board_name": "x",
"matches": 100,
"processes": 1,
"parallel": "player",
"random_opening": 0,
"player_names": [
"RANDOM",
"GREEDY",
"CORNER"
]
}
AIは変えずに、先ほどと同様に対戦させると、結果は以下のようになりました。
Size : 8
| RANDOM GREEDY CORNER
---------------------------------------------------------------------------------------------------------
RANDOM | ------ 30.0% 39.0%
GREEDY | 66.0% ------ 57.0%
CORNER | 57.5% 41.5% ------
---------------------------------------------------------------------------------------------------------
| Total | Win Lose Draw Match
------------------------------------------------------------
RANDOM | 34.5% | 138 247 15 400
GREEDY | 61.5% | 246 143 11 400
CORNER | 49.5% | 198 192 10 400
------------------------------------------------------------
今回のボードでは、4隅の角を狙うよりも、より多く取れる手を選ぶ方が勝ちやすい、という結果が得られました。
AIに以下のget_result
メソッドを実装することで、シミュレータ実行時に1試合ごとの対戦結果を、AIに渡し何らか処理させることができます。
from reversi.strategies import AbstractStrategy
class OriginalAI(AbstractStrategy):
def next_move(self, color, board):
#
# 次の一手(X, Y)を決めるロジックをコーディングして下さい。
#
return (X, Y)
def get_result(self, result):
#
# 1試合終わるごとにSimulatorからコールされます。
#
# (resultには以下の情報が格納されています)
# result.winlose : 対戦結果(0=黒の勝ち、1=白の勝ち、2=引き分け)
# result.black_name : 黒のAIの名前
# result.white_name : 白のAIの名前
# result.black_num : 黒の石の数
# result.white_num : 白の石の数
#
本ライブラリに用意されている各種オブジェクトについて説明します。
ここでは、リバーシの盤面を管理するboard
オブジェクトの使い方について説明します。
board
オブジェクトはreversiより、Board
クラスをインポートすることで、生成できるようになります。
Board
クラスをインスタンス化する際の引数に、数値を入れることで盤面のサイズを指定できます。
サイズは4~26までの偶数として下さい。省略時は8となります。
また、size
プロパティにて盤面のサイズを確認することができます。
コーディング例は下記のとおりです。
from reversi import Board
board = Board()
print(board.size)
board = Board(10)
print(board.size)
上記の実行結果は下記となります。
8
10
board
オブジェクトをprint
すると盤面の状態が標準出力されます。
from reversi import Board
board = Board()
print(board)
board = Board(4)
print(board)
board
オブジェクトの使用可能なメソッドを紹介します。
黒番または白番での着手可能な位置を返します。
着手可能な位置は"XY座標のタプルのリスト"となります。
引数にはblack
(黒番)またはwhite
(白番)の文字列(以後color
と呼びます)を指定して下さい。
from reversi import Board
board = Board()
legal_moves = board.get_legal_moves('black')
print(legal_moves)
上記の実行結果は下記となります。
[(3, 2), (2, 3), (5, 4), (4, 5)]
この場合、下図の黄色のマスの位置が、着手可能な位置として返されます。
指定位置に着手した場合の、ひっくり返せる石を返します。
ひっくり返せる石は"XY座標のタプルのリスト"となります。
第一引数にcolor
、第二引数に石を置くX座標、第三引数にY座標を指定して下さい。
from reversi import Board
board = Board()
flippable_discs = board.get_flippable_discs('black', 5, 4)
print(flippable_discs)
上記の実行結果は下記となります。
[(4, 4)]
この場合、下図の黄色のマスの位置が、ひっくり返せる石の位置として返されます。
盤面に置かれた石の状態を"2次元リスト"で返します。 "1"が黒、"-1"が白、"0"が空きを表します。引数はありません。
from pprint import pprint
from reversi import Board
board = Board()
board_info = board.get_board_info()
print(board)
pprint(board_info)
盤面の情報を1行の文字列で返します。
from pprint import pprint
from reversi import Board
board = Board()
print(board.get_board_line_info('black'))
上記の表示結果は以下です。
---------------------------O*------*O---------------------------*
盤面のマス目情報 + プレイヤー情報の形式となっています。
引数にはプレイヤーを示す文字列('black'または'white')を指定して下さい。
デフォルトの文字の割り当ては以下の通りです
- "*" : 黒プレイヤー
- "O" : 白プレイヤー
- "-" : 空きマス
オプション引数の指定で、お好みの文字に変更可能です。
print(board.get_board_line_info(player='black', black='0', white='1', empty='.'))
上記実行時は、以下の出力になります。
...........................10......01...........................0
- player : 'black'(黒)か'white'(白)を指定して下さい。
- black : 黒に割り当てる文字を指定して下さい
- white : 白に割り当てる文字を指定して下さい
- empty : 空きマスに割り当てる文字を指定して下さい
指定位置に石を配置し、取れる石をひっくり返します。
第一引数にcolor
、第二引数に石を置くX座標、第三引数にY座標を指定して下さい。
from reversi import Board
board = Board()
print(board)
board.put_disc('black', 5, 4)
print(board)
put_disc
メソッドで置いた石を元に戻します。引数はありません。
put_disc
メソッドを呼び出した回数だけ、元に戻すことができます。
put_disc
メソッドを呼び出した回数を超えて、本メソッドを呼び出さないで下さい。
from reversi import Board
board = Board()
board.put_disc('black', 5, 4)
print(board)
board.undo()
print(board)
put_disc
同様に、指定位置に石を配置し、取れる石をひっくり返します(ただし、引数が異なります)。
第一引数にcolor
、第二引数に石を置くX座標とY座標のタプルまたは、後述のMove
オブジェクトを指定して下さい。
from reversi import Board
board = Board()
board.move('black', (5, 4))
これまでは、黒番や白番の手番の判別に'black'や'white'の文字列を使う方法を示しましたが
color
オブジェクトを用いて指定することも可能です。
以下のようにcolor
オブジェクトであるC
をインポートして、
blackプロパティやwhiteプロパティにてそれぞれ黒番、白番を指定できます。
from reversi import Board
from reversi import C as c
board = Board()
board.put_disc(c.black, 5, 4)
print(board)
board.put_disc(c.white, 5, 5)
print(board)
move
オブジェクトを使うと、手を打つ座標の指定に、これまでのXY座標形式だけではなく、'a1'・'c3'などのstr形式が使えるようになります。
str形式のアルファベットは大文字・小文字どちらでもOKです。
Move
クラスをインポートして、下記のように使用して下さい。
from reversi import Board
from reversi import C as c
from reversi import Move as m
board = Board()
board.put_disc(c.black, *m('f5'))
print(board)
board.move(c.white, m('f6'))
print(board)
また、move
オブジェクトはXY座標形式でも生成でき、str関数を使ってstr形式へ変換できます。
move
オブジェクトをprint表示した場合も同様にstr形式となります。
caseオプションにupper
を指定すると大文字表記になります。
from reversi import Board
from reversi import Move as m
move = str(m(5, 4))
print(move)
print(m(5, 5, case='upper'))
上記の実行結果は下記となります。
f5
F6
player
オブジェクトは、リバーシのゲームAIをプレイヤーとして対戦に参加させるためのオブジェクトです。
player
オブジェクトはcolor
(手番)とname
(名前)、strategy
(戦略)をそれぞれ引数に指定して作成します。strategy
に指定できるAIの戦略は以降のAIクラス編で詳しくご紹介します。
以下はplayer
オブジェクトの黒番と白番のプレイヤーを準備する例です。AIの戦略はランダムに打ち手を選ぶものとしています。
from reversi import Board, Player
from reversi.strategies import Random
from reversi import C as c
black = Player(c.black, 'BLACK', Random())
white = Player(c.white, 'White', Random())
引数 | 内容 |
---|---|
color | プレイヤーの手番を指定して下さい |
name | 文字列でプレイヤーの名前をお好きに決めて下さい |
strategy | プレイヤーの戦略(AIの頭脳)を指定して下さい |
続いて、実際にAI同士が対戦するためのgame
オブジェクトについて説明します。
game
オブジェクトを使うと、指定したプレイヤー同士をリバーシのルールに基づいて決着まで対戦させることができます。先述のシミュレータとは異なり、個別の対戦を自由にプログラミングしたい場合などに活用できます。
game
オブジェクトの作成には、黒プレイヤーオブジェクトと白プレイヤーオブジェクト、ボードオブジェクト(省略可能)を指定します。play
メソッドを呼ぶと対戦を始めます。
以下に、4x4の盤面にてランダムな打ち手同士で対戦をさせ、結果を表示する例です。
from reversi import Board, Player, Game
from reversi.strategies import Random
from reversi import C as c
black = Player(c.black, 'BLACK', Random())
white = Player(c.white, 'White', Random())
board4 = Board(4)
print(board4)
game = Game(black, white, board4)
game.play()
print(board4)
print(game.result.winlose)
print(game.result.black_name, game.result.black_num)
print(game.result.white_name, game.result.white_num)
引数 | 内容 |
---|---|
black_player | 黒プレイヤーを指定して下さい |
white_player | 白プレイヤーを指定して下さい |
board | 対戦させるボードを指定して下さい(省略可能) |
color | color=c.white とオプション引数指定すると、白番から開始可能です(省略可能) |
対戦結果は、game
オブジェクトのresult
プロパティに格納されています。内容は以下の通りです。
プロパティ名 | 内容 |
---|---|
winlose | 勝敗(0:黒の勝ち、1:白の勝ち、2:引き分け) |
black_name | 黒プレイヤーの名前 |
white_name | 白プレイヤーの名前 |
black_num | 黒プレイヤーの石数 |
white_num | 白プレイヤーの石数 |
recorder
オブジェクトを使うと、board
オブジェクトの打ち手の情報から、棋譜情報を取得することができます。
以下はランダム対戦を実施し、その時の棋譜を出力する例です。
from reversi import Board, Player, Game, Recorder
from reversi.strategies import Random
from reversi import C as c
black = Player(c.black, 'BLACK', Random())
white = Player(c.white, 'White', Random())
board4 = Board(4)
game = Game(black, white, board4)
game.play()
recorder = Recorder(board4)
print(recorder)
(実行結果)
D3d4B1a1A2d2C4a3B4a4d1c1
先手の黒手番の場合はアルファベット大文字、白手番は小文字としております。
また、play
メソッドを使うと棋譜通りの進行を1手ずつテキストで表示します。
recorder.play()
※表示が長いため、途中で省略しております
本ライブラリに用意されている各種AIクラスについて説明します。
取れる石が最も少ない手を選びます。
(使用例)
from reversi import Reversi
from reversi.strategies import Unselfish
Reversi({"UNSELFISH": Unselfish()}).start()
毎回ランダムな手を選びます。
(使用例)
from reversi import Reversi
from reversi.strategies import Random
Reversi({"RANDOM": Random()}).start()
取れる石が最も多い手を選びます。
(使用例)
from reversi import Reversi
from reversi.strategies import Greedy
Reversi({"GREEDY": Greedy()}).start()
序盤(盤面に置かれている石が15%未満の場合)は、取れる石が最も少ない手を選び、
以降は取れる石が最も多い手を選びます。
(使用例)
from reversi import Reversi
from reversi.strategies import SlowStarter
Reversi({"SLOWSTARTER": SlowStarter()}).start()
盤面のマス目の位置に重み(重要度)を設定して、
その重みを元に盤面を評価し、スコアが最も高くなる手を選びます。
マス目の重みは使用例の通り、パラメータにて自由に設定が可能です。
ただし、パラメータの値には実数値ではなく整数値(負の値も可)を設定して下さい。
(使用例)
from reversi import Reversi
from reversi.strategies import Table
Reversi(
{
'TABLE': Table(
corner=100,
c=30,
a1=50,
a2=50,
b1=50,
b2=50,
b3=50,
x=-25,
o1=45,
o2=45,
),
}
).start()
(パラメータ)
各パラメータに対応するマス目の位置は下図のとおりです。
リバーシでは角を取ると有利になりやすく、Xを取ると不利になりやすいと言われています。
そこで、corner
パラメータを大きくして角を狙い、x
パラメータを小さくしてXを避ける、といった調整が可能です。
モンテカルロ法で手を選びます。
打てる手の候補それぞれについて、ゲーム終了までランダムに打つ事を複数回繰り返し
最も勝率が良かった手を選びます。(持ち時間は1手0.5秒)
ゲーム終了までランダムに打つ回数と、モンテカルロ法を開始する残り手数をパラメータで指定可能です。
(使用例)
from reversi import Reversi
from reversi.strategies import MonteCarlo
Reversi(
{
'MONTECARLO': MonteCarlo(
count=100, # ランダムにゲーム終了まで打つ回数(デフォルト:100)
remain=60, # モンテカルロ法を開始する残り手数(デフォルト:60)
),
}
).start()
盤面の形勢を判断する評価関数を元に、相手も自分同様に最善を尽くすと仮定して、数手先の盤面を読み
その中で評価が最も良くなる手を選びます。
評価関数のカスタマイズ方法はこちらを参照して下さい。
MinMax法で手を選びます。読む手数を大きくしすぎると処理が終わらない場合がありますのでご注意下さい。
(使用例)
from reversi import Reversi
from reversi.strategies import MinMax
from reversi.strategies.coordinator import Evaluator
Reversi(
{
'MINMAX': MinMax(
depth=2, # 何手先まで読むかを指定
evaluator=Evaluator(), # 評価関数を指定(カスタマイズ方法は後述)
),
}
).start()
NegaMax法で手を選びます。MinMax法と性能は同じです。
一手0.5秒の持ち時間の中で手を読みます。
(使用例)
from reversi import Reversi
from reversi.strategies import NegaMax
from reversi.strategies.coordinator import Evaluator
Reversi(
{
'NEGAMAX': NegaMax(
depth=2, # 何手先まで読むかを指定
evaluator=Evaluator(), # 評価関数を指定(カスタマイズ方法は後述)
),
}
).start()
※持ち時間制限を外したい場合は、NegaMax
クラスの代わりに_NegaMax
クラスを使用して下さい。
AlphaBeta法で手を選びます。不要な手(悪手)の読みを枝刈りする(打ち切る)ことでMinMax法より効率よく手を読みます。
一手0.5秒の持ち時間の中で手を読みます。
(使用例)
from reversi import Reversi
from reversi.strategies import AlphaBeta
from reversi.strategies.coordinator import Evaluator
Reversi(
{
'ALPHABETA': AlphaBeta(
depth=2, # 何手先まで読むかを指定
evaluator=Evaluator(), # 評価関数を指定(カスタマイズ方法は後述)
),
}
).start()
※持ち時間制限を外したい場合は、AlphaBeta
クラスの代わりに_AlphaBeta
クラスを使用して下さい。
NegaScout法で手を選びます。AlphaBeta法の枝刈りに加えて自身の着手可能数がより多くなる手を優先的に読むよう設定しています。
一手0.5秒の持ち時間の中で手を読みます。
(使用例)
from reversi import Reversi
from reversi.strategies import NegaScout
from reversi.strategies.coordinator import Evaluator
Reversi(
{
'NEGASCOUT': NegaScout(
depth=2, # 何手先まで読むかを指定
evaluator=Evaluator(), # 評価関数を指定(カスタマイズ方法は後述)
),
}
).start()
※持ち時間制限を外したい場合は、NegaScout
クラスの代わりに_NegaScout
クラスを使用して下さい。
評価関数のカスタマイズにはEvaluatorクラスを使用します。
引数にはseparatedとcombined(それぞれリスト)が指定できます。
各パラメータの要素には盤面のスコアを算出するScorerクラスのオブジェクトを指定する必要があります。
引数 | 説明 |
---|---|
separated | Scorerのスコア算出結果が存在する場合はその結果を評価値とします。リストの先頭の方にあるほど優先度が高くなります。 |
combined | リストのすべてのScorerのスコア算出結果の和を評価値とします。 |
使用可能なScorerクラスは以下になります。
Scorerクラス | 説明 | パラメータ |
---|---|---|
TableScorer | 盤面の位置に応じた重みづけでスコアを算出します。 |
size=盤面のサイズ corner, c, a1, a2, b1, b2, b3, x, o1, o2=マス目の位置に応じて手を選ぶAIと同じ デフォルト:size=8, corner=50, c=-20, a1=0, a2=-1, b1=-1, b2=-1, b3=-1, x=-25, o1=-5, o2=-5 |
PossibilityScorer | 着手可能数に基づいてスコアを算出します。 | w=(自分の着手可能数 - 相手の着手可能数)の重み デフォルト:5 |
WinLoseScorer | 勝敗に基づいてスコアを算出します。勝敗が決まっていない場合はスコアなしとします。 | w=自分が勝ちの場合のスコア デフォルト:10000 |
NumberScorer | 石差(自分の石数 - 相手の石数)をスコアとして算出します。 | パラメータなし |
EdgeScorer | 辺の確定石の数に基づいてスコアを算出します。下図の4隅から8方向を探索し、同じ石が連続する数に応じてスコアを決定します。相手のスコアは合計値からマイナスされます。 |
w=確定石一つあたりの重み デフォルト:100 |
BlankScorer | 石が空きマスに接するパターンに基づいてスコアを算出します。算出するスコアは以下の3種類。 1. 置かれた石の周囲8方向の空きマスに接する数 2. 空いた隅に接するX打ち 3. 空いた隅に接するC打ち時の辺の空きマスの数 ※上記3種類ともに相手のスコアはマイナスします。 |
w1=左記1 w2=左記2 w3=左記3 デフォルト:w1から順に-1、-4、-2 |
(使用例)
以下に、評価関数をカスタマイズする例を示します。
- 勝ちが見える手は優先的に選ぶ
- 勝敗が確定していない場合は以下の指標をすべて加味して手を選ぶ
- マス目の位置に応じた重みで形勢を判断し、評価値が大きくなるよう手を選ぶ
- 自身の着手可能数が相手よりも多くなるように手を選ぶ
from reversi import Reversi
from reversi.strategies import AlphaBeta
from reversi.strategies.coordinator import Evaluator, TableScorer, PossibilityScorer, WinLoseScorer
Reversi(
{
'CUSTOMIZED': AlphaBeta(
depth=4,
evaluator=Evaluator(
separated=[
WinLoseScorer(
w=10000,
),
],
combined=[
TableScorer(
corner=50,
c=-20,
a1=0,
a2=-1,
b1=-1,
b2=-1,
b3=-1,
x=-25,
o1=-5,
o2=-5,
),
PossibilityScorer(
w=5,
),
],
),
),
}
).start()
Evaluatorクラスを自作することで、より自由度の高い評価関数を用意することもできます。
以下に、評価関数を自作したAIを作るためのひな形を示します。
(前提)
- 探索方法にはAlphaBeta法を用いる(数手先の盤面を読んで手を選ぶAIならいずれでも可)
- 6手先まで読み、探索時間の制限はなしとする
- 評価関数には自作した
MyEvaluator
を用いる - 評価関数のスコアは高いほど、自身の形勢が良いことを示し、もっともスコアの高い手が選ばれる
(処理内容)
- 初期盤面を表示する
- 自作したAIに、黒の手番での次の一手を求めさせ、盤面に打つ
- 盤面を表示する
from reversi import Board
from reversi import C as c
from reversi.strategies.common import AbstractEvaluator
from reversi.strategies import _AlphaBeta
class MyEvaluator(AbstractEvaluator):
def evaluate(self, color, board, possibility_b, possibility_w):
score = 0
#
# 現在の盤面のスコア(評価値)を算出するロジックをコーディングして下さい。
#
return score
my_ai = _AlphaBeta(depth=6, evaluator=MyEvaluator())
board = Board()
print(board)
x, y = my_ai.next_move(c.black, board)
board.put_disc(c.black, x, y)
print(board)
なお、Evaluatorクラスのevaluate関数の引数には以下が渡されます。
必要に応じて使用して下さい。
引数 | 説明 |
---|---|
color 変数 |
black かwhite のstr 型の文字列が渡され、それぞれ黒番か白番かを判別することができます。 |
board オブジェクト |
リバーシの盤面情報を持ったオブジェクトが渡されます。黒と白の石の配置情報のほか、石が置ける位置の取得などゲームを進行するために必要となる、パラメータやメソッドを持っています。 |
possibilitiy_b 変数 |
黒番の着手可能数が格納されています。 |
possibilitiy_w 変数 |
白番の着手可能数が格納されています。 |
Joseki
クラスを活用すると、AIに序盤は定石どおりに手を選ばせることができます。
以下に、自作したAIに定石打ちを追加する例を示します。
(前提)
- 自作したAI(
MyAI
)に兎進行の定石打ちを追加する
import random
from reversi import Board
from reversi import C as c
from reversi.strategies import AbstractStrategy, Usagi
class MyAI(AbstractStrategy):
"""自作AI(ランダムに打つ)"""
def next_move(self, color, board):
legal_moves = board.get_legal_moves(color)
return random.choice(legal_moves)
my_ai = Usagi(base=MyAI()) # base引数に自作AIを与える
board = Board()
print(board)
for color in [c.black, c.white, c.black]: # 3手進める
x, y = my_ai.next_move(color, board)
board.put_disc(color, x, y)
print(board)
使用可能なJoseki
クラスの一覧は以下になります。
Josekiクラス | 説明 |
---|---|
Usagi | 兎進行を選びます。 |
Tora | 虎進行を選びます。 |
Ushi | 牛進行を選びます。 |
Nezumi | 鼠進行を選びます。 |
Neko | 猫進行を選びます。 |
Hitsuji | 羊進行を選びます。 |
上記いずれにも同じ定石が搭載されており、それぞれの進行を外れても打てる定石に差異はありません。
Switch
クラスを活用すると、現在の手数に応じて、AIを切り替えることができます。
以下に、使い方の例を示します。
(前提)
- 盤面のサイズは8x8
- 1~30手目までは
Random
- 31~50手目までは
Table
- 51~60手目までは
MonteCarlo
from reversi import Reversi
from reversi.strategies import Random, Table, MonteCarlo, Switch
Reversi(
{
'SWITCH': Switch( # 戦略切り替え
turns=[
29, # 1~30手目まではRandom (30手目-1を設定)
49, # 21~50手目まではTable (50手目-1を設定)
60 # それ以降(残り10手)からはMobteCarlo (最後は60を設定)
],
strategies=[
Random(), # Random AI
Table(), # Table AI
MonteCarlo(), # MonteCarlo AI
],
),
}
).start()
上記の例のように、序盤は適当に打ちハンデを与え、
中盤以降から徐々に強くするといった、ゲーム性を調整する場合や
序盤、中盤、終盤それぞれで最適な戦略を切り替えて、
より強いAIを作成する場合などにも活用することができます。
完全読みとは、互いに最善を尽くす前提でゲーム終了まで打ち
最終の石数の差が、より自身にとって多くなる手を選ぶという方法です。
決着まで読み切るため、手数によっては大きく時間がかかる場合もありますが、
手を読んだ時点で勝てる手が残っていれば、必ず相手に勝つことができます。
探索手法にAlphaBeta法を用いて完全読みを行います。
処理時間の目安として、残り14手以下の盤面の手を概ね0.5秒以内に読みます。
ただしこれは努力目標であり、盤面によっては著しく時間がかかる場合がございます。
EndGame
クラスは制限時間あり、_EndGame
クラスは制限時間なしとなります。
以下に、自作したAIに終盤の完全読みを追加する例を示します。
(前提)
- 盤面のサイズは8x8
- 残り10手から完全読みを開始する
(使用例)
import random
from reversi import Reversi
from reversi.strategies import AbstractStrategy, Switch, _EndGame
class MyAI(AbstractStrategy):
"""自作AI(ランダムに打つ)"""
def next_move(self, color, board):
legal_moves = board.get_legal_moves(color)
return random.choice(legal_moves)
Reversi(
{
'ENDGAME': Switch( # 戦略切り替え
turns=[
49, # 残り11(= 60 - 49)手まではMyAI()
60 # それ以降(残り10手)からは完全読み
],
strategies=[
MyAI(), # 自作AI
_EndGame(), # 完全読み(制限時間なし)
],
),
}
).start()
コンソール上で動くもの限定となりますが、外部のAIを対戦相手として追加する事も可能です。ここではいくつかのサンプルを示しますので、参考にして下さい。
以下のコードを元に、強豪リバーシAIのEdaxを対戦相手として追加することが可能です。
詳細は、Eadxの追加方法をご参照下さい。
import subprocess
from reversi import strategies
from reversi.strategies import AbstractStrategy
from reversi.move import Move as m
class Edax(AbstractStrategy):
def next_move(self, color, board):
if board.size != 8:
return strategies.Random.get_next_move(color, board)
with open('./board.txt', 'w') as f:
f.write(board.get_board_line_info(color))
if board._black_score + board._white_score < 56:
cmd = "./edax-4.4 -solve ./board.txt -l 8 -book-usage off -cpu"
else:
cmd = "./edax-4.4 -solve ./board.txt -cpu"
output_str = subprocess.run(cmd, capture_output=True, text=True).stdout
move = output_str.split('\n')[2][57:].split()[0]
return m(move)
以下のコードを元に、強豪リバーシAIのEgaroucidを対戦相手として追加可能です。
詳細は、Egaroucidの追加方法をご参照下さい。
import subprocess
from reversi import strategies
from reversi.strategies import AbstractStrategy
from reversi.move import Move as m
class Egaroucid(AbstractStrategy):
def next_move(self, color, board):
if board.size != 8:
return strategies.Random.get_next_move(color, board)
with open('./board.txt', 'w') as f:
f.write(board.get_board_line_info(color))
if board._black_score + board._white_score < 56:
cmd = "./Egaroucid_for_Console.exe -solve ./board.txt -l 8 -nobook -t 1"
else:
cmd = "./Egaroucid_for_Console.exe -solve ./board.txt -t 1"
output_str = subprocess.run(cmd, capture_output=True, text=True).stdout
move = output_str.split('\n')[1][46:46+2]
return m(move)
AIクラスに特定のメソッドを追加する事で、シミュレータの実施やアプリケーションでの対戦など、毎ゲームの開始と終了のタイミングで任意の処理を実行することが可能となります。
以下のように、AIクラスのプログラミング時にsetup
とteardown
メソッドを追加して下さい。
setup
メソッドには対戦開始前に実施したい処理を書いて下さい。引数のboard
オブジェクトが参照可能です。また、teardown
メソッドには対戦終了後に実施したい処理を書いて下さい。引数のboard
オブジェクトと、対戦結果のresult
オブジェクトが参照可能です。不要な場合はいずれのメソッドも省略可能です。
from reversi.strategies import AbstractStrategy
class MyAI(AbstractStrategy):
def setup(self, board):
# 対戦開始前の処理を書いて下さい。
# - 引数からboardオブジェクトのみ参照できます。
def teardown(self, board, result):
# 対戦終了後の処理を書いて下さい。
# - 引数からboardオブジェクトと、対戦結果のresultオブジェクトを参照できます。
# (resultには以下の情報が格納されています)
# result.winlose : 対戦結果(0=黒の勝ち、1=白の勝ち、2=引き分け)
# result.black_name : 黒のAIの名前
# result.white_name : 白のAIの名前
# result.black_num : 黒の石の数
# result.white_num : 白の石の数
def next_move(self, color, board):
#
# 次の一手(X, Y)を決めるロジックをコーディングして下さい。
#
return (X, Y)
盤面のサイズや対戦プレイヤーをいろいろ選べるリバーシです。
難易度の異なる多種多様なAIがお相手いたします。
おまけ要素として、お好きなプログラミング言語で作ったAIをゲームに追加して遊べる機能もございます。
tkinterアプリケーションで遊ぶには、以下の2通りの方法がございます。
- サンプルをコピーする(本ライブラリのインストールが必要)
- Windows版のアプリケーションをダウンロードする(インストール不要)
Windows版のアプリケーションで遊ぶ場合は下記リンクをクリックし、
"reversi.zip"をダウンロードして下さい(無料)。
- reversi.zip (Release Test20)
"reversi.zip"を解凍後、reversi.exeをダブルクリックするとアプリケーションで遊ぶ事ができます。
選択可能なメニューの一覧です。
名前 | 内容 |
---|---|
Size | 盤面のサイズ(4~26までの偶数)を選択します。 |
Black | 黒(先手)のプレイヤーを選択します。 |
White | 白(後手)のプレイヤーを選択します。 |
Cputime | CPUの持ち時間を設定します。デフォルトは0.5秒となっております。 |
Extra | 外部プログラムのAIを追加します。Cputimeの持ち時間の設定は適用されません。 |
Assist | 打てる手の候補をハイライト表示するかどうか選びます。 |
Language | 言語設定(English or 日本語)を選びます。 |
Cancel | ゲームを中断します。 |
選択可能なプレイヤーの一覧です。
難易度は8x8サイズの場合の目安となっております。
名前 | 特徴 | 難易度 |
---|---|---|
User1, User2 | 人が操作します。 | ? |
Unselfish | なるべく少なく取ろうとします。 | ★ |
Random | ランダムに手を選びます。 | ★ |
Greedy | なるべく多く取ろうとします。 | ★ |
SlowStarter | 序盤はUnselfish、それ以降はGreedyになります。 | ★ |
Table | マス目の位置に重みをつけたテーブルで盤面を評価し、自身の形勢が良くなるよう手を選びます。なるべく少なく取り、角を狙い、角のそばは避けるよう心掛けます。 | ★★ |
MonteCarlo | モンテカルロ法で手を選びます。持ち時間の限り、すべての手の候補についてゲーム終了までランダムな手を打ちあうプレイアウトを繰り返し、最も勝率が高かった手を選びます。 | ★★ |
MinMax | ミニマックス法で2手先を読んで手を選びます。Tableの盤面評価に加えて、着手可能数と勝敗を考慮します。自身の置ける場所は増やし、相手の置ける場所は減らし、勝ちが見えた手を優先するよう手を読みます。 | ★★ |
NegaMax | MinMaxの探索手法をネガマックス法に替えて、持ち時間の限り3手先を読んで手を選びます。手を読む探索効率はミニマックス法と同じです。 | ★★★ |
AlphaBeta | NegaMaxの探索手法をアルファベータ法(ネガアルファ法)に替えて、持ち時間の限り4手先を読んで手を選びます。αβ値の枝刈りにより、ネガマックス法より効率良く手を読みます。 | ★★★ |
Joseki | AlphaBetaに加えて、序盤は定石通りに手を選びます。 | ★★★ |
FullReading | Josekiに加えて、終盤残り9手からは最終局面までの石差を読んで手を選びます。 | ★★★ |
Iterative | FullReadingに反復深化法を適用して持ち時間の限り徐々に深く手を読みます。読む手の深さを増やす際は前回の深さで最も評価が高かった手を最初に調べます。それにより、不要な探索を枝刈りしやすくし、4手よりも深く手を読む場合があります。 | ★★★★ |
Edge | Iterativeの盤面評価に加えて、4辺のパターンを考慮し確定石を増やすよう手を選びます。 | ★★★★ |
Switch | Edgeの各パラメータを遺伝的アルゴリズムを使って強化し、手数に応じて5段階にパラメータを切り替えることで、よりゲームの進行に応じた手を選びます。また、探索手法をアルファベータ法からネガスカウト法に変更し、自身の着手可能数が相手より多くなる手を優先的に探索するよう候補を並び替え、探索効率を上げています。加えて終盤残り10手から石差を読みます。 | ★★★★ |
Blank8_16 | Edgeのパラメータに加え、自身の石がなるべく空きマスに接しないよう考慮して手を選びます。制限時間を考慮せず必ず毎回8手先を読みます。加えて終盤残り16手(制限時間なし)から石差を読みます。 | ★★★★★ |
BlankI_16 | Blank8_16と同じ評価関数で手を読みますが、こちらは制限時間0.5s以内で見つけた最善手を選びます。加えて終盤残り16手(制限時間なし)から石差を読みます。 | ★★★★★ |
本アプリケーションはお好きなプログラミング言語で作成したAI(追加プレイヤー)を
ゲームに参加させて遊ぶことができます。
また、あらかじめ用意された追加プレイヤーについても動作環境を準備する事で遊ぶ事ができます。
なお、追加プレイヤーのプログラムを作成する際は入出力を後述のフォーマットに準拠させて下さい。
あらかじめ用意された追加プレイヤーの一覧です。
動作環境を準備し、Extraメニューより登録ファイルを読み込ませると遊べるようになります。
名前 | 特徴 | 難易度 | 登録ファイル | 開発言語 | 動作確認環境 |
---|---|---|---|---|---|
TopLeft | 打てる手の中から一番上の左端を選びます。 | ★ | topleft.json | Python | Windows10 64bit Python 3.7.6 |
BottomRight | 打てる手の中から一番下の右端を選びます。 | ★ | bottomright.json | Perl | Windows10 64bit Strawberry Perl 5.30.1.1 |
RandomCorner | 角が取れる時は必ず取ります。それ以外はランダムに手を選びます。 | ★ | randomcorner.json | VBScript | Windows10 64bit |
プレイヤーを自作して遊ぶには、下記の手順でプレイヤーの作成と登録を行って下さい。
追加プレイヤーをアプリケーションに登録すると外部プログラムとして実行されるようになります。
以下に処理の流れを示します。
-
ゲーム開始後、追加プレイヤーの手番になるとアプリケーションは対応するプログラムのコマンドを実行します。
その際、標準入力に盤面情報を渡し、追加プレイヤーのプログラムの応答を待ちます。 -
追加プレイヤーは標準入力から盤面情報を受け取り、次の手を決め、その結果を標準出力します。
(そのようなプログラムを書いて下さい) -
アプリケーションは追加プレイヤーの標準出力(次の手)を受け取るとゲームを再開します。
一定時間応答がない場合は追加プレイヤーのプログラムを強制終了し、反則負けとして扱います。
追加プレイヤーが受け取る標準入力の盤面の情報です。
手番の色(黒:1、白:-1)
盤面のサイズ(4~26までの偶数)
盤面の石の2次元配置(空き:0、黒:1、白:-1をスペース区切り)
-1
8
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 1 1 1 0 0
0 0 0 -1 1 0 0 0
0 0 -1 -1 1 -1 0 0
0 0 0 0 1 -1 0 0
0 0 0 0 1 -1 0 0
0 0 0 0 0 0 0 0
追加プレイヤーが標準出力する次の手の情報です。
盤面の座標(左上を起点(0,0)としてxとyをスペース区切り)
2 4
追加プレイヤーをアプリケーションに登録するために本ファイルを作成する必要があります。
登録ファイルは下記のフォーマット(JSON形式)に従ってextra/
以下に作成して下さい。
作成後、Extraメニューより読み込む事でプレイヤーが追加されます。
{
"name": "追加プレイヤーの名前",
"cmd": "追加プレイヤー実行用のコマンド",
"timeouttime": 追加プレイヤーからの応答待ち時間(秒) ※起動に時間がかかる場合があるため、余裕を持った設定を推奨します
}
下記に、Windows10上のPythonで動作するTopLeft(あらかじめ用意されたプレイヤー)の例を示します。
{
"name": "TopLeft",
"cmd": "py -3.7 ./extra/python/topleft/topleft.py",
"timeouttime": 60
}
コマンドプロンプト(Windowsの場合)のようなコンソール上で遊べるリバーシです。
通常と異なる多種多様な20種類以上にも及ぶ盤面で遊ぶ事ができます。
サンプルをインストールすると遊べます。
アプリケーションを起動すると、以下の画面が表示されます。
メニューの項目 | 内容 |
---|---|
BoardType | 現在選択中のボードの種類 |
BlackPlayer | 現在選択中の黒のプレイヤー名 |
WhitePlayer | 現在選択中の白のプレイヤー名 |
キー入力により、設定変更やゲームの開始および終了を行えます。
キー入力 | 内容 |
---|---|
enter | Enterキー入力でゲームを開始します。 |
t + enter | ボードの種類を変更します。 |
b + enter | 黒のプレイヤーを変更します。 |
w + enter | 白のプレイヤーを変更します。 |
q + enter | ゲームを終了します。 |
ctrl + c | Ctrl+cでゲームを強制終了します。(ゲーム途中で終了する場合) |
ボードの種類に対応する番号を入力すると、ボードを変更できます。
黒と白ともにプレイヤー名に対応する番号を入力すると、プレイヤー(AI)を変更できます。
キー入力 | 名前 | 難易度 | 特徴 |
---|---|---|---|
1 + enter | User1, User2 | 人が操作 | - |
2 + enter | X | ★ | ランダム |
3 + enter | M-10 | ★★ | モンテカルロ10回 |
4 + enter | M-100 | ★★★ | モンテカルロ100回 |
5 + enter | M-1000 | ★★★★ | モンテカルロ1000回 |
6 + enter | TheEnd | ★★★★★ | モンテカルロ10000回 + 終盤14手完全読み |
ゲーム開始後、打てる手(座標)に対応する番号(+ enter)を入力すると、手を打つことができます。
reversiのインストールがうまくいかない場合は 下記の手順(1~5)に従って環境を準備して下さい。
下記よりPythonの64bit版インストーラのexeをダウンロード後、インストールして下さい。
Python 3.7.6
インストール後、コマンドプロンプトを立ち上げて下記の'$'以降を入力してEnterを押し、同じ結果が出ればOKです。
$ python --version
Python 3.7.6
reversiをPythonから実行するためにはいくつかの外部パッケージが必要となります。
正しくインストールできるようにするために下記を実行してpipをアップデートして下さい。
$ pip install --upgrade pip
:
Successfully installed pip-20.0.2
※バージョンが異なる場合は上位であれば問題ないはずです
reversiの実行に必要なPythonのパッケージのインストールは下記で一括して行えます。
事前にコマンドプロンプトにてreversiフォルダ以下に移動しておいて下さい。
$ pip install -r requirements.txt
もしうまくいかない場合は、以降の"(パッケージインストールの補足)"を個別に実行して下さい。
reversiの実行にはC言語のコンパイル環境が必要となります。
下記よりVisual C++をダウンロードして下さい。
Microsoft Visual C++ 2019
サンプルを参照して、サンプルが動作するか確認して下さい。
reversiを実行するためにはcythonという外部パッケージが必要となります。
下記を実行してインストールして下さい。
$ pip install cython
:
Successfully installed cython-0.29.15
reversiのexeを生成するためにはpyinstallerという外部パッケージが必要となります。
下記を実行してインストールして下さい。不要な場合は省略しても構いません。
$ pip install pyinstaller
:
Successfully installed altgraph-0.17 future-0.18.2 pefile-2019.4.18 pyinstaller-3.6 pywin32-ctypes-0.2.0
うまくいかない場合は下記を実行後に、再度上記を試してみて下さい。
$ pip install wheel
インストール完了後、pyinstallerを実行できるようにするために環境変数に下記を追加して下さい。
C:\Users\{あなたのユーザ名}\AppData\Local\Programs\Python\Python37\Scripts
- 「実践Python3」 Mark Summerfield著 斎藤 康毅訳 株式会社オライリー・ジャパン ISBN978-4-87311-739-3
- 「Java言語で学ぶデザインパターン入門」 結城 浩著 ソフトバンククリエイティブ株式会社 ISBN4-7973-2703-0
- 「日経ソフトウェア2019年11月号」 日経BP ISSN1347-4685
- 「Python計算機科学新教本」 David Kopec著 黒川 利明訳 株式会社オライリー・ジャパン ISBN978-4-87311-881-9
- 「Cython Cとの融合によるPythonの高速化」 Krurt W. Smith著 中田 秀基監訳 長尾 高弘訳 株式会社オライリー・ジャパン ISBN978-4-87311-727-0
- 「Fluent Python ----Pythonicな思考とコーディング手法」 Luciano Ramalho著 豊沢 聡、桑井 博之監訳 梶原 玲子訳 株式会社オライリー・ジャパン ISBN978-4-87311-817-8
- 「オセロ・リバーシプログラミング講座 ~勝ち方・考え方~」https://uguisu.skr.jp/othello/
- 「オセロ・リバーシの勝ち方、必勝法」https://bassy84.net/
- 「強いオセロプログラムの内部動作」http://www.amy.hi-ho.ne.jp/okuhara/howtoj.htm
- 「オセロAI入門」https://qiita.com/na-o-ys/items/10d894635c2a6c07ac70
- 「Thellのアルゴリズムについて」http://sealsoft.jp/thell/algorithm.html
- 「ブラウザで打てる自分より強いオセロAIを作る」https://github.com/trineutron/othello
本リポジトリのソースコードはMITライセンスです。 商用・非商用問わず、ご自由にお使い下さい。