じゃんけんは「グー/チョキ/パー」の3パターンだけのシンプルなゲームですが、CPUに「人の手を読ませる」と一気に面白くなります。完全ランダムなCPUとの違いも学べます。
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';
}
プレイヤーが過去にどの手を多く出したかを集計し、その最頻出の手に勝つ手を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]); // 予想に勝つ手を出す
}
毎回パターン通りだとプレイヤーに簡単に読まれます。ランダム要素を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でより長い手のパターンを学習する、難易度モードを追加する、勝率履歴をグラフ化するなどに挑戦してみましょう。
A: 完全ランダムだと勝率は理論上50%になり、長く遊ぶと飽きます。クセを読むCPUなら「同じ手を連続で出すと負ける」など心理的な駆け引きが生まれ、ゲームに深みが出ます。
A: なります。「直近の手の頻度」だけでも十分人間っぽい動きをします。本格的な機械学習を使わなくても、シンプルな統計でAIの雰囲気は十分出せます。