1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今回は paiza の「幅のある移動」の問題に挑戦!


問題概要

✔ 問題の目的

マップ上を移動し、通ったマスを '*' に書き換えて最終マップを出力する。

✔ 与えられる情報

  • マップサイズ:H 行 × W
  • マップ内容:
    • . → 移動可能
    • # → 障害物(通れない)
  • 開始位置:(sy, sx) ※必ず .
  • 移動回数 N
  • N 個の移動指示
    • d_i → L or R(左/右回転)
    • l_i → 移動マス数(最大20)

✔ 移動ルール

  • 初期の向きは 北(N)。
  • L/R によって向きが変わる。
  • 各指示ごとに、向きを変えてから l_i マス進む。
  • 移動中に
    • マップ外へ出る
    • 障害物 # に当たる
      → そこまでの移動分だけ '*' を付けて 全ての移動を打ち切る。
  • 最初の位置も '*' にする。

✔ 移動可能の定義

移動先が

  • マップ範囲内
  • .(障害物ではない)

の両方を満たす場合。


✔ 出力

  • 移動経路に '*' が付いた H 行のマップ

✔ 入力される値

H W sy sx N        
S_0     
...     
S_(H-1)     
d_1 l_1     
...     
d_N l_N



入力例:

10 10 4 5 3
.......#..
..........
..........
#.........
..........
......#...
..........
....#.....
...#......
..........
L 3
R 1
R 3

出力例:

.......#..
..........
..........
#.****....
..****....
......#...
..........
....#.....
...#......
..........






✅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'; 
    gridS[y][x] = '*';
    
    // 移動処理
    for (let i = 0; i < N; i++) {
        const d = moves[i][0]; // 左右の回転
        const l = Number(moves[i][1]); // 移動回数
        
        // 方向の更新
        dir = turn[dir][d];
        
        // 移動
        for (let j = 0; j < l; j++) {
            const ny = y + dy[dir];
            const nx = x + dx[dir];

            if (ny < 0 || ny >= H || nx < 0 || nx >= W || gridS[ny][nx] === '#') {
                gridS.forEach(s => console.log(s.join('')));
                return;
            } else {
                gridS[ny][nx] = '*';
            }
            
            y = ny;
            x = nx;
        }
    }
    
    gridS.forEach(s => console.log(s.join('')));
});

🧭 コード全体の流れ

① 入力の読み取り

  • 標準入力を lines[] にすべて読み込む
  • 1行目から H, W, sy, sx, N を取得
  • 次の H 行をマップとして gridS に2次元配列で格納
  • 残りの N 行を移動指示(方向回転 + 移動距離)として moves に格納

② 初期設定

  • 今の座標を (x, y) にセット(sx, sy
  • 初期向きは 北(N)
  • 現在地 gridS[sy][sx]'*' に変更(通った場所マーク)

③ 回転ルールの定義

  • 方向と L/R 回転の対応表 turn を用意
  • 例:北で L → 西、北で R → 東

④ 移動量(dx, dy)の定義

  • 各方向(N, S, E, W)に対して y, x がどう変化するか定義

⑤ N回の移動を順に処理

  1. 移動指示 d_i(L or R)と l_i(歩数)を取り出す
  2. 現在の向きを更新(turn[dir][d]
  3. 歩数 l 回だけ繰り返し移動
    • 次の座標 ny, nx を計算
    • 壁(#)か、範囲外なら →
      これまで歩いた分だけ '*' をつけた状態で出力して終了(以降の移動は無視)
    • 通れるなら '*' を付けて座標更新

⑥ 全移動が正常に終了したら

  • 最終的なマップをすべて出力






📝まとめ

① 方角の管理(N, S, E, W の向きと回転)

  • L/R で向きがどう変わるかの回転辞書を用意する
  • 向きを決める → 動く

② 座標更新(dx, dy の使い方)

  • 向きに応じて (y, x) をどのように増減させるか整理する。
  • dx, dy を辞書(オブジェクト)で持つことでコードがシンプルになる。

③ マップ範囲チェック

  • 0 ≤ ny < H
  • 0 ≤ nx < W
    範囲外は即終了条件。

④ 障害物チェック

  • grid[ny][nx] === '#' のとき進めない。

⑤ “できるところまで移動して終了” の処理

  • 1歩ずつ進み、途中で壁/範囲外に当たれば即終了。
  • "その手前まで" '*' を付ける点が重要。

⑥ 進んだマスを '*' に書き換える

  • 開始地点も必ず '*'
  • 移動中に通ったマスすべて '*'

⑦ 全移動が終わる or 途中終了したらマップを出力

  • grid.forEach(row => console.log(row.join('')));
    で二次元配列を出力。




僕の失敗談(´;ω;`)と解決法🐈

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?