LoginSignup
4
4

More than 1 year has passed since last update.

x、y座標使ったプログラミング問題を解いて思ったこと

Last updated at Posted at 2021-07-17

メモがてらの投稿です。

よく、プログラミング問題を解く時に、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|

スクリーンショット 2021-07-17 13.02.19.png
これがいわゆるy軸の値です。

次に、各配列をさらにループします。
同様にこちらも、添字を取得できます。

field.each_with_index do |f, x|

スクリーンショット 2021-07-17 13.10.30.png
これが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を返しています。

スクリーンショット 2021-07-17 15.08.13.png

左と上は、-1になることはないので、それを条件分岐に使用しています。
右と下は、要素の長さを超えることはないので、それを条件分岐に使用しています。

参考

each_with_indexの使い方

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4