メモがてらの投稿です。
よく、プログラミング問題を解く時に、x、y座標を使って解くやつありますよね。
以下みたいな感じで、あーだこーだするやつです。(雑
# #を囲うにはいくつの柵が必要?みたいな問題だとして
# 横の数と縦の数が宣言されて
6 4
# 1列ずつ値がくる
####..
..#.#.
#.#.#.
.##..#
最初、x、y座標使ってなんなん、どうやって求めるんや、、意味不...と思ってましたが、
ちょっとずつ紐解けてきました。
今回は、自分なりにx、y座標の求め方やそれを使った応用などをまとめました。
まだまだ自分も学習中なので、よりよい方法などございましたらコメントいただけると幸いです!
なお、今回はrubyを使って記述しています。
x、y座標の求め方
結論、配列を二重にし、ループ処理を使います。
こんな感じ。
fields = [
['#', '#', '#', '#', '.', '.'],
['.', '.', '#', '.', '#', '.'],
['#', '.', '#', '.', '#', '.'],
['.', '#', '#', '.', '.', '#'],
]
fields.each_with_index do |field, y|
field.each_with_index do |f, x|
end
end
こうすることで、ループを使い添字を取得できます。
処理を説明していくと、
まず1回目のループ処理でfields内の各配列の添字を取得できます。
fields.each_with_index do |field, y|
次に、各配列をさらにループします。
同様にこちらも、添字を取得できます。
field.each_with_index do |f, x|
これらを使って、#のx、y座標を取得するならば
こんな感じかと思います。
hash_places = []
fields = [
['#', '#', '#', '#', '.', '.'],
['.', '.', '#', '.', '#', '.'],
['#', '.', '#', '.', '#', '.'],
['.', '#', '#', '.', '.', '#'],
]
fields.each_with_index do |field, y|
field.each_with_index do |a, x|
hash_places << { x: x, y: y} if a == '#'
end
end
# hash_placesの中身
{:x=>1, :y=>0}
{:x=>2, :y=>0}
{:x=>3, :y=>0}
{:x=>2, :y=>1}
{:x=>4, :y=>1}
{:x=>0, :y=>2}
{:x=>2, :y=>2}
{:x=>4, :y=>2}
{:x=>1, :y=>3}
{:x=>2, :y=>3}
{:x=>5, :y=>3}
x、y座標の値のリストができました。
隣接関係を調べる
取得した値を使用して、上下左右に同じ値があるか、調べることができます。
方法は+1 -1を使用するだけです。
# 左の値を確認したいならば、x軸 - 1
# 右ならば、x軸 + 1
# 上ならば、y軸 - 1
# 下ならば、y軸 + 1
これを使って、先程のhash_placesから上下左右に#があるか調べてみると、
こんな感じになります。(ちょっと汚いコードですいません。。)
def is_neighbors(place, fields)
top = place[:y] - 1 == -1 ? 'NONE' : { x: place[:x], y: place[:y] - 1 }
is_top = top != 'NONE' && (fields[top[:y]][top[:x]] == fields[place[:y]][place[:x]])
right = place[:x] + 1 == fields[0].length ? 'NONE' : { x: place[:x] + 1, y: place[:y] }
is_right = right != 'NONE' && (fields[right[:y]][right[:x]] == fields[place[:y]][place[:x]])
bottom = place[:y] + 1 == fields.length ? 'NONE' : { x: place[:x], y: place[:y] + 1 }
is_bottom = bottom != 'NONE' && (fields[bottom[:y]][bottom[:x]] == fields[place[:y]][place[:x]])
left = place[:x] - 1 == -1 ? 'NONE' : { x: place[:x] - 1, y: place[:y] }
is_left = left != 'NONE' && (fields[left[:y]][left[:x]] == fields[place[:y]][place[:x]])
answer = {
is_top: is_top,
is_right: is_right,
is_bottom: is_bottom,
is_left: is_left,
}
end
hash_places.each_with_index do |place, i|
puts "#{i + 1}番目: #{is_neighbors(place, fields)}"
end
# 戻り値
1番目: {:is_top=>false, :is_right=>true, :is_bottom=>false, :is_left=>false}
2番目: {:is_top=>false, :is_right=>true, :is_bottom=>false, :is_left=>true}
3番目: {:is_top=>false, :is_right=>true, :is_bottom=>true, :is_left=>true}
4番目: {:is_top=>false, :is_right=>false, :is_bottom=>false, :is_left=>true}
5番目: {:is_top=>true, :is_right=>false, :is_bottom=>true, :is_left=>false}
6番目: {:is_top=>false, :is_right=>false, :is_bottom=>true, :is_left=>false}
7番目: {:is_top=>false, :is_right=>false, :is_bottom=>false, :is_left=>false}
8番目: {:is_top=>true, :is_right=>false, :is_bottom=>true, :is_left=>false}
9番目: {:is_top=>true, :is_right=>false, :is_bottom=>false, :is_left=>false}
10番目: {:is_top=>false, :is_right=>true, :is_bottom=>false, :is_left=>false}
11番目: {:is_top=>true, :is_right=>false, :is_bottom=>false, :is_left=>true}
12番目: {:is_top=>false, :is_right=>false, :is_bottom=>false, :is_left=>false}
各値を上下左右で計算しています。
一番外側にいた場合は、隣の値がないので、
その時はNONEを返しています。
左と上は、-1になることはないので、それを条件分岐に使用しています。
右と下は、要素の長さを超えることはないので、それを条件分岐に使用しています。