ボウリングゲーム

ボウリングでTDDのコツ1つ。仕様を確認すること!
いきなりコードかいちゃだめよw。
ストライクのルールがわかってなくてCodeが2展3展しちゃってる.いまもルールをわかっているか怪しいw


まわりを見渡すと、インプットのスコアが配列構造.うーん.なんかこの時点でもやもやがw。

とりあえず現時点めも

# あれ?小さな個々のメソッドのテスト全然なくね?TDDのはずなのにorz
require File.dirname(__FILE__) + "/../lib/bowling"

describe Game, "perfect game" do
  before(:each) do
    @game = Game.new
    9.times { |i|
      @game.frame(i+1).first = 10
    }
    @game.frame(10).first = 10
    @game.frame(10).second = 10
    @game.frame(10).third = 10
  end
  
  it "should calc total_score" do
    @game.total_score.should == 300
  end
  
  it "should calc cumulative_score frame" do
    @game.frame(1).cumulative_score.should == 30
    @game.frame(5).cumulative_score.should == 150
    @game.frame(10).cumulative_score.should == 300
  end
end

describe Game, "no spare, no strike game(open frame)" do
  before(:each) do
    @game = Game.new
    10.times { |i|
      @game.frame(i+1).first = 3
      @game.frame(i+1).second = 5      
    }
  end
  
  it "should calc total_score" do
    @game.total_score.should == 80
  end
  
  it "should calc cumulative_score frame" do
    @game.frame(1).cumulative_score.should == 8
    @game.frame(5).cumulative_score.should == 40
    @game.frame(10).cumulative_score.should == 80
  end
end

describe Game, "all spare" do
  before(:each) do
    @game = Game.new
    9.times { |i|
      @game.frame(i+1).first = 3
      @game.frame(i+1).second = 7      
    }
    
    @game.frame(10).first = 3
    @game.frame(10).second = 7
    @game.frame(10).third = 3
  end
  
  it "should calc total_score" do
    @game.total_score.should == 13 * 10
  end
  
  it "should calc cumulative_score" do
    @game.frame(1).cumulative_score.should == 13
    @game.frame(5).cumulative_score.should == 65
    @game.frame(10).cumulative_score.should == 130
  end  
end

describe Game, "drink acceptance" do
  before(:each) do
    @game = Game.new
    @game.set_pin do
      def frame num
        @game.frame(num)
      end
      frame(1).first = 1
      frame(1).second = 2
      frame(1).first = 1
      frame(1).second = 4
      frame(2).first = 4
      frame(2).second = 5
      frame(3).first = 6
      frame(3).second = 4
      #spare
      frame(4).first = 5
      frame(4).second = 5
      # strike
      frame(5).first = 10
      frame(6).first = 0
      frame(6).second = 1 
      frame(7).first = 7
      frame(7).second = 3 
      frame(8).first = 6
      frame(8).second = 4 
      # strike
      frame(9).first = 10
      # last game spare
      frame(10).first = 2
      frame(10).second = 8
      frame(10).third = 6
    end
  end
  
  it "should calc cumulative_score frame" do
    @game.frame(1).cumulative_score.should == 5
    @game.frame(2).cumulative_score.should == 14
    @game.frame(3).cumulative_score.should == 29
    @game.frame(4).cumulative_score.should == 49
    @game.frame(5).cumulative_score.should == 60
    @game.frame(6).cumulative_score.should == 61
    @game.frame(7).cumulative_score.should == 77
    @game.frame(8).cumulative_score.should == 97
    @game.frame(9).cumulative_score.should == 117
    @game.frame(10).cumulative_score.should == 133    
  end
  
  it "should calc total_score" do
    @game.total_score.should == 133
  end
end

describe Game, "9frame strike, 10frame strike and 2, 3" do
  before(:each) do
    @game = Game.new
    8.times { |i|
      @game.frame(i+1).first = 0
      @game.frame(i+1).second = 0
    }
    @game.frame(9).first = 10
    
    @game.frame(10).first = 10
    @game.frame(10).second = 2
    @game.frame(10).third = 3
  end
  
  it "should calc cumulative_score frame" do
    @game.frame(1).cumulative_score.should == 0
    @game.frame(9).cumulative_score.should == 22
    @game.frame(10).cumulative_score.should == 22 + 15
  end
end
class Game
  attr_reader :frames
  def initialize(frame_size=10)
    @frames = (0..frame_size-2).map{|i| 
      f1 = Frame.new
    }
    @frames << LastFrame.new
    (0..frame_size-2).each{|i|
      @frames[i].next_frame = @frames[i+1]
    }
    (1..frame_size-1).each{|i|
      @frames[i].prev_frame = @frames[i-1]
    }
  end

  def total_score
    @frames.last.cumulative_score
  end
  
  def frame(num)
    @frames[num-1]
  end
  
  def set_pin(&block)
    block.call
  end
end

class Frame
  attr_accessor :first, :second
  attr_accessor :next_frame, :prev_frame
  
  def initialize
    @next_frame = nil
    @prev_frame = nil
  end
  
  def score
    strike? ? @first + strike_bonus :
    spare? ? @first + @second + spare_bonus :
             @first + @second
  end
  
  def cumulative_score
    prev_cumulative_score + score
  end
  
  def prev_cumulative_score
    @prev_frame ? @prev_frame.cumulative_score : 0
  end
  
  def strike?
    @first == 10
  end
  
  def spare?
    return false if strike?
    @first + @second == 10
  end

  def strike_bonus
    # 何かいまいち
    (not @next_frame.strike?) ? @next_frame.first + @next_frame.second : 
    (not @next_frame.last?) ? @next_frame.first + @next_frame.next_frame.first :
      @next_frame.first + @next_frame.second
  end

  def spare_bonus
    @next_frame.first
  end
  
  def last?
    false
  end
end

class LastFrame < Frame
  attr_accessor :third

  def strike_bonus
    return @second + @third
  end

  def spare_bonus
    @third
  end
  
  def last?
    true
  end
end