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


🧩 問題概要

  • H × W の盤面が与えられる
  • 盤面には次の4種類のマスがある
    • '*':すでに置かれている自分の石
    • '.':何もないマス
    • '#':穴の空いているマス(通過不可)
    • '!':今回、新しく石を置くマス(1つだけ)

プレイヤーの操作ルール

  • '!' のマスに 石 '*' を1つ置く
  • その石を起点にして縦・横・斜めの8方向 に探索を行う
  • ある方向について次を満たす場合、石を置ける
    • 新しく置いた石 '*' と既存の石 '*' によって、穴 '#' を含まない連続したマス をはさめている
  • はさめた場合
    → その間にあるマスをすべて '*' にする
  • 新たに石を置いた結果、さらに置ける場合があっても追加の操作は行わない(1回で終了)

最終的にやること

  • 上記の操作を 1回だけ 行ったあとの盤面を H 行でそのまま出力する



入力例:

5 5
*.*.*
.....
*#!.*
...#*
*.***

出力例:

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






✅OK例:

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

const lines = [];

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

rl.on('close', () => {
    const [H, W] = lines[0].split(' ').map(Number);
    const grid = lines.slice(1).map(row => row.split(''));
    
    // 方向リスト
    const directionList = [
        [-1, 0], // 上
        [-1, 1], // 右上
        [0, 1],  // 右
        [1, 1],  // 右下
        [1, 0],  // 下 
        [1, -1], // 左下
        [0, -1], // 左
        [-1, -1] // 左上
    ];
    
    // 石を置く位置
    let X;
    let Y;
    
    LABEL:
    for (let y = 0; y < H; y++) {
        for (let x = 0; x < W; x++) {
            if (grid[y][x] === '!') {
                X = x;
                Y = y;
                break LABEL;
            }
        }
    }
    
    // 石を置く
    grid[Y][X] = '*';
    
    // ひっくり返す
    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('')));
});

🔍 コードの流れ

  1. 標準入力を1行ずつ読み込み、配列 lines に保存する
  2. 1行目から盤面サイズ H, W を取得する
  3. 続く H 行から盤面を読み込み、2次元配列 grid を作成する
  4. 縦・横・斜めの 8方向 を (dy, dx) の配列 directionList として定義する
  5. 盤面全体を走査し、石を置くマス '!' の座標 (Y, X) を見つける
  6. '!' の位置に石 '*' を置く
  7. 各方向について次の処理を行う
    • (Y, X) の1マス先から探索を開始する
    • 通過したマスを path に順番に保存する
    • 探索中に
      • '#' に当たったら → その方向は失敗
      • '*' に当たったら → はさみ成功
        path 内のマスをすべて '*' にする
    • 盤面の外に出たら → その方向は何もしない
  8. 8方向すべての処理が終わったら、更新後の盤面を1行ずつ出力する






📝まとめ

🔹 1. 2次元配列の基本操作

  • 入力を 2次元配列(配列の配列) に変換する
  • (y, x) 座標でマスを扱う

🔹 2. 方向による探索

  • 8方向を (dy, dx) の 配列 で管理することで、同じロジックを for文1本で回せる
  • 条件分岐を増やさず、実装をシンプルにできる

🔹 3. 「はさめたらひっくり返す」の考え方

  • すぐに盤面を書き換えない
  • まず path に通過したマスを保存
  • 最後に '*' に当たったときだけ反映
    → 失敗時に元に戻す必要がない

🔹 4. 探索の終了条件を明確にする

  • 盤面外に出たら終了
  • '#' に当たったら失敗で終了
  • '*' に当たったらひっくり返して終了
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?