今回は paiza の「スライドゲーム」の問題に挑戦!
🧩 問題概要
グリッド
- 縦
H行 × 横W列 のグリッドがある - 各マスの中身は
.(ドット)または# - グリッドは トーラス状(端と端がつながっている)
- 右端の次は左端
- 下端の次は上端
座標
- 上から
i行目 - 左から
j列目 - マスを
(i, j)と表す(1-indexed)
クエリについて
- クエリは
Q個 与えられる - クエリは次の 2 種類のみ
① 1 p(行操作)
- 上から
p行目を - 左に 1 マスずつずらす
- 左にはみ出たマスは 右端に回る
例(横)
abcde → bcdea
② 2 q(列操作)
- 左から
q列目を - 上に 1 マスずつずらす
- 上にはみ出たマスは 下端に回る
例(縦)
a b
b → c
c a
求めるもの
- すべてのクエリを順番どおりに処理した後、最終的なグリッドの状態を出力する
入力例:
3 3 1 // H W Q
.#. // グリッド
#.#
.#.
1 2 // query ← "1 p" or "2 q"
出力例:
.#.
.##
.#.
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
// 入力を1行ずつ配列に格納
rl.on('line', line => lines.push(line));
rl.on('close', () => {
// H: 行数, W: 列数, Q: クエリ数
const [H, W, Q] = lines[0].split(' ').map(Number);
// グリッドを2次元配列として読み込む
const grid = lines.slice(1, H + 1).map(line => line.split(''));
// クエリを数値配列として取得
const query = lines.slice(H + 1).map(q => q.split(' ').map(Number));
// 各クエリを順に処理
for (const q of query) {
// クエリタイプ1:指定行を左に1マスずらす
if (q[0] === 1) {
const row = q[1] - 1; // 0-indexに変換
const left = grid[row][0]; // 左端を退避
for (let i = 0; i < W; i++) {
if (i === W - 1) {
// 最後のマスに元の左端を入れる(トーラス)
grid[row][i] = left;
continue;
}
// 右のマスで上書き
grid[row][i] = grid[row][i + 1];
}
}
// クエリタイプ2:指定列を上に1マスずらす
else {
const col = q[1] - 1; // 0-indexに変換
const top = grid[0][col]; // 上端を退避
for (let i = 0; i < H; i++) {
if (i === H - 1) {
// 最後のマスに元の上端を入れる(トーラス)
grid[i][col] = top;
continue;
}
// 下のマスで上書き
grid[i][col] = grid[i + 1][col];
}
}
}
// 最終的なグリッドを出力
grid.forEach(g => console.log(g.join('')));
});
🔍コードの流れ
- 標準入力を1行ずつ読み込み、配列
linesに格納する - 入力の1行目から
- グリッドの行数
H - 列数
W - クエリ数
Q
を取得する
- グリッドの行数
- 続く
H行を読み取り、グリッドを 2次元配列gridとして作成する - 残りの行をクエリとして読み取り、数値配列に変換する
- クエリを先頭から順に処理する
- クエリタイプ
1- 指定された行を左に1マスずつシフトする
- はみ出た左端のマスは右端に回す(トーラス)
- クエリタイプ
2- 指定された列を上に1マスずつシフトする
- はみ出た上端のマスは下端に回す(トーラス)
- クエリタイプ
- すべてのクエリ処理後、完成したグリッドを行ごとに出力する
📝まとめ
実装の考え方
- グリッドは 2次元配列で管理すると扱いやすい
- クエリごとに
- 行なら 横方向
- 列なら 縦方向
を直接ずらす
トーラス処理のコツ
- ずらす前に
- 行なら「左端」
- 列なら「上端」
を 一時保存
- ずらした後、最後のマスに戻す