(フォークでは)ないです

横へな問題チャレンジ第2回

フォークじゃない 〜 横へな 2014.2.1 問題

見た感想

レジに並ばせてどんどん処理していけばいいけどめんどくさそう……

  • レジの管理役→どのレジに並ぶか管理
  • レジ→並んでいる人の管理

実装

とりあえず書いてみたら何箇所かバグってた。

バグその1

xがちょうど処理できる人数にいるときの境界値条件。
あるある……

バグその2

xが2人同じレジに並んだときの条件。
これまたあるある……

class Register
  attr_reader :waiting
  def initialize(performance)
    @waiting = 0
    @stopper = 0
    @performance = performance
  end
  def exec
    if @stopper == 0
      next_without_stopper
    else
      next_with_stopper
    end
  end
  def add(customers)
    if customers == 'x'
      @waiting += 1
      @stopper = @waiting if @stopper == 0
    else
      num = customers.to_i
      @waiting += num
    end
  end
  def <=> (other)
    if other.waiting
      @waiting <=> other.waiting
    else
      nil
    end
  end
  private
  def next_with_stopper
    if @stopper <= @performance
      @waiting -= (@stopper - 1)
      @stopper = 1
    else
      @waiting -= @performance
      @stopper -= @performance
    end
  end
  def next_without_stopper
    @waiting -= @performance
    @waiting = 0 if @waiting < 0
  end
end
class Registers
  def initialize(performances)
    @arr = []
    performances.each do |p|
      @arr.push(Register.new(p))
    end
  end
  def exec(input)
    if input == '.'
      @arr.each do |r|
        r.exec
      end
    else
      to_wait.add(input)
    end
  end
  def status
    input = []
    @arr.each do |r|
      input.push(r.waiting.to_s)
    end
    input.join(",")
    # なんでこれじゃダメなんだろ
    #@arr.select{|r| r.waiting.to_s}.join(",")
  end
  private
  def to_wait
    i = 0
    tmp = @arr.sort_by {|v| [v, i += 1]}
    tmp[0]
  end
end
class Solver
  attr_writer :input
  def solve
    regis = Registers.new([2,7,3,5,2])
    @input.chomp.split("").each do |input|
      regis.exec(input)
    end
    regis.status
  end
end

テストはこんなふうにした

require "./regi.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

なんとなくmoduleにしたけどほんとかって感じがある。
こういうとこでの書き方にセンスというか、言語への思想が出る気がする。