今回は paiza の「移動が可能かの判定・複数回の移動」の問題に挑戦!
問題概要
- マップの大きさ(
H×W)と、移動者の初期座標 (sy,sx)、移動回数Nが与えられる - マップは
'.'(移動可能)、'#'(障害物)で構成される - 続いて
N回分、L(左に曲がる)か R(右に曲がる)が与えられる - 移動者は 最初は「北」を向いている
- 1 回の移動で行うこと
① 指示に従い左/右へ 方向転換する
② その向きに 1 マス進む - 移動できる条件
→ 移動先が マップ内 かつ'.' - 条件を満たせばその座標を出力
- 条件を満たさない場合
→"Stop"を出力して 以降の移動は全て中止
入力例:
7 3 2 1 5
..#
...
...
...
..#
.#.
##.
L
L
L
L
L
出力例:
2 0
3 0
3 1
2 1
2 0
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', input => lines.push(input));
rl.on('close', () => {
const [H, W, sy, sx, N] = lines[0].split(' ');
const grid = lines.slice(1, Number(H)+1).map(line => line.split(''));
const d = lines.slice(Number(H)+1);
let movedY = Number(sy);
let movedX = Number(sx);
let dir = 'N';
for (let i = 0; i < Number(N); i++) {
const LR = d[i];
if (dir === 'N') {
if (LR === 'L') {
movedX--;
dir = 'W';
} else { // === 'R'
movedX++;
dir = 'E'
}
}
else if (dir === 'S') {
if (LR === 'L') {
movedX++;
dir = 'E';
} else {
movedX--;
dir = 'W';
}
}
else if (dir === 'E') {
if (LR === 'L') {
movedY--;
dir = 'N';
} else {
movedY++;
dir = 'S';
}
}
else { // === 'W'
if (LR === 'L') {
movedY++;
dir = 'S';
} else {
movedY--;
dir = 'N';
}
}
if (movedY >= 0 && movedY < Number(H) && movedX >= 0 && movedX < Number(W) && grid[movedY][movedX] === '.') {
console.log(movedY, movedX);
} else {
console.log('Stop');
return;
}
}
});
🧭 コードの処理の流れ
- 標準入力を1行ずつ読み取る
- 読み取り完了後、処理開始 (
closeイベント) - 1行目から
-
H: マップの高さ -
W: マップの幅 -
sy: 初期 y 座標 -
sx: 初期 x 座標 -
N: 移動回数
を取得
-
- 続く
H行を読み取り、.,#が入った マップ配列gridを作成 - 残り
N行の入力を移動指示d[](L or R)として取得 - 現在位置 (
movedY,movedX) を初期値 (sy,sx) に設定 - 現在向き
dirを'N'(北)で初期化 -
N回分ループ- 指示が L なら左回転 → 1 マス進む
- 指示が R なら右回転 → 1 マス進む
※ 進む方向と新しい向きはdirに応じて決定
- 移動後のマスが
- マップ範囲内
-
'.'(通行可)
なら → 座標を出力
- 移動不可なら
"Stop"を出力し 即終了 - すべての移動が成功したら、全座標を出力し終了
📝まとめ
- 向き(方向)を状態として持ち、更新しながら進む問題
- 回転によって向きが変わるため、進む方向は毎回異なる可能性がある
- マップ範囲外チェックと障害物チェックを毎回行うのが重要
- 失敗時は即終了する制御(
return/break) - 文字入力を正しく配列/数値へ変換する必要がある (
split,Numberなど) - 座標系の向きに注意
- y:下に行くほど +
- x:右に行くほど +
- 「移動 → 判定」の順番
🚀 おまけ:短縮版コード
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', input => lines.push(input));
rl.on('close', () => {
const [H, W, sy, sx, N] = lines[0].split(' ').map(Number);
const grid = lines.slice(1, H + 1).map(line => line.split(''));
const moves = lines.slice(H + 1);
let y = sy;
let x = sx;
// 0:北, 1:東, 2:南, 3:西
let dir = 0;
const dy = [-1, 0, 1, 0];
const dx = [0, 1, 0, -1];
for (let i = 0; i < N; i++) {
const m = moves[i];
// L = 左回転(-1), R = 右回転(+1)
if (m === 'L') dir = (dir + 3) % 4;
else dir = (dir + 1) % 4;
const ny = y + dy[dir];
const nx = x + dx[dir];
if (ny >= 0 && ny < H && nx >= 0 && nx < W && grid[ny][nx] === '.') {
y = ny;
x = nx;
console.log(y, x);
} else {
console.log('Stop');
break;
}
}
});