サイコロを転がしてみる

オフラインリアルタイムどう書く #28 - 横浜へなちょこプログラミング勉強会 | Doorkeeper

こちらに明日おじゃまする予定なので過去問を実装してみた。
挑戦してみたのはこちら

サイコロを転がす 〜 横へな 2013.7.6

うん、まあ素直に書けそうな問題ですね。 とりあえず気の向くままに書いてみる。
言語は最近勉強中のRuby

class Dice
  attr_reader :history
  def initialize(head = 1, n = 2, w = 3)
    @head = head
    @body = {N: n, W: w, S: reverse(n), E: reverse(w)}
    @tail = reverse(@head)
    @history = []
    add_head_history
  end
  def head
    @head
  end
  def N
    @body[:N]
  end
  def W
    @body[:W]
  end
  def S
    @body[:S]
  end
  def E
    @body[:E]
  end
  def tail
    @tail
  end
  def show_head_history
    puts @history.join
  end
  def move_to(dir)
    # オエー
    case dir
    when 'N'
      tmp = @head
      @head = @body[:S]
      @body[:S] = @tail
      @tail = @body[:N]
      @body[:N] = tmp
    when 'E'
      tmp = @head
      @head = @body[:W]
      @body[:W] = @tail
      @tail = @body[:E]
      @body[:E] = tmp
    when 'W'
      tmp = @head
      @head = @body[:E]
      @body[:E] = @tail
      @tail = @body[:W]
      @body[:W] = tmp
    when 'S'
      tmp = @head
      @head = @body[:N]
      @body[:N] = @tail
      @tail = @body[:S]
      @body[:S] = tmp
    end
    add_head_history
  end
  private
  def add_head_history
    @history.push(@head)
  end
# 以下略……

こ、こ、こいつはひでぇ~~~
Dice#move_toがやばい。なんかすごく気持ち悪い。
と、ここで気がついたのは「6面全部管理する必要ってないのでは?」ということ。

別にheadとnorthとwestのみわかれば全ての面の位置がわかるはず!
(今回はサイコロの形も明示されているのでheadとnorthだけでもいいけど)

というわけでちょっと変えてみたのがこっち。

# 今度はheadとNとEを1~6に割り当ててみる。
class Dice
  attr_reader :history
  def initialize(h = 1, n = 2, w = 3)
    @history = []
    @state = Array.new(7) #こういうのも番兵というのだろうか
    set_state(n, h, w)
    add_head_history
  end
  def move_to(dir)
    n, h, w = get_new_state(dir)
    set_state(n, h, w)
    add_head_history
  end
  private
  def get_new_state(dir)
    case dir
    when 'N'
      n = head
      h = reverse north
      w = west
    when 'S'
      n = reverse head
      h = north
      w = west
    when 'E'
      n = north
      h = west
      w = reverse head
    when 'W'
      n = north
      h = reverse west
      w = head
    end
    return n, h, w
  end
  def set_state(n, h, w)
    @state = Array.new(7)
    @state[h] = :head
    @state[n] = :north
    @state[w] = :west
  end
  def add_head_history
    @history.push(head())
  end
  def reverse(num)
    7 - num
  end
  def head
    @state.index(:head)
  end
  def north
    @state.index(:north)
  end
  def west
    @state.index(:west)
  end
end
class Solver
  attr_accessor :input
  def solve
    d = Dice.new
    @input.split("").each do |dir|
      d.move_to dir
    end
    d.history.join
  end
end

s = Solver.new
s.input = gets.chomp
puts s.solve

うーん、なんか変な印象は残るもののまあいいか……。
気になってるのは以下の箇所

  • Dice#get_new_stateがやっぱりダメなのでは?
  • そもそもSolverとかの書き方ってRuby的にこれでいいの?
  • そもそも命名ってRuby的にこれでいいの……?
  • Rubyってどうやってテストするんだ……?

気になりつつも時間も時間なので明日開始前に調べたいところ。