1. 導入:なぜPHPで「状態」を扱う必要があるのか
PHPは本来「ステートレス(状態を保持しない)」な言語です。リクエストごとに処理が完結し、メモリ上の変数は破棄されます。しかし、ブラックジャックのようなゲームや、ショッピングカートのようなアプリケーションでは、ユーザーの操作をまたいでデータを維持する必要があります。本稿では、PHPのセッション機能を用いて、簡易的なゲーム状態を管理する方法を解説します。
2. 基礎知識:PHPセッションの仕組み
セッションは、サーバー側に一時的なデータを保存する仕組みです。
session_start() を呼び出すことで、ブラウザから送られてくるクッキー(セッションID)をキーとして、サーバー上のファイルやメモリにアクセスします。これにより、ページ遷移しても変数の中身を維持することが可能になります。
今回の実装では、トランプの山札の状態やプレイヤーの手札を配列としてセッションに保存し、リクエストごとに復元・更新することでゲームの進行を実現します。
3. 実装と解決策
ゲームの核心となるのは「山札の初期化(シャッフル)」「カードの配布」「合計値の算出」です。
特に重要なのが、カードを配列として管理し、array_shift() 関数を使用して山札からカードを一枚ずつ取り出す処理です。この手法は、スタックやキューのようなデータ構造を扱う際に非常に直感的です。
4. サンプルプログラム
以下は、ゲームのロジック部分を抽出したシンプルなコード例です。
/
function init_cards() {
$cards = [];
$suits = [‘spade’, ‘heart’, ‘diamond’, ‘club’];
foreach ($suits as $suit) {
for ($i = 1; $i <= 13; $i++) {
$cards[] = ['num' => $i, ‘suit’ => $suit];
}
}
shuffle($cards); // 配列をランダムに並び替える
return $cards;
}
/
- 手札の合計値を計算する(エースの11/1判定を含む)
/
function sum_up_hands($hands) {
$total = 0;
$ace_count = 0;
foreach ($hands as $card) {
$num = $card[‘num’];
if ($num > 10) {
$total += 10;
} elseif ($num === 1) {
$ace_count++;
$total += 1; // 一旦1として計算
} else {
$total += $num;
}
}
// エースを11として扱えるか判定(合計が11以下なら10を加算して21に近づける)
if ($ace_count > 0 && $total <= 11) {
$total += 10;
}
return $total;
}
// ゲームの初期化またはセッションからの復元
if (!isset($_SESSION['cards'])) {
$_SESSION['cards'] = init_cards();
$_SESSION['player'] = [array_shift($_SESSION['cards']), array_shift($_SESSION['cards'])];
}
?>
5. 応用・注意点:現場で役立つポイント
実務開発において、セッションに複雑なオブジェクトをそのまま突っ込むことは推奨されません。以下の点に注意してください。
データ型のシリアライズ:
PHPのセッションは配列や文字列の保存には適していますが、複雑なクラスインスタンスを保存する場合、__sleep()や__wakeup()の挙動を理解しておく必要があります。基本的には「データ(配列)」と「ロジック(関数・クラス)」を分離し、セッションにはデータのみを保持させる設計が保守性を高めます。
バースト(オーバーフロー)の回避:
ゲームロジックで最も陥りやすいのは、カードが尽きた場合の処理です。本番環境では、array_shift() を行う前に、山札の配列が空でないか(count関数などで確認)を必ずチェックしてください。山札が空になった際の再シャッフル機能を実装することが、堅牢なシステム構築の第一歩となります。