Sha256: f757b943e27a7968011c38d1ba7d1650f07e9c887816ff138dda4b0bf4627d95
Contents?: true
Size: 1.97 KB
Versions: 6
Compression:
Stored size: 1.97 KB
Contents
module BookKeeping VERSION = 2 end class Game PINS = { MIN: 0, MAX: 10 }.freeze at_exit { public :roll, :score } private def initialize @score_card = Hash.new { |frame_number, k| frame_number[k] = [] } @score_card[1] end def roll(pins) validate(pins) @score_card[current_frame] << pins @score_card[current_frame + 1] unless last_frame? || !frame_complete? end def validate(pins) raise StandardError, 'Invalid number of pins' unless (PINS[:MIN]..PINS[:MAX]).cover?(pins) raise StandardError, 'Too many pins in frame' unless valid_frame?(pins) raise StandardError, 'Game is over, no rolls allowed' if game_complete? end def valid_frame?(pins) last_roll_was_strike = @score_card[current_frame].last == 10 (last_frame? && last_roll_was_strike || spare?) || @score_card[current_frame].last.to_i + pins <= PINS[:MAX] end def score raise StandardError, 'Score unavailable until end of the game' unless game_complete? @score_card.values.map.with_index(1) do |f, i| score_frame(f, i) end.reduce(:+) end def score_frame(f, i) strike_or_spare = [f.first, f.inject(:+)].any? { |e| e == PINS[:MAX] } if strike_or_spare special(@score_card[i], @score_card[i + 1], @score_card[i + 2]) else f.reduce(:+) end end def special(*frames) first_three_scores = 0..2 frames.flatten[first_three_scores].reduce(:+) end def current_frame @score_card.keys.max end def game_complete? last_frame? && frame_complete? end def last_frame? current_frame == 10 end def frame_complete? if last_frame? frame_filled && open_frame? || frame_filled(3) else frame_filled || strike? end end def frame_filled(rolls = 2) @score_card[current_frame].size == rolls end def open_frame? !(strike? || spare?) end def strike? @score_card[current_frame].first == 10 end def spare? @score_card[current_frame].inject(:+) == 10 end end
Version data entries
6 entries across 6 versions & 1 rubygems