なぜ要るか
前の術でデータの形にしました。では増やしてみます。 山を1〜5の5枚から1〜7の7枚にして、配る枚数も3枚から4枚にします。
変えるのは2つの数字だけです。DECK_SIZE が山に入れる札の枚数、DEAL が最初に配る枚数です。
やってみると分かりますが、データを足しただけでは壊れます。 壊れる場所は決まっていて、手で数字を書いた場所です。
この術は、そこを1つずつ潰す回です。
使う道具: なし
AIプロンプト
この術の作業をAIへ任せるときは、これをそのまま貼ってください。
DECK_SIZE を7、DEAL を4にして。takerOf と chooseCpuMove は変更しないで。
画面の文字と手番の数をデータから作る形に直して。
takerOf と chooseCpuMove の部分は、自分のゲームで変えたくない関数の名前に置き換えてください。
山5枚を7枚にした結果
先に見せます。データを2つ変えただけの前後です。
山5枚・3枚配りのとき。
DECK_SIZE を7、DEAL を4にしたあと。
画面の文字、配られる枚数、手番の数、相手の思考、全部が付いてきています。 コードは触っていません。
これが自動で付いてくるようにするのが、この術の中身です。
数字を手で書いた場所が全部バグになります
いちばん分かりやすいのが画面の文字です。
<p class="sub">山5枚から3枚・3手勝負</p>
山を増やした瞬間、この表示は嘘になります。 5枚でもないし3手でもありません。
だからデータから作ります。
el('subtitle').textContent = '山' + DECK.length + '枚から' + DEAL + '枚・' + DEAL + '手勝負';
el('subtitle') は id で画面の部品を取ってくる書き方で、textContent はその中の文字を差し替える指示です。+ は文字をつなぐ記号なので、この1行は「いまの山の枚数と配る枚数から説明文を組み立てて、画面に入れ直す」という意味になります。
山そのものも、枚数のデータから作れます。
var DECK = [];
for (var d = 1; d <= DECK_SIZE; d++) DECK.push({ id: 'c' + d, label: String(d), power: d });
手番の数を 3 と書かないのも要点です。 このゲームは1手番に1枚置くので、配る枚数=手番の数です。DEAL から出せば、配りを変えても勝負の長さが勝手に付いてきます。
これは記事の外でも同じで、この講座のサイトも看板に出る「◯◯の術」の数を手書きしていません。術を1本増やすと、看板の数字が勝手に変わります。 数字を手書きすると、増やすたびに直す場所を探す作業が生まれます。
増やすと壊れる場所の一覧
僕が実際に踏んだものです。同じ順で壊れます。
| 壊れる場所 | 症状 | 直し方 |
|---|---|---|
| 画面の文字 | 「山5枚から3枚」のまま | データから作る |
| 手番の判定 | 3手で終わる/終わらない | DEAL を使う |
| 手札の並び | 横に溢れてはみ出す | flex-wrap: wrap を入れる |
| 相手の思考 | 増えた札を考慮しない | 手札を全部見て点数を付ける形にする |
最後の1つが盲点です。 3-4で作った相手の思考が「3枚のうちから選ぶ」前提で書かれていると、4枚になっても3枚しか見ません。
いまの形はこうなっています。手札の枚数に依存していません。
function legalMoves(hand) {
var moves = [];
hand.forEach(function (cardId) {
TARGETS.forEach(function (t) { moves.push({ card: cardId, target: t.id }); });
});
return moves;
}
この関数は、手札1枚ごとに的の数だけ組み合わせを作り、「打てる手の一覧」として返します。枚数を数字で書いていないので、手札が3枚でも4枚でもそのまま通ります。
残っている手札を全部並べて点数を付ける形なら、枚数が変わっても動きます。 3枚×的3つで9通りだった合法手が、4枚×的3つで12通りになるだけです。
データの間違いを起動時に見つける
増やすときに一番多いのが、書き写しの間違いです。idの重複、powerの書き忘れ、そして今回増えたのが「配る枚数を山より多くしてしまう」です。
どれも黙って壊れます。だから起動時に見ます。
function checkDeck() {
var errors = [];
var seen = {};
DECK.forEach(function (card) {
if (seen[card.id]) errors.push(card.id + ': idが重複');
seen[card.id] = true;
if (typeof card.power !== 'number') errors.push(card.id + ': powerがない');
});
if (DEAL > DECK.length) errors.push('配る枚数が山より多い');
return errors;
}
見ているのは3つです。同じidの札が2枚ないか、power が数字として入っているか、配る枚数が山の枚数を超えていないか。おかしい所を見つけるたびに errors へ1行ずつ足していき、最後にその一覧を返します。何も無ければ空の一覧が返るので、「中身が0件なら正常」と判断できます。
起動時に呼んで、間違っていたら画面に出して止めます。
var deckErrors = checkDeck();
if (deckErrors.length) {
el('msg').textContent = '札のデータが壊れています: ' + deckErrors.join(' / ');
} else {
// ここから普通の起動
}
僕が試しに壊してみたとき(山3枚のまま5枚配ろうとした)は、こう出ました。
札のデータが壊れています: 配る枚数が山より多い
遊べる状態で黙って壊れているより、起動しない方が親切です。 原因がその場で分かります。
やってみる
データを2つ変える
var DECK_SIZE = 7; var DEAL = 4;手で書いた数字を探す
grep -nE "3枚|3手|全 3" index.htmlgrepは、ファイルの中から指定した文字を探して、見つかった行を行番号つきで出すコマンドです。ここでは手書きで埋め込んだ「3枚」「3手」が残っていないかを探しています。出てきた場所を、データから作る形に置き換えます。
データから作り直す
画面の文字と手番の数を
DECK.lengthとDEALから出します。上のコードのとおりです。チェックを入れる
checkDeckを足して、起動時に呼びます。わざと配る枚数を山より多くして、止まるか確かめてください。遊んで確かめる
open index.html見るのはこの4つです。
- 画面の文字が「山7枚から4枚・4手勝負」になっているか
- 配られる手札が4枚か
- 4手で決着するか
- 手札がはみ出していないか
保存する
git add . git commit -m "山と配る枚数をデータにして、画面と手番を追従させた" git push
つまずきどころ
手札が横にはみ出す
flex-wrap: wrap を入れてください。
.myhand { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
flex-wrap: wrap は「横に並べた部品が入り切らなくなったら、次の行へ折り返す」という指定です。これが無いと、札が増えたときに画面の外へ押し出されて見えなくなります。
増やしたら読み合いが薄くなった気がする
正しい感覚かもしれません。山が大きいほど、相手の手札は読めなくなります。 対策は2つあります。
- 山を戻す
- 配る枚数の方を調整する
どちらが良いかは、6-6で数字を見て決めます。 ここで勘で決めないでください。
増やしたら急に簡単/難しくなった
起きます。種類を増やすとバランスは必ず動きます。 これも6-6で測ります。
AIに増やさせたら、判定のコードも書き換えられた
頼み方の問題です。
claude -p "DECK_SIZE を7、DEAL を4にして。takerOf と chooseCpuMove は変更しないで。
画面の文字と手番の数をデータから作る形に直して。"
「変更しないで」を明示するのが効きます。 データだけ変える作業なのか、仕組みも直す作業なのかを分けて頼んでください。
Windows の場合
grep は PowerShell では Select-String です。
Select-String -Path index.html -Pattern "3枚|3手"
次の一歩
DECK_SIZE と DEAL をいろいろ変えて開いてみてください。
山10枚から2枚だけ配ると、ほぼ運のゲームになります。山4枚から4枚配ると、全部見えている読み切りのゲームになります。データを2つ変えるだけで、別の遊び味を試せる——これがルールをデータで持った成果です。
中身が増えても壊れない形になりました。次は増えた画面を、説明なしで操作できる形に整えます!
ここまでの三つの的
この講座は、見本ゲーム「三つの的」を術ごとにすこしずつ育てながら進みます。下にあるのはこの術を終えた時点の実物です。そのまま遊べます。

