Cloudflare Durable Objectsでリバーシのリアルタイム対戦を実装する
Cloudflare Workers の Durable Objects と WebSocket を使ってリバーシ(オセロ)のリアルタイムオンライン対戦を実装する方法を解説。サーバー権威型の設計、パス自動判定、ターン管理など、ボードゲーム特有の課題と解決策を紹介します。
リバーシ開発の舞台裏
リバーシ(オセロ)ゲームの開発で使ったAIアルゴリズム、オンライン対戦の実装、評価関数の設計を解説
Cloudflare Durable Objectsでリバーシのリアルタイム対戦を実装する
前回の記事では、リバーシAIを3段階の難易度で実装しました。今回は、そのリバーシをオンライン対戦に対応させます。
「リアルタイム対戦」と聞くと複雑そうですが、Cloudflare Durable Objectsを使えば、サーバーレスなのにステートフルなゲームサーバーを簡単に作れます。
なぜDurable Objectsなのか?
ボードゲームのオンライン対戦には3つの要件があります:
Durable Objectsはこの3つをすべて満たします:
各「対戦部屋」が1つのDurable Objectインスタンスになります。部屋ごとに独立した状態を持ち、WebSocket接続も直接管理できます。
アーキテクチャ全体像
OthelloRoom クラスが DurableObject を継承し、盤面状態・プレイヤー情報・WebSocket接続の3つをまとめて管理します。
部屋のライフサイクル
対戦部屋は4つの状態を遷移します:
1. waiting(待機中)
プレイヤーが部屋に参加し、準備完了を待つフェーズです。
色の割り当てはシンプルに**先に入った人が黒(先手)**です。
2. countdown(カウントダウン)
2人ともReadyになると、3秒のカウントダウンが始まります:
カウントダウン中にReadyを解除すると、待機状態に戻ります。これにより「準備ができていないのにゲームが始まる」事態を防ぎます。
3. playing(対戦中)
ゲーム開始時に盤面をリセットし、10分のタイマーを開始します:
タイマーの通知は残り60秒以下で毎秒、それ以外は30秒ごとです。これでクライアントの負荷を抑えつつ、終盤の緊迫感を演出します。
4. finished(終了)→ リマッチ
ゲーム終了後、プレイヤーの状態をリセットして待機状態に戻します:
部屋自体は破棄せず、再びReadyすれば新しいゲームを始められます。
サーバー権威型の設計
オンライン対戦で最も重要な設計判断が「誰がゲームロジックを実行するか」です。
OthelloRoomでは、クライアントから受け取るのは座標だけです。裏返しの計算、合法手の判定、勝敗判定はすべてサーバー側で行います:
3段階のバリデーション(ターン → 範囲 → 合法手)を通過した手だけが盤面に反映されます。
リバーシ特有の課題:パスの自動判定
リバーシには「打てる場所がないときはパス」というルールがあります。これはチェスや将棋にはない、リバーシ特有の仕組みです。
オンライン対戦では、パスの判定をサーバーが自動で行う必要があります。プレイヤーに「パス」ボタンを押させると、打てる場所があるのにパスする不正が可能になるためです。
3つのケース
手を適用した後、次にどうなるかは3パターンあります:
実装コードを見てみましょう:
Case 2のパス処理を詳しく見る
パスが発生したとき、サーバーは2つのメッセージを送信します:
具体例で見てみましょう:
情報の隠蔽:プレイヤーごとの有効手
セキュリティ上重要なのが、各プレイヤーに自分の有効手だけを送ることです:
なぜこれが重要なのか?もし相手の有効手が分かると、「相手はここしか打てないから、その裏をかこう」という不公平な戦略が可能になります。リバーシでは有効手の数が戦略に直結するため、この隠蔽は公平性を保つために必要です。
切断への対応
オンライン対戦では、プレイヤーが突然切断する可能性を常に考慮する必要があります:
WebSocketのcloseイベントとerrorイベントの両方で handlePlayerLeave を呼ぶことで、正常切断・異常切断の両方に対応しています。
メッセージプロトコル
クライアントとサーバー間のメッセージは、すべてJSON形式で型安全に定義されています:
クライアントが送るメッセージは最小限(意図だけ)で、サーバーが返すメッセージには計算結果がすべて含まれています。これがサーバー権威型の特徴です。
ゲーム終了の3パターン
ゲームが終了する条件は3つあります:
終了時には、両プレイヤーに詳細な結果を送信します:
まとめ
リバーシのオンライン対戦をDurable Objectsで実装するポイントをまとめます:
Durable Objectsの最大の利点は、WebSocketの接続管理とゲーム状態の保持を1つのクラスにまとめられることです。従来のようにRedisやデータベースで状態を外部管理する必要がなく、コードの見通しが良くなります。
次回の記事では、AIの「強さ」を決定する評価関数の設計に焦点を当て、位置評価・角の価値・モビリティ・終盤戦略の4要素を深掘りします。
実際のオンライン対戦は ADA Labのリバーシゲーム で体験できます。