読者です 読者をやめる 読者になる 読者になる

十字の壁がそそり立つ世界の中を君は螺旋状に歩く 横へな 2015.2.7 問題

問題

十字の壁がそそり立つ世界の中を君は螺旋状に歩く 横へな 2015.2.7 問題

結果

(´・ω・`)

ふりかえり

よかった点

  • それなりにRubyっぽい(OOPっぽい?)書き方ができたと思う
  • 割とガリガリ書けた

悪かった点

  • ガリガリ書きすぎてとてもナイーブな実装になった
  • いまいち問題の本質がわかってなかった感じがある
  • ↑ガリガリ書くのもマージナルな場所からガリガリ書いてしまったせい
  • ↑こういうのは結局使わない「不要なコード」が増えがち("You ain't gonna need it!")

最終回答

時間制限後に直した点

  • debug_show_meiroメソッドselectmapの誤りを修正
  • debug_show_meiroメソッドの名前を変更 -> debug
  • 二方向を壁に囲われていた場合の処理を追加。ついでにリファクタリング
  • 問題文の座標系と@field配列のindexがグラフィカルに対応してなかったのを修正
  • DIRがただの文字列でも良さそうだったので修正。ついでにシンボル化。
  • @fieldが特に配列である必要がなかったのでhashに変更
  • 目についたデバッグメソッド・メンバ削除

その他いろいろ(あんまり覚えてない)

実コード

class Wall
  attr_accessor :field
  MAX = 100
  def initialize(input)
    n, e, s, w = input
    @field = {}
    s = -s
    w = -w
    s.upto(n) do |y|
      set_wall(0, y)
    end
    w.upto(e) do |x|
      set_wall(x, 0)
    end
  end
  def is_wall(x, y)
    key = key_of(x, y)
    @field[key]
  end
  def set_wall(x, y)
    key = key_of(x, y)
    @field[key] = true
  end
  private
  def key_of(x, y)
    half = MAX / 2
    x = x + half
    y = half - y
    if x < 0 || x >= MAX || y < 0 || y >= MAX
      debug
    end
    return "#{x},#{y}"
  end
end
class Person
  attr_reader :point
  VECT = [[ 0,  1],
          [ 1,  0],
          [ 0, -1],
          [-1,  0]]
  DIR = :NESW
  def initialize(w)
    @wall = w
    @point = [1, 1]
    @wall.set_wall(1, 1)
    @front = 1
  end
  def step
    v = VECT[togo_dir]
    nx, ny = add_point(v)
    @wall.set_wall(nx, ny)
    @point = [nx, ny]
  end
  def togo
    DIR[togo_dir]
  end
  private
  def right
    (@front + 1) % 4
  end
  def left
    (@front + 3) % 4
  end
  def try_step(x, y)
    !@wall.is_wall(x, y)
  end
  def togo_dir
    v = VECT[right]
    nx, ny = add_point(v)
    if try_step(nx, ny)
      @front = right
      return @front
    end
    v = VECT[@front]
    nx, ny = add_point(v)
    if try_step(nx, ny)
      return @front
    end
    return left
  end
  def add_point(v)
    x = @point[0] + v[0]
    y = @point[1] + v[1]
    return x, y
  end
end
class Solver
  attr_writer :input
  def solve
    arr = @input.split(",")
    arr[3],day = arr[3].split(":")
    arr.map!{|e| e.to_i}
    d = day.to_i

    w = Wall.new(arr)
    me = Person.new(w)
    d.times do
      me.step
    end
    me.togo
  end
end
require "./solver.rb"
module Test
  def self.exec
    all_ok = true
    File::open("./input.txt") do |f|
      f.each do |line|
        arr = line.split("\t")
        s = Solver.new
        s.input = arr[1].chomp
        expected = arr[2].chomp
        actual = s.solve.chomp
        is_ok = expected == actual
        all_ok = all_ok && is_ok
        next if is_ok
        puts "case#{arr[0]} actual=#{actual} expected=#{expected}"
      end
    end
    if all_ok
      puts "-> ALL OK"
    else
      puts "-> OMG"
    end
  end
end

Test.exec