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?

座標系での規則的な移動

Posted at

今回は paiza の「座標系での規則的な移動」の問題に挑戦!
難しかった(´;ω;`)


問題概要

  • 開始地点の (X, Y) 座標と 移動ステップ数 N が与えられる
  • 移動パターンは、中心(0,0)から 時計回りの渦巻き
    • 東 → 南 → 西 → 北 → 繰り返し
  • 座標系は
    • 👇 下方向が y 座標の正の向き
    • 👉 右方向が x 座標の正の向き
  • 時計回りの移動規則に従って N 歩進んだ後の「座標」を出力する

図:

20 21 22 23 24 25
19  6  7  8  9 ↓ 
18  5  0  1 10
17  4  3  2 11
16 15 14 13 12


入力例:

0 0 3 // X Y N

出力例:

0 1 // x y






✅ OK例:

const rl = require('readline').createInterface({ input: process.stdin });

const lines = [];

rl.on('line', l => lines.push(l));

rl.on('close', () => {
    let [sx, sy, N] = lines[0].split(' ').map(Number);

    // ESWN の順 → 時計回り
    const direct = ['N', 'E', 'S', 'W'];

    let x = 0, y = 0; // 座標変化(相対座標)
    let length = 1;   // 現在の移動マス数
    let now = 1;      // length の初期値
    let d = 1;        // 方向インデックス(右回転していく)
    let first = true; // その移動マス数の1回目かどうか

    const move = dir => {
        if (dir === 'N') y--;
        else if (dir === 'S') y++;
        else if (dir === 'E') x++;
        else if (dir === 'W') x--;
    };

    for (let i = 0; i < N; i++) {
        move(direct[d % 4]);
        length--;

        if (!first && length === 0) {
            // 2回目の移動終了 → 次のマス数へ
            first = true;
            now++;
            length = now;
            d++;
        } else if (length === 0) {
            // 1回目の移動終了 → もう一度同じマス数
            length = now;
            first = false;
            d++;
        }
    }

    console.log(sx + x, sy + y);
});

🔍 コードの流れ

  1. 入力を受け取る
    • 開始位置 sx, sy と歩数 N を取得する
  2. 方角リストを用意
    • ['N','E','S','W']
      ※配列 direct[d % 4] を使い、順番に
      北 → 東 → 南 → 西 → 北… と繰り返す
  3. 座標変化を表す変数を初期化
    • (x, y) = (0, 0) ← ここに移動量を足していく(相対座標)
  4. 移動に関する管理用変数のセット
    • length:今の方向で進むマス数(最初は 1
    • now:次に設定する length の元になる値(初期 1
    • d:方向インデックス(右回転を表す)
    • first:そのマス数で 1回目の移動 かどうか
  5. ループ開始(N 回移動する)
    • 現在向く方向 = direct[d % 4]
      その方向に 1マスだけ移動
    • length--(残りマス数を更新)
  6. マス数を使い切ったときに分岐
    • first == true(1回目終了)
      first = false にして、同じマス数でもう一度
      → 方向を1つ右回転
    • first == false(2回目終了)
      → 次はマス数を1増やして now++
      first = true に戻す
      → 方向を1つ右回転
  7. ループ終了後
    • 開始座標に移動量を加算して結果出力
    • sx + x, sy + y






🗒️ まとめ

  • 方向制御は配列を使って (d % 4) で管理
    ['N', 'E', 'S', 'W']
  • 移動回数の規則性
    → マス数は「同じ値を 2 回ずつ増やしながら進む」
  • 管理すべき変数
    • length:現在の残りの移動マス数
    • now:次に設定する移動マス数の基準値
    • d:移動方向を示すインデックス
    • first:そのマス数で1回目の移動かを管理
  • 移動後は 開始位置 + 相対的な移動量 で最終座標を算出




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
















🧸 おまけ:駄作記録

const rl = require('readline').createInterface({ input: process.stdin });

const lines = [];

rl.on('line', input => lines.push(input));

rl.on('close', () => {
    const [X, Y, N] = lines[0].split(' ').map(Number);
    
    let x = X;
    let y = Y;
    
    let p = 1;
    let j = 0;
    let k = 0;
    let dir = null;
    
    for (let i = 0; i <= N; i++) {
        // if (i > 24) console.log(dir + 'direction');
        
        if (dir === 'N') {
            y--;
            j++;
        } else if (dir === 'S') {
            y++;
            j++;
        } else if (dir === 'E') {
            x++;
            j++;
        } else if (dir === 'W') {
            x--;
            j++;
        }
        
        // console.log(p, i, j, 'start')
        if (i === p - 1) {
            j = 0;
            p = (Math.sqrt(p) + 2) ** 2;
            // console.log(p)
            k++;
            // let j = 0;
            // console.log(j, 'reset')
            dir = 'E';
        }
        else if (j < Math.sqrt(p) - 1) {
            // console.log(i, j, 'ijS')
            dir = 'S';
        } else if (j < (Math.sqrt(p) - 1) + (Math.sqrt(p) - 1)) {
            dir = 'W';
        } else if (i < Math.sqrt(p) * (Math.sqrt(p) - 1)) {
            // console.log(j, 'one', (Math.sqrt(p) - 1) + (Math.sqrt(p) - 1))
            // console.log(Math.sqrt(p) * (Math.sqrt(p) - 1), 'two')
            dir = 'N';
        } else {
            dir = 'E';
        }
        // console.log(j, i, 'ji')
        // console.log (Math.sqrt(p) - k + 'hoge')
        // console.log((Math.sqrt(p) - k) + (Math.sqrt(p) - 1) + 'hogek');
        // console.log(p, i, j, 'p i j')

    }
    
    console.log(x, y);
}) ;

このコード自体は、一番初めに書いたもので、とりあえず答えがあってればいいやって感じで解いた。

(謎の変数 k とか残ってるし(´;ω;`))

コメントアウトは、途中で値を確認するためのもの。

ctrl + / でコメントアウトしたり解除したりして、実行を繰り返して確認しながら解いた。単体テスト的な?

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?