オンライン対戦ゲーム「リバーシ」を作ってみる
「リバーシ」と「オセロ」は基本的に同じゲームですが、オセロは「リバーシ」というイギリス発祥のゲームを基に、1973年に日本で「オセロ」として商品化された際、商標(Othello)の関係で「リバーシ」と名付けられました。
ルールに若干の違い(中央配置など)を加えたりして生まれ、現在では「オセロ」という名前はメガハウスの登録商標であり、それ以外の類似ゲームは「リバーシ」と名付けられることが多いです。
どちらも8×8盤で相手の石を挟んでひっくり返すボードゲームですが、オセロは中央の4マスに白黒の石を交互に置いて始めるという厳密なルールがあります。
リバーシのプロジェクト
.
1-- reversi_app.py --- アプリのメインプログラム
2-- reversi_utils.py --- リバーシのロジックを定義したプログラム
3-- reversi_test.py --- ロジックのテストプログラム
4-- token_checker.py --- 不正防止対策のためのプログラム
-- requirements.txt --- インストールに必要なパッケージを記述(flaks pytest)
-- statics --- リバーシの石などの画面素材を配置
------stone0.png---空の盤の画像
------stone1.png---黒の石の画像
------stone2.png---白の石の画像
------stone3.png---配置可能を示す画像
-- templates --- テンプレートを配置
5------index.html --- 画面のテンプレート
リバーシの実行
(flask_env) PS C:\Users\DELL\python\src\ch4\memo> cd..
(flask_env) PS C:\Users\DELL\python\src\ch4> cd reversi
(flask_env) PS C:\Users\DELL\python\src\ch4\reversi>
(flask_env) PS C:\Users\DELL\python\src\ch4\reversi>python -m pip install pytest
VSコードの▷で実行します。
「http://127.0.0.1:8888」にアクセスして、以下のような画像が表示されれば成功です。
今回はFlask起動時のホストに「0.0.0.0」を指定しているので、同じネットワーク内にある別のPCやスマホからもこのサーバーにアクセスできます。オンライン対戦ゲームなのでブラウザを2つ開いて交互に石を置いていきましょう。

リバーシのプログラム
reversi_app.py
from flask import Flask, redirect, url_for, render_template, request
import reversi_utils as utils
import token_checker as tc
# 盤面の初期化 --- (※1)
board = utils.generate_board()
who = utils.BLACK
app: Flask = Flask(__name__)
tc.reset_tokens()
# 現在の盤面の状態を表示 --- (※2)
@app.route("/")
def index():
me = int(request.args.get("who", who)) # 誰の手番か
token = request.args.get("token", "") # トークン
# 石の数を数えて、表示するメッセージを決定
black, white = utils.count_stone_both(board)
msg = utils.STATUS[who] + "の手番" # メッセージを表示
if black + white == 64:
msg = "黒の勝ち" if black > white else "白の勝ち"
elif black + white >= 6: # 初期状態でなければ不正チェック
if not tc.check_token(me, token):
return "不正なアクセスです"
can_place = (who == me)
return render_template( # テンプレートに当てはめて表示 --- (※3)
"index.html",
board=utils.add_flip_mark(board, who) if can_place else board,
count=(black, white), token=tc.get_token(me),
msg=msg, me=me, can_place=can_place)
# 座標(x, y)に石を配置する関数 --- (※4)
@app.route("/place/<int:y>/<int:x>")
def place(y: int, x: int):
global who
me = int(request.args.get("who", who))
token = request.args.get("token", "")
c = sum(utils.count_stone_both(board))
if (c >= 5)and(not tc.check_token(me, token)): # 不正を検知 --- (※5)
return "不正なアクセスです"
if utils.can_flip(board, x, y, who):
utils.flip(board, x, y, who)
who, me = utils.toggle(who), who
return redirect(url_for("index", who=me, token=tc.get_token(me)))
# ゲームをリセットする関数 --- (※6)
@app.route("/reset")
def reset():
global board, who
board = utils.generate_board()
who = utils.BLACK
tc.reset_tokens()
return redirect(url_for("index"))
# 手番をスキップする関数 --- (※7)
@app.route("/skip")
def skip():
global who
me = int(request.args.get("who", who))
token = request.args.get("token", "")
if who != me: # 自分の手番ではない
return redirect(url_for("index", who=me, token=token))
if not tc.check_token(me, token):
return "不正なアクセスです"
who = utils.toggle(who)
return redirect(url_for("index", who=me, token=tc.get_token(me)))
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port=8888) # Flaskのサーバーを起動
あ



コメント