0
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 の「へび」の問題に挑戦!

へびシリーズの最終Aランク問題を解くことができた!


問題概要

■ やること

  • マップ上をへびが 0〜99 の間で最大 100 回移動する。
  • 方向転換が指定されている時刻に向きを変え、その後 1 マス進む。

■ 移動の条件(重要)

  • 移動先が '.'(空き) のときだけ進める

  • '#'(障害物) や 自分の身体 '*' があると移動失敗

  • マップ外に出ても失敗

  • 失敗した時点で終了し、マップを出力


■ 移動のルール

  • 初期位置:与えられた (sy, sx)

  • 初期向き:北(N)

  • 向きは d_i の L(左)か R(右)で回転

  • 回転は指定の時刻 t_i にだけ行う

  • その後、いま向いている方向に 1 マス伸びる(=移動)

■ 出力

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

  • へびが通ったマスはすべて '*' に変える

  • 動けなくなったらその時点で終了して出力

  • 99 番目の時刻の移動まで行ったら終了



入力例:

5 5 3 1 3
.....
.....
.....
.....
.....
2 R
4 R
6 R

出力例:

.....
.***.
.*.*.
.***.
.....






✅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;
    gridS[y][x] = '*';
    
    for (let i = 0; i < 100; i++) {
        if (count < N) {
           const t = Number(moves[count][0]);
           const d = moves[count][1];
        
            if (i === t) {
                dir = turn[dir][d];
                count++;
            } 
        }
        
        const ny = y + dy[dir];
        const nx = x + dx[dir];
        
        
        if (ny >= 0 && nx >= 0 && ny < H && nx < W && gridS[ny][nx] === '.') {
            gridS[ny][nx] = '*';
            y = ny;
            x = nx;
        } else {
            gridS.forEach(s => console.log(s.join('')));
            return;
        }
    }
    
    gridS.forEach(s => console.log(s.join('')));
});

✔️ コードの流れ(簡潔な箇条書き)

  1. 入力を読む準備
    • readline で入力行を配列 lines に貯める。
  2. 入力データを分解
    • 1 行目から H, W, sy, sx, N を数値で取得。
    • 次の H 行をマップとして gridS に読み込む。
    • それ以降の行を「(時刻, 回転方向)」として moves に保持。
  3. 初期設定
    • 現在の位置を (x, y) にセット(スタート位置)。
    • 現在向きを 'N' に設定。
    • 方向転換表 turn と、各向きの移動量 dy, dx を準備。
    • スタート地点に '*' を置く(へびの身体にする)。
    • 次に読む方向転換のインデックス count = 0
  4. 最大 100 回の移動ループ開始
    • i = 0 〜 99 で順番に時刻を進める。
  5. 時刻 i が方向転換のタイミングなら向きを変える
    • moves[count] にまだ残りがあれば、
    • その時刻 t と回転方向 d を取り出す。
    • i === t なら dir = turn[dir][d] で向きを変更。
    • count++ して次の指示へ進む。
  6. 新しい位置 (ny, nx) を計算
    • 現在向き dir に応じて 1 マス進んだ位置を求める。
  7. 進めるかチェックして移動 or 終了
    • 範囲内かつ gridS[ny][nx] === '.' なら進める。
    • そこを '*' にして身体を伸ばす。
    • (x, y) を (nx, ny) に更新。
    • それ以外(壁・身体・範囲外)なら 終了してマップ出力。
  8. 100 回移動し終わったら最終マップを出力






📝まとめ


🔍 1. 今回の問題のポイント
  • 「へびの身体が残り続ける」=踏んだマスに '*' を残す

  • 「自分の身体にも衝突する」ようになる
     → 一度踏んだ場所には二度と入れない!


🔍 2. 時刻管理のコツ

  • i = 0〜99 をループ

方向転換の行は 時刻昇順で来る(t_i < t_(i+1)
 → count で次の転換を管理しやすい

🔍 3. 向き管理は表でやると超ラク

turn = {
  N: {L: 'W', R: 'E'},
  S: {L: 'E', R: 'W'},
  E: {L: 'N', R: 'S'},
  W: {L: 'S', R: 'N'}
}

🔍 4. 移動処理の順序が超重要

  • 時刻が方向転換のタイミングなら向きを変える

  • 次の移動先 (ny, nx) を計算

  • 範囲外・障害物・身体 → 即終了

  • そうでなければ進んで '*' を置く


🔍 5. へびの身体は消えない(伸びっぱなし)

  • 普通のスネークみたいに尻が消えない

  • 常に進んだマスを '*' にするだけ

  • そのため「身体にぶつかる」チェックが増える


🔍 6. 終了条件は2種類

  • 100 回(時刻 99)まで移動が終わった

  • 移動不可(壁 or 身体 or 範囲外)




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

0
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
0
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?