今回は paiza の「「ビームの反射」を解くために:part3」の問題に挑戦!
「ビームの反射」では、箱の区画を移動していき、通過回数を求める必要があるので、これを練習する問題を解いていく!
問題概要
箱の中にある各マスには、
ビームの「進行方向を指示する文字」が書かれている。
記号:指示の意味
-
R: ビームの向きを右にする -
L: ビームの向きを左にする -
U: ビームの向きを上にする -
D: ビームの向きを下にする -
S: ビームの向きを変更せず、直進させる
🚀 ビームの動作ルール
- ビームは 左上のマス (0,0) に対して
- 左の外部から右向き(→) に撃ち込まれる。
→ 最初の進行方向は R(右) - ビームが箱の外に出た時点で終了。
- 通過したマスの回数 を出力。
🧮 入力形式
H W
s_1
s_2
...
s_H
-
H: 高さ(行数) -
W: 幅(列数) - 各
s_iは長さWの文字列で、
各文字はR,L,U,D,Sのいずれか。
入力例:
3 5
SSDUR
ULSSS
LSRSU
出力例:
9
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', (input) => lines.push(input));
rl.on('close', () => {
const [H, W] = lines[0].split(' ').map(Number);
const s = lines.slice(1).map(line => line.split(''));
let x = 0;
let y = 0;
let dir = 'R'; // 初期方向は右向き
let count = 0;
while (true) {
// 範囲外に出たら終了
if (x < 0 || x >= W || y < 0 || y >= H) break;
const cell = s[y][x];
count++;
if (cell === 'R') dir = 'R';
else if (cell === 'L') dir = 'L';
else if (cell === 'U') dir = 'U';
else if (cell === 'D') dir = 'D';
// 'S' の場合は向きを変えずに進む
// 次の位置に進む
if (dir === 'R') x++;
else if (dir === 'L') x--;
else if (dir === 'U') y--;
else if (dir === 'D') y++;
}
console.log(count);
});
💻 コードの流れ
- 入力受付の準備
-
readlineモジュールで標準入力を受け取る準備をする。 - 入力行を
lines配列に順次格納。
-
- 入力完了時 (
closeイベント発火)- 最初の1行目(
lines[0])から高さHと幅Wを取得。 - 例: "
3 4" →H=3, W=4 - 残りの行(マップ部分)を2次元配列
sに変換。 - つまり、
s[y][x]で各マスの文字(R/L/U/D/S)が取れるようにする。
- 最初の1行目(
- 初期状態を設定
- ビームの開始位置を (x, y) = (0, 0) に設定。
(左上スタート) - 進行方向
dirを"R"(右向き)に設定。 - 通過したマスのカウント
count = 0。
- ビームの開始位置を (x, y) = (0, 0) に設定。
- ループでビームを進める
-
while (true)で無限ループを開始。 - まず、範囲外チェック。
→ 画面外に出たらbreakでループ終了。
-
- 現在のマスを確認
-
const cell = s[y][x];で現在位置の文字を取得。 - 通過回数をカウント:
count++
-
- マスの内容によって進行方向を変更
-
R→ 右向き (dir = 'R') -
L→ 左向き (dir = 'L') -
U→ 上向き (dir = 'U') -
D→ 下向き (dir = 'D') -
S→ 向きを変えずにそのまま進む(dirはそのまま)
-
- 次のマスへ進む
- 現在の
dirに応じて (x, y) を更新。- 右:
x++ - 左:
x-- - 上:
y-- - 下:
y++
- 右:
- 現在の
- 次ループへ → 範囲外になったら終了
- 結果出力
- 通過したマスの総数
countをconsole.log()で出力。
- 通過したマスの総数
📝まとめ
1️⃣ 入力は文字列→2次元配列化
→ s[y][x] でマスを直接参照できるように。
2️⃣ 初期向きは常に「右」
→ 左上マスに左側から入る。
3️⃣進行方向の更新はマスの文字で決まる
4️⃣ 移動処理の基本構造
if (dir === 'R') x++;
else if (dir === 'L') x--;
else if (dir === 'U') y--;
else if (dir === 'D') y++;
5️⃣ ループの終わりは「範囲外チェック」だけでOK
→ if (x < 0 || x >= W || y < 0 || y >= H) break;