今回は paiza の「ひとりすごろく」の問題に挑戦!
問題概要
ゲーム設定
- 一直線上に並んだ
N個のマスがある - 各マスには 1〜6 の数字が書かれている
サイコロ
- 通常と異なる配置の 特殊な6面サイコロ
- 面には ID が固定で割り当てられている:
T, B, U, D, L, R - 入力で「各 ID に対応する数字」が与えられる
- 裏表:
T ↔ B
U ↔ D
L ↔ R
初期状態
- スタート地点にサイコロを置く
-
T面が上 -
U面がゴール方向
移動ルール
- 次のマスに進むとき:
- 上面の数字が次のマスの数字になるようにサイコロを回転させる
- 回転は 90° 単位
- 奥 / 手前 / 左 / 右
- 必要なら 複数回 回転してよい
目的
- スタートからゴールまで進む
- 必要な回転回数の最小値を求める
入力例:
1 6 2 5 4 3
4
1
5
3
4
出力例:
4
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
const num = lines[0].split(' ').map(Number);
const N = Number(lines[1]);
const p = lines.slice(2).map(Number);
let count = 0; // 回転数
let topIdx = 0; // 上面のインデックス
for (let i = 0; i < N; i++) {
// 次のマス
const nextIdx = num.indexOf(p[i]);
// 反対の面
let opposite;
if (topIdx % 2 !== 0) {
opposite = topIdx - 1;
} else {
opposite = topIdx + 1;
}
if (topIdx === nextIdx) {
// 回転なし
} else if (nextIdx === opposite) {
// 反対は2回転
count += 2;
} else {
// それ以外は1回転
count++;
}
topIdx = nextIdx; // 上面を更新
}
// 結果を出力
console.log(count);
});
🔍コードの流れ
- 入力を受け取る
- サイコロの面配置
num = [T, B, U, D, L, R] - マスの数
N - 各マスに書かれた数字配列
p
- サイコロの面配置
- 初期状態を設定
- 回転回数
count = 0 - サイコロの上面は
T(index0)とする
- 回転回数
- スタートからゴールまで順に処理
- 各マス
iについて次を行う:- そのマスに必要な数字
p[i]が - サイコロのどの面(index)かを
indexOfで調べる - 現在の上面
topIdxの 裏面の index を求める- 偶数なら
+1 - 奇数なら
-1
- 偶数なら
- 回転回数を判定する
- 同じ面 → 0 回転
- 裏面 → 2 回転
- それ以外 → 1 回転
- 上面を次のマスの面に更新する
- そのマスに必要な数字
- 各マス
- 合計回転数を出力
📝まとめ
観察ポイント
- 各マスで重要なのは:
- 今の上面
- 次に必要な数字(=次の上面)
- 向き(U/D/L/R)を完全に追跡する必要はない
サイコロの性質
- 上面が決まれば、裏面は一意に決まる
- 6 面の関係は 固定ペア
0 ↔ 1
2 ↔ 3
4 ↔ 5
各ステップでの最小回転数
| 状態 | 必要回転 |
|---|---|
| 今の上面 = 次の面 | 0 回 |
| 次の面 = 裏面 | 2 回 |
| それ以外 | 1 回 |
➡️ 毎回これを足すだけで最小になる