じゃんけん何連勝の作り方 — 心理戦CPUを作ろう

このゲームで遊ぶ → ソースコード全文 →

このチュートリアルで学べること

じゃんけんは「グー/チョキ/パー」の3パターンだけのシンプルなゲームですが、CPUに「人の手を読ませる」と一気に面白くなります。完全ランダムなCPUとの違いも学べます。

ステップ1: 勝敗判定をオブジェクトで美しく書く

if文を並べる代わりに、「この手に勝つ手は?」というマップを作ると、コードがすっきりします。

// hand に勝つ手を返す
function winnerOf(hand) {
  return {
    rock: 'paper',
    scissors: 'rock',
    paper: 'scissors'
  }[hand];
}

function judge(player, cpu) {
  if (player === cpu) return 'draw';
  if (winnerOf(cpu) === player) return 'win';
  return 'lose';
}

ステップ2: プレイヤーのクセを読むCPU

プレイヤーが過去にどの手を多く出したかを集計し、その最頻出の手に勝つ手をCPUに選ばせます。

var history = []; // プレイヤーが出した手の履歴

function chooseCpuHand() {
  if (history.length < 3) {
    // 序盤はランダム
    return rand(['rock','scissors','paper']);
  }
  // 直近5手の頻度
  var freq = { rock: 0, scissors: 0, paper: 0 };
  var start = Math.max(0, history.length - 5);
  for (var i = start; i < history.length; i++) {
    freq[history[i]] += 1;
  }
  // 最頻出の手を予想
  var sorted = Object.keys(freq).sort(function (a, b) {
    return freq[b] - freq[a];
  });
  return winnerOf(sorted[0]); // 予想に勝つ手を出す
}

ステップ3: 確率調整で「読まれすぎない」工夫

毎回パターン通りだとプレイヤーに簡単に読まれます。ランダム要素を70:20:10で混ぜることで、適度な難易度になります。

function chooseCpuHand() {
  // ... (前ステップの予想ロジック)
  var counter = winnerOf(predicted);

  var r = Math.random();
  if (r < 0.7) return counter;     // 70%: 予想通り
  if (r < 0.9) return rand(HANDS); // 20%: ランダム
  return predicted;                 // 10%: あいこ狙い
}

この比率はゲームバランスに直結します。プレイヤーが連勝しすぎる場合は予想通りの確率を上げ、勝てなさすぎる場合はランダム比率を上げて調整します。

まとめ — 次のステップ

「過去のデータから次を予測する」という考え方は、シンプルなAIの基礎です。発展としては、N-gramでより長い手のパターンを学習する、難易度モードを追加する、勝率履歴をグラフ化するなどに挑戦してみましょう。

よくある質問

Q: 完全ランダムなCPUとの違いは?

A: 完全ランダムだと勝率は理論上50%になり、長く遊ぶと飽きます。クセを読むCPUなら「同じ手を連続で出すと負ける」など心理的な駆け引きが生まれ、ゲームに深みが出ます。

Q: 機械学習を使わなくてもAIっぽい動きになる?

A: なります。「直近の手の頻度」だけでも十分人間っぽい動きをします。本格的な機械学習を使わなくても、シンプルな統計でAIの雰囲気は十分出せます。