今回は paiza の「【シミュレーション 2】perfect shuffle」の問題に挑戦!
問題概要
- 題材:トランプ52枚を用いた「パーフェクトシャッフル」
- 初期デッキ:
上から順に
S_1 ~ S_13, H_1 ~ H_13, D_1 ~ D_13, C_1 ~ C_13
※ Sスペード、Hハート、Dダイヤ、Cクローバー
- シャッフル手順(1回分)
- 山札を 上半分(26枚) と 下半分(26枚) に分ける。
- 下半分の一番下 → 上半分の一番下 → 下半分の下から2番目 → 上半分の下から2番目 → … の順で交互に積む。
→ つまり 「下 → 上」順で交互にカードを並べる。
- 入力:
K(0 ≤ K ≤ 100)
- 出力:
パーフェクトシャッフルをK回 行った後の山札の順番を、上から1枚ずつ改行して表示。
入力例:
1
出力例:
S_1
D_1
S_2
D_2
S_3
D_3
S_4
D_4
S_5
D_5
S_6
D_6
S_7
D_7
S_8
D_8
S_9
D_9
S_10
D_10
S_11
D_11
S_12
D_12
S_13
D_13
H_1
C_1
H_2
C_2
H_3
C_3
H_4
C_4
H_5
C_5
H_6
C_6
H_7
C_7
H_8
C_8
H_9
C_9
H_10
C_10
H_11
C_11
H_12
C_12
H_13
C_13
✅ OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', (input) => lines.push(input));
rl.on('close', () => {
const K = Number(lines[0]);
// 初期デッキ(S→H→D→C)
const suits = ['S', 'H', 'D', 'C'];
let deck = [];
for (const s of suits) {
for (let num = 1; num <= 13; num++) {
deck.push(`${s}_${num}`);
}
}
// K回シャッフル
for (let k = 0; k < K; k++) {
const top = deck.slice(0, 26); // 上半分
const bottom = deck.slice(26); // 下半分
const newDeck = [];
// 下から順に交互に積む(bottom[25], top[25], bottom[24], top[24], ...)
for (let i = 25; i >= 0; i--) {
newDeck.unshift(bottom[i]);
newDeck.unshift(top[i]);
}
deck = newDeck; // 元の山札を、新しくシャッフルした山札に置き換える
}
// 出力(配列の先頭が山札の上なのでそのまま出す)
console.log(deck.join('\n'));
});
- 初期デッキ作成
- 絵柄
[‘S’, ‘H’, ‘D’, ‘C’]を順番に回す。 - 各絵柄に対して
1〜13の番号をつけて、合計52枚の山札を作る。
- 絵柄
- シャッフル処理を
K回繰り返す- 山札を 上半分(0〜25) と 下半分(26〜51) に分ける。
- 新しい配列
newDeckを作って、交互にカードを積んでいく。 - ここでは
bottom[i]→top[i]の順で交互に追加している。 - シャッフルが終わったら
deck = newDeckで置き換える。
- 出力
- 最終的な山札の順番を、1枚ずつ改行して出力する。
🗒️ まとめ
◯ 配列操作
-
sliceで配列を分割(上半分・下半分)。 - 新しい配列に交互に
unshift(先頭に追加)して並べ直す。
◯ ループ処理
- シャッフルを繰り返すために、
for (let k = 0; k < K; k++)とループを回す。
◯ 状態の更新が重要
-
deck = newDeck;とすることで、「次のシャッフルの出発点」を常に最新の山札に更新している。
◯ 出力の仕方
-
console.log(deck.join('\n'));で配列を1行ずつ表示できる。