AOJ 0141 Spiral Pattern (Ruby)

問題。
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0141&lang=ja

「ぐるぐる模様」を出力します。簡単そうでかなりむずかしかったので、印象に残っています。

6番目の「ぐるぐる模様」

######
#    #
# ## #
# #  #
# #  #
# ####

 
コード。

result = []

gets.to_i.times do
  n = gets.to_i
  
  field = Array.new(n) {" " * n}
  x, y = 0, n - 1
  
  go = ->(dx, dy, l) {
    l.times do
      field[y][x] = "#"
      x += dx
      y += dy
    end
  }
  square = ->(l) {
    if l != 1
      go.(0, -1, l - 1)
      go.(1,  0, l - 1)
      go.(0,  1, l - 1)
      if l != 3
        go.(-1, 0, l - 3)
        if l != 4
          if l > 4
            go.(0, -1, 2)
            square.(l - 4)
          end
          return
        end
      end
    end
    field[y][x] = "#"
  }
  
  square.(n)
  result << field.map {|l| l + "\n"}.join
end
puts result.join("\n")

 

解説

  • まず、キャンバスfield[][]の左下に、開始位置 (x, y) をセットします。
  • go.(dx, dy, l) は、(dx, dy) 方向に l ステップだけ描画して、(x, y) を進めます。
    • まず (x, y) に # を置いてから、ステップを進めるという順です。
  • square.(l)は l 番目の「ぐるぐる模様」のいちばん外側一周を描き、(x, y) を進めます。
    • l > 4 の場合は、外周一周を描いたら、2ステップ上に進んで、square.(l - 4) を再帰的に呼びます。
    • l <= 4 の場合はややこしくて、場合分けがたくさんあります。

square.(l)は、冗長でも case ~ when 式で書けばもっとすっきりしましたね。
こんな感じか。

  square = ->(l) {
    case l
    when 1
      field[y][x] = "#"
    when 2
      go.(0, -1, 1)
      go.(1,  0, 1)
      field[y][x] = "#"
    when 3
      go.(0, -1, 2)
      go.(1,  0, 2)
      go.(0,  1, 2)
      field[y][x] = "#"
    when 4
      go.(0, -1, 3)
      go.(1,  0, 3)
      go.(0,  1, 3)
      go.(-1, 0, 2)
    else
      go.(0, -1, l - 1)
      go.(1,  0, l - 1)
      go.(0,  1, l - 1)
      go.(-1, 0, l - 3)
      go.(0, -1, 2)
      square.(l - 4)
    end
  }

これだと平凡ですね。