今回は paiza の「時刻に伴う移動」の問題に挑戦!
これが初の「Aランク」問題かも?!
問題概要
へびが 10×10 などのマップの上を動く。
はじめは 北向き(N) で、最大 100 回(時刻 0〜99) 移動する。
🔹 1. 入力されるもの
基本情報
- マップの行数:
H - マップの列数:
W - 初期位置:(
sy,sx) - 方向転換の回数:
N
マップ
-
H行W列の文字列 -
'.'は移動可能 -
'#'は障害物(移動不可)
方向転換の予定
-
N行のデータ:- 時刻
t_i - 曲がる方向
d_i(L = 左、R = 右)
※t_iは昇順で来る
- 時刻
🔹 2. 移動ルール
◆ 各時刻 i(0〜99)での処理
- 方向転換の時刻なら
→ 指定の L / R に向きを変更してから 1マス動く - 方向転換でないなら
→ 今の向きにそのまま 1マス動く
🔹 3. 移動が「可能」かどうか
次の条件を両方満たすこと:
- 移動先が マップ外でない
- 移動先が 障害物 (
#でない
🔹 4. 出力
- 各移動が成功したら、その時点の座標 (y, x) を出力
- 移動できなかった瞬間
→"Stop"を出力して終了
最大 100 行。
入力例:
10 10 5 5 22
........#.
..........
..........
..........
#.........
..........
..........
........#.
..........
..........
0 L
3 R
4 L
7 L
10 R
12 R
21 L
24 L
26 R
28 R
35 L
36 R
41 R
44 R
62 L
63 L
72 L
81 L
85 R
90 R
92 R
98 R
出力例:
5 4
5 3
5 2
4 2
4 1
Stop
✅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(' ').map(Number);
const gridS = lines.slice(1, H+1).map(line => line.split(''));
const moves = lines.slice(H+1).map(line => line.split(' '));
let x = sx;
let y = sy;
const turn = {
N: { L: 'W', R: 'E'},
S: { L: 'E', R: 'W'},
E: { L: 'N', R: 'S'},
W: { L: 'S', R: 'N'}
}
const dy = { N: -1, S: 1, E: 0, W: 0 };
const dx = { N: 0, S: 0, E: 1, W: -1 };
let dir = 'N';
let count = 0;
for (let i = 0; i < 100; i++) {
const t = Number(moves[count][0]);
const d = moves[count][1];
// 方向転換をおこなう時刻の場合
if (i === t) {
dir = turn[dir][d];
count++;
}
y += dy[dir];
x += dx[dir];
if (y < 0 || y >= H || x < 0 || x >= W || gridS[y][x] === '#') {
console.log('Stop');
return;
} else {
console.log(y, x);
}
}
});
🧭 このコードの流れ
- 入力を受け取る
- 1 行目:
H, W, sy, sx, N - 次の
H行:マップ./# - 残り
N行:方向転換時刻t_iと向きd_i
- 1 行目:
- 初期設定
- 現在位置 (
y,x) をsy,sxにセット - 初期向き
dir = 'N' - 方向転換を読むインデックス
count = 0
- 現在位置 (
- 方向転換表
turnを作る(今の向き × L/R → 新しい向き) - 各向きごとの移動量
dy,dxを用意 - 時刻
0〜99をループでまわす(最大 100 回移動) - 今の時刻
iが方向転換予定時刻か確認-
i === moves[count][0]の場合- 指定された方向 (L または R) に向きを変更
-
count++で次の方向転換へ
-
- 向き
dirにしたがって 1 マス移動(y,xを更新) - 移動が可能かチェック
- マップ外なら
Stop -
'#'ならStop
- マップ外なら
- 移動が成功したら新しい
y,xを出力 - 移動不能になった時点で終了
📝まとめ
◆ 1. 時刻
- 時刻
iに応じて、 -
i == t_jなら方向転換を行う
◆ 2. 方向の管理(N / E / S / W の更新)
- L / R でどう変わるかを辞書(オブジェクト)で管理するのが楽。
- 今回の
turnオブジェクトが便利。
◆ 3. dy, dx で座標を簡潔に動かす
- 向きごとの移動量を
dy/dxオブジェクト化するとコードを圧縮できる。
◆ 4. 配列を使ったマップ処理
-
grid[y][x]で障害物チェック - 2次元マップの基本処理が身につく。
◆ 5. 境界チェック
範囲外アクセスは絶対 NG
0 <= y < H-
0 <= x < W
という典型的な 2D の境界条件。
◆ 6. シミュレーション問題での終了条件
- 移動不可になった瞬間に
Stop - 以降の処理はしない(
returnで早期終了)
◆ 7. 方向転換の入力が複数回あるときの管理
-
count変数で「次の方向転換はどれか」を追跡