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 の「いびつなひとりリバーシ」の問題に挑戦!


🧩 問題概要

盤面とマスの種類

  • H × W の盤面が与えられる
  • 各マスは次のいずれか
    • '*':すでに置かれている自分の石
    • '.':何も置かれていないマス
    • '#':穴の空いているマス(通過・反転不可)

操作内容(これを N 回繰り返す)

  • あらかじめ与えられた座標 (Y_i, X_i) に石を置く
    • そのマスは必ず '.'(空マス)
  • 石を置いた直後、その石を起点に、縦・横・斜めの8方向 に探索を行う
  • ある方向について次を満たした場合のみ石を置ける
    • '#' を含まない連続したマス列
    • 自分の石 '*' が存在する(=はさめている)
  • はさめた場合
    • 間にあるマスをすべて '*' に変える
  • 新しく石を置いた結果、さらに置ける状態になっても
  • その操作はそこで終了

やること

  • 上記の操作を N 回すべて順番に実行する
  • 最終的な盤面を H 行で出力する



入力例:

3 3 1 // H W N
..*
...
*.*
0 0 // Y_i X_i

出力例:

***
**.
*.*






✅ OK例:

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

const lines = [];

// 入力を1行ずつ配列に保存
rl.on('line', (line) => lines.push(line));

rl.on('close', () => {
    // H:高さ, W:幅, N:操作回数
    const [H, W, N] = lines[0].split(' ').map(Number);

    // 盤面を2次元配列に変換
    const grid = lines.slice(1, H + 1).map(row => row.split(''));

    // 石を置く座標リスト
    const stones = lines.slice(H + 1).map(row => row.split(' ').map(Number));
    
    // 8方向(縦・横・斜め)
    const directionList = [
        [-1, 0],  // 上
        [-1, 1],  // 右上
        [0, 1],   // 右
        [1, 1],   // 右下
        [1, 0],   // 下
        [1, -1],  // 左下
        [0, -1],  // 左
        [-1, -1]  // 左上
    ];
    
    // 各操作ごとに処理
    for (const stone of stones) {
        const [Y, X] = stone;

        // 穴(#)でなければ石を置く
        if (grid[Y][X] !== '#') grid[Y][X] = '*';
        else continue;
        
        // 8方向をチェック
        for (const direction of directionList) {
            const [dy, dx] = direction;
            let ny = Y + dy;
            let nx = X + dx;
            
            const path = []; // 挟めるか確認するための通過マス
            
            // 盤面内を進む
            while (0 <= ny && ny < H && 0 <= nx && nx < W) {
                if (grid[ny][nx] === '#') break; // 穴があれば失敗
                if (grid[ny][nx] === '*') {
                    // 自分の石で挟めたら、通過したマスを石に変える
                    for (const [py, px] of path) {
                        grid[py][px] = '*';
                    }
                    break;
                }
                // 空マスを記録して次へ
                path.push([ny, nx]);
                ny += dy;
                nx += dx;
            }
        }
    }
    
    // 最終盤面を出力
    grid.forEach(g => console.log(g.join('')));
});

🔍 コード全体の流れ

  • 最初の行から
    • 盤面サイズ H, W
    • 操作回数 N を取得
  • 次の H 行を、文字の2次元配列 grid(盤面)に変換
  • 残りの行を、石を置く座標 (Y, X) の配列として取得
  • 各操作について:
    • 指定マスに * を置く(穴 # ならスキップ)
    • 8方向それぞれに石の位置から探索
      • # が出たらその方向は失敗
      • * が出たら、その間に通ったマスをすべて * に変える
  • 全操作終了後、盤面をそのまま出力






🗒️ まとめ


🔹 1. 「1操作 = 完結した処理」を `N` 回回す - 1回の処理ロジックをそのまま `for` ループで包む - 状態(盤面)は 累積的に更新 される

🔹 2. 8方向探索ロジックの再利用

  • Step6 で作ったロジックをそのまま使い回せる:
    • 方向リスト
    • while による直線探索
    • path による一時保存 

→ 問題がレベルアップしても、「考え方」は変わっていないことが分かる

🔹 3. 途中で確定させない設計の重要性

  • 通過マスは一旦 path に保存
  • '*' に到達したときだけ反映
  • 失敗時('#' や盤面外)は何もしない

→ ロジックが安全・シンプルになる

🔹 4. 問題文の「連鎖しない」に注意

  • ひっくり返した結果さらに石をはさめる状況が生まれても、再探索しない
  • 「1回の操作で見るのは、置いた石起点のみ」

🔹 5. 入力処理の整理

  • 入力を分ける:
    • 盤面情報
    • 操作情報
  • slice() の使い分けで問題文どおりの構造をそのままコードに反映
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?