第25回オフラインリアルタイムどう書く「めぐるセル」の rubyによる実装


問題 http://nabetani.sakura.ne.jp/hena/ord25rotcell/
解答リンク集 http://qiita.com/Nabetani/items/636fce060e1ebbc95f9b
イベント http://yhpg.doorkeeper.jp/events/13947

当日お見せした実装。

module RotCell
  class Rotater
    def initialize(board)
      @board = board
    end

    def rot_core(ix, cx, cy)
      ix = ix.sort_by{ |i|
        y, x = i.divmod(5)
        Math.atan2(y - cy, x - cx)
      }
      v = @board.values_at(*ix)
      v.size.times.each do |i|
        @board[ix[i]] = v[i - 1]
      end
    end

    def rot(cmd)
      positions = cmd.chars.map { |c| @board.index(c).divmod(5) }
      left, right = positions.map { |xy| xy[1] }.minmax
      top, bottom = positions.map { |xy| xy[0] }.minmax
      indices_from = @board.size.times.select{ |xy|
        y, x = xy.divmod(5)
        (((x == left - 1 || x == right + 1) && ((top - 1..bottom + 1) === y)) ||
            ((y == top - 1 || y == bottom + 1) && ((left - 1..right + 1) === x)))
      }
      rot_core(indices_from, (left + right) / 2r, (top + bottom) / 2r)
      indices_from.map { |ix| @board[ix] }.sort.join
    end
  end

  def self.solve(s)
    cells = ('a'..'y').to_a
    commands = s.split(',')
    ro = Rotater.new(cells)
    commands.each do |c|
      ro.rot(c)
    end
    r = ro.rot(commands[-1])
    r.empty? ? 'none' : r
  end
end

DATA.map do |line|
  id, src, expected = line.split(/\s+/)
  actual = RotCell.solve(src)
  ok = actual == expected
  puts '***NG*** : %s %s->%s ( %s )' % [id, src, actual, expected] unless ok
  ok
end.all?.tap { |r| puts ( r ? 'ok' : 'NG') }

__END__
0 ab,gg,uj,pt,an,ir,rr  hpqsvwxy
1 gs,ok abcdftvwxy
2 gs,sg,ok  none

いつも通り、テストデータの大半は省略。

実装戦略で選択はいくつかあって。

  • データの持ち方
    a) 盤面を2次元または1次元の配列で持つ
    b) 文字と座標の対応を、key-value pair で持つ
  • 回転関連
    p) 回る方向にそってセルを集める
    q) 適当に集めて、あとで整列する

あたりが重要だと思う。

で。
この実装は aq という戦略にした。
会場では ap と bp の方がいらっしゃったけど q を選んだ方はいなかった。

ruby なので minmaxdivmod の結果を多重代入で取得とか、ary[-1]ary.last と同等であることを利用するとか、そういう小ネタを積み重ねている。

全体的に美しくない実装だと感じてはいるものの、こんな感じで。

ruby に偏っているので別の言語でいくべきだったなぁと思ったり。