3から続きます
※スキルチェック問題ではありません。
規約により公式の解答コードそのままはよろしくないので、
オリジナルのコードにしています。
詳しくはコチラ
なるべくわかりやすい解説を付けました。
マップの判定・縦横
1:移動が可能かの判定・方角 (paizaランク B 相当)
マップの行数 H と列数 W , 障害物を ‘#’ で、移動可能な場所を ‘.’ で表した H 行 W 列のマップ S_1 … S_H が与えられます。
続けて現在の座標 sy , sx ,1マス移動する方角 m が与えられるので、移動が可能かどうかを判定してください。
移動が可能であるということは、以下の図の通り
「移動先が障害物でない かつ 移動先がマップの範囲外でない」
ということを意味します。
なお、マスの座標系は左上端のマスの座標を ( y , x ) = ( 0 , 0 ) とし、
下方向が y 座標の正の向き、右方向が x 座標の正の向きとします。
- 入力される値
H W sy sx m S_0 ... S_(H-1)
- ・ 1 行目にはマップの行数を表す整数 H , マップの列数を表す整数 W , 現在の y, x 座標を表す sy sx , 1 マス移動する方角 m が与えられます。
・ 続く H 行のうち i 行目 (0 ≦ i < H) には、マップの i 行目の文字をまとめた文字列 S_i が与えられ、 S_i の j 文字目は、マップの i 行目の j 列目に書かれている文字を表します。(0 ≦ j < W)入力値最終行の末尾に改行が1つ入ります。
- 期待する出力
- 移動が可能である場合 “Yes” を、不可能である場合 “No” を出力してください。
Yes
または
No
条件
すべてのテストケースにおいて、以下の条件をみたします。 ・ 1 ≦ H, W ≦ 20 ・ 0 ≦ sy < H , 0 ≦ sx < W ・ S_i は W 文字の文字列 ・ マップ上の(sy, sx)のマスは必ず '.' ・ S の各文字は '.' または '#' ・ m は、N, S, E, W のいずれかであり、それぞれ 北・南・東・西 を意味します。
- 入力例1
3 3 1 1 E ..# ..# ...
- 出力例1
No
- 入力例2
9 2 4 0 S #. #. .. ## .. .. .# .. .#
- 出力例2
Yes
解答と解説(入力例1で行います)
#方角のみ文字列なので、それ以外を数値として変数に代入して、mに文字列として代入する
h,w,y,x,m = gets.split.map.with_index { |val, i| i == 4 ? val : val.to_i }
#盤面の情報をバラバラにして代入する 結果→[[".", ".", "#"], [".", ".", "#"], [".", ".", "."]]
chart = h.times.map { gets.chomp.chars}
#移動操作した時の座標の移動パターンを作成する。
direction = { N: [-1, 0], S: [1, 0], E: [0, 1], W: [0, -1] }
#入力例1の場合mがEなので[0, 1]yとxに加算する
y += direction[m.to_sym][0]
x += direction[m.to_sym][1]
#画面外だとアウトなのでyとxが0以上でyがh未満xがw未満であることを記述する
#移動後の座標の現在地(chart[y][x])が"."であることを満たしたときに"Yes"
if y >= 0 && x >= 0 && y < h && x < w && chart[y][x] == "."
puts "Yes"
それ以外を"No"と出力する
else puts "No"
end
2:移動が可能かの判定・方向 (paizaランク B 相当)
マップの行数 H と列数 W , 障害物を ‘#’ , 移動可能な場所を ‘.’ で表した H 行 W 列のマップ S_1 … S_H が与えられます。
続けて現在の座標 sy , sx , 現在向いている方角 d , 1マス移動する方向 m が与えられるので、移動が可能かどうかを判定してください。
移動が可能であるということは、以下の図の通り
「移動先が障害物でない かつ 移動先がマップの範囲外でない」
ということを意味します。
なお、マスの座標系は左上端のマスの座標を ( y , x ) = ( 0 , 0 ) とし、
下方向が y 座標の正の向き、右方向が x 座標の正の向きとします。
- 入力される値
H W sy sx d m S_0 ... S_(H-1)
- ・ 1 行目にはマップの行数を表す整数 H , マップの列数を表す整数 W , 現在の y, x 座標を表す sy sx , 現在向いている方角 d , 1 マス移動する方向 m が与えられます。
・ 続く H 行のうち i 行目 (0 ≦ i < H) には、マップの i 行目の文字をまとめた文字列 S_i が与えられ、 S_i の j 文字目は、マップの i 行目の j 列目に書かれている文字を表します。(0 ≦ j < W) - 入力値最終行の末尾に改行が1つ入ります。
- 期待する出力
- 移動が可能である場合 “Yes” を、不可能である場合 “No” を出力してください。
Yes
または
No
- 条件
すべてのテストケースにおいて、以下の条件をみたします。 ・ 1 ≦ H, W ≦ 20 ・ 0 ≦ sy < H , 0 ≦ sx < W ・ S_i は W 文字の文字列 ・ マップ上の(sy, sx)のマスは必ず '.' ・ S の各文字は '.' または '#' ・ d は、N, S, E, W のいずれかであり、それぞれ 北・南・東・西 を意味します。 ・ m は、L, R のいずれかであり、それぞれ 左・右 を意味します。
- 入力例1
2 6 0 4 E L ####.. ##..#.
- 出力例1
No
- 入力例2
7 9 6 0 S R ..#.#..## ..#..#... #.......# #.#...### #.##....# .....#... ..##..#.#
- 出力例2
No
解答と解説(入力例1で行います)
#dとmが文字列なので、それ以外を数値として変数に代入して、dとmに文字列として代入する
h,w,y,x,d,m = gets.split.map.with_index { |val, i| i >= 4 ? val : val.to_i }
#盤面の情報をバラバラにして代入する 結果→[["#", "#", "#", "#", ".", "."], ["#", "#", ".", ".", "#", "."]]
chart = h.times.map { gets.chomp.chars}
#Rが来たときの移動パターンを設定する
operateR = { N: [0, 1], S: [0, -1], E: [1, 0], W: [-1, 0] }
#Lが来たときの移動パターンを設定する
operateL ={ N: [0, -1], S: [0, 1], E: [-1, 0], W: [1, 0] }
#入力例1の場合mがLで向いている方向がEなので[-1, 0]yとxに加算する
if m == "R"
y += operateR[d.to_sym][0]
x += operateR[d.to_sym][1]
elsif m == "L"
y += operateL[d.to_sym][0]
x += operateL[d.to_sym][1]
end
#画面外だとアウトなのでyとxが0以上でyがh未満xがw未満であることを記述する
#移動後の座標の現在地(chart[y][x])が"."である条件を満たしたときに"Yes"
if y >= 0 && x >= 0 && y < h && x < w && chart[y][x] == "."
puts "Yes"
else puts "No"
end
※移動後の座標が[-1,4]で画面外なので”No”が出力された
3:移動が可能かの判定・複数回の移動 (paizaランク B 相当)
マップの行数 H と列数 W , 現在の座標 sy , sx , 移動の回数 N が与えられます。
続けて、障害物を ‘#’ で、移動可能な場所を ‘.’ で表した H 行 W 列 のマップ S_1 … S_H と N 回の移動の向き d_1 … d_N が与えられます。
移動者ははじめ北を向いています。移動者は、1 回の移動で次の行動を行います。
「移動の向きに方向転換したのち、1 マス進む。」
各移動が可能である場合、移動後の y , x 座標を出力してください。
移動が可能でない場合、移動後の座標を出力する代わりに “Stop” を出力して、以降の移動を打ち切ってください。
各移動が可能であるということは、以下の図の通り
「移動先が障害物でない かつ 移動先がマップの範囲外でない」
ということを意味します。
なお、マスの座標系は左上端のマスの座標を ( y , x ) = ( 0 , 0 ) とし、
下方向が y 座標の正の向き、右方向が x 座標の正の向きとします。
右に移動
- 入力される値
H W sy sx N S_0 ... S_(H-1) d_1 ... d_N
- ・ 1 行目にはマップの行数を表す整数 H , マップの列数を表す整数 W , 現在の y, x 座標を表す sy sx , 移動する回数 N が与えられます。
・ 続く H 行のうち i 行目 (0 ≦ i < H) には、マップの i 行目の文字をまとめた文字列 S_i が与えられ、 S_i の j 文字目は、マップの i 行目の j 列目に書かれている文字を表します。(0 ≦ j < W)
・ 続く N 行のうち i 行目 (1 ≦ i ≦ N) には、i 回目の移動の向き d_i が与えられます。
入力値最終行の末尾に改行が1つ入ります。
- 期待する出力
- M (1 ≦ M ≦ N) 行の出力
・ k (1 ≦ k ≦ M) 回目の移動後の y , x 座標、y_k, x_k を出力してください。
・ ただし、M 回目で移動しきれない場合、”Stop” を出力してください。y_1 x_1 ... y_k x_k ... y_M x_M
または
y_1 x_1 ... y_k x_k ... y_(M-1) x_(M-1) Stop
- 条件
すべてのテストケースにおいて、以下の条件をみたします。 ・ 1 ≦ H, W ≦ 20 ・ 1 ≦ N ≦ 100 ・ 0 ≦ sy < H , 0 ≦ sx < W ・ S_i は W 文字の文字列 ・ マップ上の(sy, sx)のマスは必ず '.' ・ S_i の各文字は '.' または '#' ・ d_i は、L, R のいずれかであり、それぞれ 左・右 を意味します。
- 入力例1
7 3 2 1 5 ..# ... ... ... ..# .#. ##. L L L L L
- 出力例1
2 0 3 0 3 1 2 1 2 0
- 入力例2
7 11 1 5 43 .##........ .#......##. .#....#...# .###......# #......###. ..#....###. #.#........ L L R L R L R L L R L R L L L L R R R L R L R L L R L L R L R L R R R R L R L L L R R
- 出力例2
1 4 2 4 2 3 Stop
解答と解説(入力例2で行います)
直感的でわかりやすいけどあまりよろしくないかも
#数値として各変数に代入する
h,w,y,x,n = gets.split.map(&:to_i)
#盤面の情報をバラバラにして代入する 実行 → [[".", "#", "#", ".", ".", ".", ".", ".", ".", ".", "."], [".", "#", ".", ".", ".", ".", ".", ".", "#", "#", "."], [".", "#", ".", ".", ".", ".", "#", ".", ".", ".", "#"], [".", "#", "#", "#", ".", ".", ".", ".", ".", ".", "#"], ["#", ".", ".", ".", ".", ".", ".", "#", "#", "#", "."], [".", ".", "#", ".", ".", ".", ".", "#", "#", "#", "."], ["#", ".", "#", ".", ".", ".", ".", ".", ".", ".", "."]]
chart = h.times.map { gets.chomp.chars}
# Rが来たときの移動パターンを設定する
operateR = { N: [0, 1], S: [0, -1], E: [1, 0], W: [-1, 0] }
#Lが来たときの移動パターンを設定する
operateL ={ N: [0, -1], S: [0, 1], E: [-1, 0], W: [1, 0] }
#最初は北を向いているのでdに”N”を代入する
d = "N"
#コマンドがn回あるのでn回繰り返す
n.times do
#RかLの入力値を受け取り代入する
command = gets.chomp
#自分が向いている向きdとコマンドL,Rによってyとxを加算する
if command == "R"
y += operateR[d.to_sym][0]
x += operateR[d.to_sym][1]
elsif command == "L"
y += operateL[d.to_sym][0]
x += operateL[d.to_sym][1]
end
#自分の向いている向きとコマンドのLかRかで自分の向いている向きを変更する。
if d == "N" && command == "L" || d == "S" && command == "R"
d = "W"
elsif d == "W" && command == "L" || d == "E" && command == "R"
d = "S"
elsif d == "E" && command == "L" || d == "W" && command == "R"
d = "N"
elsif d == "S" && command == "L" || d == "N" && command == "R"
d = "E"
end
#画面外だとアウトなのでyとxが0以上でyがh未満xがw未満であることを記述する
#移動後の座標の現在地(chart[y][x])が"."である条件を満たしたときに"Yes"
if y >= 0 && x >= 0 && y < h && x < w && chart[y][x] == "."
puts y.to_s + " " + x.to_s
条件を満たさなかったときに”Stop”を出力して繰り返しを終わらせる(break)
else puts "Stop"
break
end
end
別解
#数値として各変数に代入する
h, w, y, x, n = gets.split.map(&:to_i)
#盤面の情報をバラバラにして代入する 実行 → [[".", "#", "#", ".", ".", ".", ".", ".", ".", ".", "."], [".", "#", ".", ".", ".", ".", ".", ".", "#", "#", "."], [".", "#", ".", ".", ".", ".", "#", ".", ".", ".", "#"], [".", "#", "#", "#", ".", ".", ".", ".", ".", ".", "#"], ["#", ".", ".", ".", ".", ".", ".", "#", "#", "#", "."], [".", ".", "#", ".", ".", ".", ".", "#", "#", "#", "."], ["#", ".", "#", ".", ".", ".", ".", ".", ".", ".", "."]]
chart = h.times.map { gets.chomp.chars }
#移動するパターンを作成する 北 東 南 西 の順番
direction = [[-1, 0], [0, 1], [1, 0], [0, -1]]
#状態を定義する。最初は0
current = 0
#コマンドがn回あるのでn回繰り返す
n.times do
#RかLの入力値を受け取り代入する
d = gets.chomp
#Lの時−1してRのときに+1する
d == "L" ? current -= 1 : current += 1
y += direction[current % 4][0]
x += direction[current % 4][1]
if y >= 0 && x >= 0 && y < h && x < w && chart[y][x] == "."
puts y.to_s + " " + x.to_s
# 条件を満たさなかったときに”Stop”を出力して繰り返しを終わらせる(break)
else puts "Stop"
break
end
end
入力例2
1ループ目
最初の状態はcurrent = 0でコマンドがL、yとx が[1,5]
currentが -1になり
-1 % 4 は 3なので
direction[3]は[0,-1]
yとxに [0,-1]を加算して
yとx が[1,4]
2ループ目
最初の状態はcurrent = -1でコマンドがL、yとx が[1,4]
currentが -2になり
-2 % 4 は 2なので
direction[2]は[1,0]
yとxに [1,0]を加算して
yとx が[2,4]
3ループ目
最初の状態はcurrent = -2でコマンドがR、yとx が[2,4]
currentが -1になり
-1 % 4 は 3なので
direction[3]は[0,-1]
yとxに [0,-1]を加算して
yとx が[2,3]
4ループ目
最初の状態はcurrent = -2でコマンドがL、yとx が[2,3]
currentが -2になり
-2 % 4 は 2なので
direction[2]は[1,0]
yとxに [1,0]を加算して
yとx が[3,4]
移動先が”#”があるので”Stop”を出力してループを抜ける
※ポイント
d == ‘L’ ? current -= 1 : current += 1
でcurrentの値を変えるだけで移動操作が表現できる。
4:移動が可能かの判定・幅のある移動 (paizaランク B 相当)
マップの行数 H と列数 W , 障害物を ‘#’ で移動可能な場所を ‘.’ で表した H 行 W 列のマップ S_1 … S_H , 現在の座標 sy, sx, 移動の回数 N が与えられます。
続けて、 N 回の移動の向き d_1 … d_N と移動するマス数 l_1 … l_N が与えられます。
プレイヤーははじめ北を向いています。
各移動が可能である場合、移動後の y , x 座標 を出力してください。
移動が可能でない場合(移動しきれない場合)、移動できるところまで移動した後の座標を出力した後に “Stop” を出力して、以降の移動を打ち切ってください。
各移動が可能であるということは、以下の図の通り
「今いるマスから移動先のマスまでに障害物がない かつ 移動先がマップの範囲外でない」
ということを意味します。
なお、マスの座標系は左上端のマスの座標を ( y , x ) = ( 0 , 0 ) とし、
下方向が y 座標の正の向き、右方向が x 座標の正の向きとします。
- 入力される値
H W sy sx N S_0 ... S_(H-1) d_1 l_1 ... d_N l_N
- ・ 1 行目にはマップの行数を表す整数 H , マップの列数を表す整数 W , 現在の y, x 座標を表す sy sx , 移動する回数 N が与えられます。
・ 続く H 行のうち i 行目 (0 ≦ i < H) には、マップの i 行目の文字をまとめた文字列 S_i が与えられ、 S_i の j 文字目は、マップの i 行目の j 列目に書かれている文字を表します。(0 ≦ j < W)
・ 続く N 行のうち i 行目 (1 ≦ i ≦ N) には、i 回目の移動の向き d_i と移動するマス数 l_i が与えられます。入力値最終行の末尾に改行が1つ入ります。
- 期待する出力
- M (1 ≦ M ≦ N+1) 行の出力
・ k (1 ≦ k ≦ M) 回目の移動後の y , x 座標、y_k, x_k を出力してください。
・ M 回目で移動しきれない場合、移動できるところまで移動した後の y , x 座標、y_M, x_M を出力した後に “Stop” を出力してください。y_1 x_1 ... y_k x_k ... y_M x_M
または
y_1 x_1 ... y_k x_k ... y_M x_M Stop
- 条件
すべてのテストケースにおいて、以下の条件をみたします。 ・ 1 ≦ H, W ≦ 20 ・ 1 ≦ N ≦ 100 ・ 0 ≦ sy < H, 0 ≦ sx < W ・ 1 ≦ l_i ≦ 20 ・ S_i は W 文字の文字列 ・ マップ上の(sy, sx)のマスは必ず '.' ・ S の各文字は '.' または '#' ・ d_i は、L, R のいずれかであり、それぞれ 左・右 を意味します。
- 入力例1
10 10 6 4 3 ..#.....#. .......... ##.#...... #.##....#. .##.#..... ........#. .#......#. .#........ ...#...... #.#....... L 2 R 1 L 4
- 出力例1
6 2 5 2 5 0 Stop
- 入力例2
15 15 6 4 7 .......#....... ....#.......#.# .......#.....#. .......#.#...#. #......#....... #.........#.... ..............# ..#...#....#..# ............#.. ..#...##......# ##..#..#.#..... #.............. ............#.. ...#........... .#.........#.#. L 4 L 3 R 4 R 5 L 3 L 2 R 1
- 出力例2
6 0 9 0 9 0 Stop
解答と解説
少し無駄な部分があるがとりあえずできたほう
#数値として各変数に代入する
h, w, y, x, n = gets.split.map(&:to_i)
#盤面の情報をバラバラにして代入する
chart = h.times.map { gets.chomp.chars }
#移動するパターンを作成する 北 東 南 西 の順番
direction = [[-1, 0], [0, 1], [1, 0], [0, -1]]
#状態をそれぞれ定義する。最初は0
current,stop = 0,0
#コマンドがn回あるのでn回繰り返す
n.times do
#文字列と数値をそれぞれの変数に代入
d,move = gets.split.map.with_index { |val, i| i == 0 ? val : val.to_i }
#Lの時−1してRのときに+1する
d == 'L' ? current -= 1 : current += 1
#移動する回数繰り返す
move.times do |i|
#currentの状態によってyとxを加算する
y += direction[current % 4][0]
x += direction[current % 4][1]
#画面外だとアウトなのでyとxが0以上でyがh未満xがw未満であることを記述する
#移動後の座標の現在地(chart[y][x])が"."で繰り返しの最後のときに出力
if y >= 0 && x >= 0 && y < h && x < w && chart[y][x] == "."
puts y.to_s + " " + x.to_s if move == i + 1
#画面外や現在地が”#”のとき前の状態に戻してStopを1にして繰り返しを終わらせる
else y -= direction[current % 4][0]
x -= direction[current % 4][1]
stop = 1
break
end
end
# stopが1のときに現在地を出力してから改行して”Stop”を出力して繰り返しを終わらせる
if stop == 1
puts y.to_s + " " + x.to_s + "\n" +"Stop"
break
end
end