2048オンライン対戦で「公平」を実現する方法:シード乱数の魔法
2048のオンライン対戦で両プレイヤーに同じタイル配置を保証するシード乱数の仕組みと、リアルタイム同期の実装方法を解説します。クライアント側でゲームロジックを実行しながら公平性を担保するテクニック。
2048オンライン対戦で「公平」を実現する方法
「2048の対戦版を作りたい」
そう思ったとき、最初にぶつかる壁は公平性です。2048は新しいタイルがランダムに出現するゲーム。対戦で両者に違うタイルが出てきたら、それは純粋に運ゲーになってしまいます。
この記事では、シード乱数を使って2048対戦の公平性を実現する方法と、リアルタイム同期の実装を解説します。
公平な対戦とは?
2048のランダム要素
2048には2つの重要なランダム要素があります:
- 初期タイル: ゲーム開始時に2つのタイルが配置される
- 新規タイル: 移動後に新しいタイル(2か4)が出現する
対戦では、両プレイヤーにまったく同じランダム結果を提供する必要があります。
シード乱数という解決策
シード乱数は、「種(シード)」となる数値から決定的な乱数列を生成します。
これにより、サーバーはシード値だけを両プレイヤーに送れば、両者が同じタイル配置でプレイできます。
シード乱数生成器の実装
線形合同法
最もシンプルで高速なシード乱数は「線形合同法(LCG)」です:
なぜこのパラメータ?
2048でのタイル配置
初期タイルの配置
ゲーム開始時、同じシードから同じ初期配置を生成します:
タイル配置関数
両プレイヤーで同じ結果になる理由
重要なのは、乱数を呼び出す順序が両者で同じであること。移動の操作ごとに1回addSeededTileを呼ぶので、同じ手順でプレイすれば同じ結果になります。
グリッド操作の実装
回転によるスライド処理の統一
2048は4方向にスライドできますが、実装では「左にスライド」だけを実装し、グリッドを回転させることで全方向に対応しています:
グリッドの時計回り回転
スライドとマージ
サーバー側の実装
Durable Objectでルーム管理
ゲーム開始時のシード生成
スコアのリアルタイム同期
2048はクライアント側でゲームロジックを実行しますが、スコアは定期的にサーバーに送信します:
クライアント側の実装
React Hookでの状態管理
ゲームコンポーネントでのシード初期化
勝敗判定のロジック
勝利条件
2048対戦には複数の勝利条件があります:
| 条件 | 説明 |
|---|---|
| 2048達成 | 最初に2048を作ったプレイヤーが勝利 |
| 時間切れ | スコアが高い方が勝利 |
| 相手ゲームオーバー | 相手が動けなくなったら5秒後に判定 |
| 退出 | 相手が離脱したら自動勝利 |
2048達成時の処理
片方がゲームオーバーになった場合
この「5秒ルール」により、相手がゲームオーバーになっても少し時間をもらえます。逆転の可能性を残しつつ、無限に待たされることも防ぎます。
相手の盤面表示
対戦の緊張感を高めるため、相手の盤面もリアルタイムで表示します:
これにより、相手がどんな状況かを把握しながらプレイできます。
アニメーションの実装
Framer Motionを使って、タイルのアニメーションを実装しています:
タイルのIDを使って、Reactが正しくアニメーションを追跡できるようにしています。
まとめ
| 技術要素 | 採用した解決策 |
|---|---|
| 公平性 | シード乱数で同じタイル配置を保証 |
| 通信 | WebSocket(Durable Objects) |
| ロジック | クライアント側で実行(レスポンス向上) |
| 同期 | スコアと盤面を定期送信 |
| アニメーション | Framer Motion |
シード乱数を使うことで、サーバーはシード値を1回送るだけで公平な対戦を実現できます。クライアント側でゲームロジックを実行するため、レスポンスも良好です。
この「シードだけ共有してクライアントで計算」というパターンは、他のパズルゲームやローグライクにも応用できます。
遊んでみる
実際に2048バトルを遊んでみたい方は、こちらからどうぞ:
ソースコード
この記事で紹介したコードの完全版はGitHubで公開しています:
- Game2048Room.ts(サーバー側)
- use2048Battle.ts(クライアントHook)
- Game2048Battle.tsx(UIコンポーネント)
- seededRandom.ts(シード乱数)
このシリーズの他の記事
このサイトでは、他にもオンライン対戦ゲームの実装記事を公開しています:
- 同一フィールドで戦うスネークバトルを実装してみた - Durable Objectsでサーバー側ゲームロジック
- 日本語タイピングゲームの「shi」と「si」問題を解決する - 150以上のローマ字パターンに対応
- テトリスは運ゲーじゃない!7-bagアルゴリズムとマルチプレイ同期の仕組み - 7-bagとシード乱数の解説