今回は paiza の「「ひとりすごろく」を解くために : part2」の問題に挑戦!
問題概要
■ サイコロについて
- 6 面サイコロが 1 つ与えられる
- 各面には 1〜6 の数字が 1 つずつ書かれている
- ただし、数字の配置は通常のサイコロとは異なる
- ゲーム開始時に、各面の数字配置が入力として与えられる
■ 面の ID(位置の定義)
- サイコロの各面には以下の ID(位置名) がある
-
T: 上 -
B: 下 -
U: 手前 -
D: 奥 -
L: 左 -
R: 右
-
■ 初期状態
- サイコロは以下の向きで置かれている
-
Tの面が 上 -
Uの面が 手前
-
- 入力では
T B U D L Rの順で、各面に書かれている数字が与えられる
■ できる操作(回転)
- サイコロを 90° 回転させることができる
- 回転方向は以下の 4 種類
- 手前
- 奥
- 右
- 左
- 必要であれば 複数回の回転を行ってよい
■ 求めるもの
- 数字 1〜6 それぞれについて、
その数字が書かれた面を上にするために必要な回転回数の最小値を求める - 出力は 6 行
i行目:数字iを上にするための最小回転回数
■ 入力条件(制約)
-
T, B, U, D, L, Rはすべて整数 - 値はすべて
1〜6 - 重複なし(必ず 1〜6 がちょうど 1 回ずつ現れる)
入力例:
5 2 3 6 4 1
出力例:
1
2
1
1
0
1
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line));
rl.on('close', () => {
const [T, B, U, D, L, R] = lines[0].split(' ').map(Number);
for (let i = 1; i <= 6; i++) {
if (i === T) {
console.log(0);
} else if (i === B) {
console.log(2);
} else {
console.log(1);
}
}
});
🔍コードの流れ
- 入力を受け取る
- 1 行目から
T, B, U, D, L, Rを読み込む - 初期状態で各 ID の面に書かれている数字を表す
- 1 行目から
- 裏面の対応を記録する配列を作る
-
opposite[i]を
「数字iが上に来たとき、その裏にある数字」として使う - サイコロは必ず「面と裏面」がペアになるため、
-
T↔B -
U↔D -
L↔R
を相互に登録する
-
- 1〜6 の数字について順番に調べる
-
i= 1, 2, …, 6 のループを回す - 「数字
iが書かれた面を上にするには何回転必要か」を考える
-
- 回転回数を条件分岐で判定する
(1)iがTと同じ場合- すでに上を向いている
- 回転は不要
-
0を出力
(2)iがTの裏面(opposite[T])の場合 - 上の面の真裏にある
- 最小でも
2回転が必要 -
2を出力
(3) それ以外の場合 - 側面(
U, D, L, Rのいずれか) - どの方向にも
1回転すれば上にできる -
1を出力
✅OK例 2:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', line => {
const num = line.split(' ').map(Number);
// num[0] = T, num[1] = B(Tの裏)
const opposite = num[1];
for (let i = 1; i <= 6; i++) {
if (i === num[0]) {
console.log(0);
} else if (i === opposite) {
console.log(2);
} else {
console.log(1);
}
}
rl.close();
});
📝まとめ
- 回転方向は自由なので 常に最小回数を選べる
- 初めから上の面は 0 回、その裏面は必ず 2 回
- それ以外は 1 回
- その判定を、
opposite[T]を使って明確にしている。