添え字を使わずに2次元配列を回転・反転させる方法

ここでは、2次元配列とは Array の Array を意味することにします。外側の親配列が同じ長さの小配列を持っている、

matrix = [[1,2,3],[4,5,6],[7,8,9]]

のようなやつですね。

視覚的にはこんな数字の表を表していると考えましょう。1 5 9 の軸が主対角線で 3 5 7 の軸が副対角線です。

1 2 3
4 5 6
7 8 9

はじめに表示用の関数を定義しておきます。

def ap ary
  ary.each do |row|
    puts row.join
  end
  puts
end
ap matrix

123
456
789

この配列を回転させたり、オモテウラを反転させたりしていきます。

こういった処理は添え字の変換で行うのが一般的なのでしょうが、あえて添え字を使わずに実装したいと思います。コードは Array クラスのメソッドとして追加していきます。

左右反転

それぞれの小配列を reverse で逆順にします。垂直の軸でひっくりかえすので vflip という名前にしましょう。

class Array
  def vflip
    map(&:reverse)
  end
end
ap matrix.vflip

321
654
987

上下反転

今度は親配列を逆順にします。

class Array
  def hflip
    reverse
  end
end
ap matrix.hflip

789
456
123

転置

主対角線にそって裏返して、行を列に、列を行にする変換です。すでに Array クラスに transpose メソッドが用意されています。

ap matrix.transpose

147
258
369

右に90°回転

転置の後に左右反転を行うと右に90°回転させたのと同じことになります。想像してみましょう。

class Array
  def right_rotate
    transpose.vflip
  end
end
ap matrix.right_rotate

741
852
963

上下反転してから転置してもできます。

右に180°回転

90°回転を2回行えば実現できます。

class Array
  def turn
    right_rotate.right_rotate
  end
end
ap matrix.turn

987
654
321

左に90°回転

左右反転の後に転置を行います。

class Array
  def left_rotate
    vflip.transpose
  end
end
ap matrix.left_rotate

369
258
147

あるいは転置のあとに上下反転してもできます。

副対角線にそった転置

左右反転、転置、左右反転の処理をこの順番で行うと副対角線にそって裏返すことができます。*1

class Array
  def atranspose
    vflip.transpose.vflip
  end
end
ap matrix.atranspose

963
852
741

どの操作もまだ別のやりかたがあるのでしょうね。あんまり深く考えると添え字アクセスよりも難しそうなので、このくらいで切り上げることにしましょう。