へび (paizaランク A 相当)
JavaScriptで解いてみました。いくつか解答例を載せたので、理解しやすいところ、しっくりくるところを参考にしていただけたらと思います。
解答例
はじめに時刻tと右左dの配列を作っています。
JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const [H,W,sy,sx,N] = lines[0].split(" ").map(Number);
//マップ
const S = lines.slice(1, H + 1).map(line => line.split(""));
const T = [];//時刻t
const D = [];//右左d
for (let i = 1; i <= N; i++) {
const [t, d] = lines[i + H].split(" ");
T.push(Number(t));
D.push(d);
}
const direct = ['N', 'E', 'S', 'W'];
let now = 0;//directの添字
//スタート位置
let [y, x] = [sy, sx];
S[y][x] = "*";
let j = 0;//Tの添字
for (let time = 0; time < 100; time++) {
//時刻tで方向転換
if (time === T[j]) {
if (D[j] === "L") {
now = (now + 3) % 4;
} else {
now = (now + 1) % 4;
}
j++;//Tの次を準備
}
//移動
if (direct[now] === 'N') {
y -= 1;
} else if (direct[now] === 'E') {
x += 1;
} else if (direct[now] === 'S') {
y += 1;
} else if (direct[now] === 'W') {
x -= 1;
}
//移動先が、マップ上かつ障害物がない,自分の体もない、なら進める
if (0 <= y && y < H && 0 <= x && x < W && S[y][x] === ".") {
S[y][x] = "*";
} else {
break;
}
}
console.log(S.map(row => row.join("")).join("\n"));
解答例(C++の場合を参考)
移動量の関数moveを定義しています。
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const [H,W,sy,sx,N] = lines[0].split(" ").map(Number);
const S = lines.slice(1, H + 1).map(line => line.split(""));
const td = [];////時刻t右左d
for (let i = 1; i <= N; i++) {
const [t, d] = lines[i + H].split(" ");
td.push([Number(t), d]);
}
let mcount = 0;//td添字
const direct = ['N', 'E', 'S', 'W'];
let dcount = 0;//directの添字
const move = (D, M) => {//D方角NESW、M左右ストレート
//M=Rのとき
let LR = 1;
add = 1;
if (M === 'S') {//M=S:ストレート,方向転換なしの時、真っ直ぐ
//移動量
if (D === 'N') {
y--;
} else if (D === 'S') {
y++;
} else if (D === 'E') {
x++;
} else {
x--;
}
} else { //方向転換あり
//Lのとき
if (M === "L") {
LR = -1;
add = 3;
}
//移動量
if (D === 'N') {
x += LR;
} else if (D === 'S') {
x -= LR;
} else if (D === 'E') {
y += LR;
} else {
x -= LR;
}
dcount += add;//方向転換 次のために
}
};
//スタート位置
let [y, x] = [sy, sx];//const sy,sxなのでy,xに置換
S[y][x] = "*";
for (let time = 0; time < 100; time++) {
//時刻tで方向転換
if (time === td[mcount][0]) {//time=t
//方向転換の時刻になったら左右についての move を呼び出し
move(direct[dcount % 4], td[mcount][1]);//(D, M=m)
mcount++;//次のtdを準備
//方向転換なし
} else {
move(direct[dcount % 4], 'S');//ストレートS,方向転換なし、真っ直ぐ
}
//移動先が、マップ上かつ障害物がない,自分の体もない、なら進める
if (0 <= y && y < H && 0 <= x && x < W && S[y][x] === ".") {
S[y][x] = "*";
} else {
break;
}
}
console.log(S.map(row => row.join("")).join("\n"));
解答例(Python3の場合を参考)
time_lrで時刻t右左dをまとめた配列を作っています。
JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const [H,W,sy,sx,N] = lines[0].split(" ").map(Number);
const S = lines.slice(1, H + 1).map(line => line.split(""));
const time_lr = [];//時刻t右左d
for (let i = 1; i <= N; i++) {
const [t, d] = lines[i + H].split(" ");
time_lr.push([t, d]);
}
let time_index = 0;//time_lrの添字
const direct = ['N', 'E', 'S', 'W'];
let now = 0;//directの添字
//スタート位置
let [y, x] = [sy, sx];
S[y][x] = "*";
for (let time = 0; time < 100; time++) {
//時刻tで方向転換
if (time_index < N && time === time_lr[time_index][0]) {
time_index += 1;//次を準備
if (time_lr[time_index] === "L") {
now = (now + 3) % 4;
} else {
now = (now + 1) % 4;
}
}
//移動
if (direct[now] === 'N') {
y -= 1;
} else if (direct[now] === 'E') {
x += 1;
} else if (direct[now] === 'S') {
y += 1;
} else if (direct[now] === 'W') {
x -= 1;
}
//移動先が、マップ上かつ障害物がない,自分の体もない、なら進める
if (0 <= y && y < H && 0 <= x && x < W && S[y][x] === ".") {
S[y][x] = "*";
} else {
break;
}
}
console.log(S.map(row => row.join("")).join("\n"));
解答例(Ruby の場合参考)
方向の配列move = [[-1, 0], [0, 1], [1, 0], [0, -1]]
を使っています。
JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
const [H,W,sy,sx,N] = lines[0].split(" ").map(Number);
const board = lines.slice(1, H + 1).map(line => line.split(""));
const turns = lines.slice(H + 1).map(line => line.split(" ").map((val, i) =>
i === 0 ? Number(val) : val));//時刻t右左d
const move = [[-1, 0], [0, 1], [1, 0], [0, -1]];
let now = 0;//moveの添字
//スタート位置
let [y, x] = [sy, sx];//const sy,sxなのでy,xに置換
board[y][x] = "*";
let [t, d] = turns.shift();
for (let time = 0; time < 100; time++) {
//時刻tで方向転換
if (t === time) {//time=t
if (d === 'L') {
now += 3;
} else {
now += 1;
}
if (turns.length > 0) {
[t, d] = turns.shift();
}//次のturndを準備
}
//移動
ny = y + move[now % 4][0];
nx = x + move[now % 4][1];
//移動先が、マップ上かつ障害物がない,自分の体もない、なら進める
if (!(0 <= y && y <= H - 1 && 0 <= x && x <= W - 1 &&
board[ny][nx] !== "#" && board[ny][nx] !== "*")) {
break;
}
[y, x] = [ny, nx];
board[y][x] = '*';
}
console.log(board.map(row => row.join("")).join("\n"));
解答例(python3の場合を参考)2
はじめにtime_lrで時刻と右左をまとめた配列を作っています。
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
let [H,W,sy,sx,N] = lines[0].split(" ").map(Number);
const s = lines.slice(1,H + 1).map((line) => line.split(""));
const time_lr = lines.slice(H + 1, H + N + 1).map(line => line.split(" "));
let time_index = 0; //方向転換の回数
const directions = ["N","E","S","W"];
let now_direction = 0;
s[sy][sx] = '*';
for (let t_now = 0; t_now <= 99; t_now++) {
//方向転換の時刻になったら
if (time_index < N && String(t_now) === time_lr[time_index][0]) {
const d = time_lr[time_index][1];
time_index += 1;
//方向転換
if (d === "L") {
now_direction = (now_direction + 3) % 4;
} else {
now_direction = (now_direction + 1) % 4;
}
}//if time_index
// 1 マス身体を伸ばす。
if (directions[now_direction] === "N") {
sy -= 1;
} else if (directions[now_direction] === "E") {
sx += 1;
} else if (directions[now_direction] === "S") {
sy += 1;
} else if (directions[now_direction] === "W") {
sx -= 1;
}
//移動できるようなら s[sy][sx] = "*" とマスを書き換え、
//できないようならループを抜けます。
if (sx < 0 || W <= sx || sy < 0 || H <= sy || s[sy][sx] !== ".") {
break;
} else {
s[sy][sx] = '*';
}
}//for t_now
//マップを出力
console.log(s.map(elm => elm.join("")).join("\n"));
解答例
蛇が行動100回するループの中で、方向転換をするかforループで調べています。
JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//マップの行数 H と列数 W
//現在の座標 sy , sx , 方向転換の回数 N
const [H,W,sy,sx,N] = lines[0].split(" ").map((v) => Number(v));
const map = lines.slice(1,H + 1).map((line) => line.split(""));
//現在の y, x 座標
let [y,x] = [sy,sx];
map[y][x] = '*';
//へびははじめ北を向いています。
const directions = ["N","E","S","W"];
let now_direction = 0; //向きを決めるインデックス
//時刻 0 から 99 までの間、へびは各時刻に次の行動を最大 100 回とります。
let stop = false; //途中で止まったか判定
for (let time = 0; time <= 99; time++) {
//方向転換をおこなう時刻の場合、
//指定の向きに方向転換したのち 1 マス身体を伸ばす。
//方向転換を行う時刻か調べる
for (let turn = 1; turn <= N; turn++) {
//方向転換をおこなう時刻 t_i と方向転換の向き d_i
const t = Number(lines[H + turn].split(" ")[0]);
const d = lines[H + turn].split(" ")[1];
//もし方向転換を行う時刻ならば
if (time === t) {
//方向転換をする
if (d === "L") {
now_direction = (now_direction + 3) % 4;
break;
} else {
now_direction = (now_direction + 1) % 4;
break;
}
}//if time=t
} //for turn 方向転換完了
// 1 マス身体を伸ばす。
if (directions[now_direction] === "N") {
y -= 1;
} else if (directions[now_direction] === "E") {
x += 1;
} else if (directions[now_direction] === "S") {
y += 1;
} else if (directions[now_direction] === "W") {
x -= 1;
}
//移動先がマップの範囲外
if (x < 0 || W <= x || y < 0 || H <= y) {
stop = true;
break;
//移動先が障害物か自分の身体
} else if (map[y][x] === "#" || map[y][x] === '*') {
stop = true;
break;
//移動終了時にへびの体のあるマスを '*' に
} else {
map[y][x] = '*';
}
//止まったらfor_timeループ抜ける
if (stop) break;
} //for time
//マップを出力
console.log(map.map(elm => elm.join("")).join("\n"));