今回は paiza の「リバーシの操作(斜め)」の問題に挑戦!
問題概要
- 縦
H行、横W列の盤面が与えられる - 盤面には
-
'*':すでに置かれている自分の石 -
'.':何も置かれていないマス
が存在する
-
- 指定されたマス (
Y,X) は必ず'.'であり、ここに 新しく石を 1 つ置く
操作ルール(斜め方向のはさみ)
- 石を
(Y, X)に置いたあと、 - 斜め 4 方向(右上・右下・左下・左上)をそれぞれ調べる
- ある方向について、
'*' → '.' → '.' → … → '*'
のように
斜め方向で両端が'*'ではさまれている場合、
その間の'.'をすべて'*'にする - 途中で
- 盤面の外に出る
-
'*'に到達できない
場合は、その方向は何もしない
- 新たに置いた石によってさらに置ける場合があっても操作は 1 回で終了(連鎖処理なし)
操作後の盤面を 上から順に H 行出力 する
入力例:
3 3 0 0
..*
...
*.*
出力例:
*.*
.*.
*.*
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', (line) => lines.push(line));
rl.on('close', () => {
const [H, W, Y, X] = lines[0].split(' ').map(Number);
const grid = lines.slice(1).map(row => row.split(''));
const directionList = [[-1, 1], [1, 1], [1, -1], [-1, -1]];
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] === '*') {
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行ずつ読み込み、配列
linesに保存する - 入力1行目から
- 盤面の高さ
H - 幅
W - 石を置く座標
Y, X
を取得する
- 盤面の高さ
- 続く
H行を読み取り、2次元配列gridとして盤面を作成する - 斜め4方向(右上・右下・左下・左上)を (
dy,dx) の配列directionListとして定義する - 指定されたマス
(Y, X)に石'*'を置く - 各斜め方向について次の処理を行う
-
(Y, X)の1マス先から探索を開始する - 通過したマスを
pathに順番に記録する - 進んだ先で
'*'が見つかったら-
pathに記録したマスをすべて'*'にする(はさみ成立)
-
- 盤面の外に出た場合は、その方向は何もしない
-
- すべての方向の処理が終わったら更新後の盤面を1行ずつ出力する
📝まとめ
- Step2(縦横)と ロジックはほぼ同じ
違いは「方向が斜め」なだけ - 斜め方向は
(dy, dx)で表現できる- (-1, 1):右上
- (1, 1):右下
- (1, -1):左下
- (-1, -1):左上
- 処理の流れ(1方向あたり)
-
(Y, X)の1マス先から探索開始 - 通過したマスを
pathに保存 -
'*'に到達したら
→path内のマスをすべて'*'にする - 盤面外に出たら
→ その方向は何もしない
-
- 最初に
(Y, X)を'*'にしてから探索する