piotrmurach/tenpin

View on GitHub
lib/tenpin/score.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true
 
module Tenpin
class Score
MAX_FRAMES_INDEX = 9
 
Stopped = Class.new(StandardError)
 
# The current total score
attr_reader :total
 
# The recording of all scores in each frame
attr_reader :frames
 
# Holds all the frame totals
attr_reader :frame_totals
 
# The currenty played frame 0 indexed
attr_reader :current_frame
 
# Create a game score
#
# @api public
def initialize
@total = 0
@current_frame = 0
@frames = []
@frame_totals = []
end
 
# Current frame scores
#
# @return [Array[Integer]]
#
# @api public
def current_frame_scores
@frames[current_frame] ||= []
end
 
# Record how many pins knocked down in a single roll
#
# @param [Integer] pins
# the number of pins knocked down
#
# @api public
Method `roll` has a Cognitive Complexity of 10 (exceeds 5 allowed). Consider refactoring.
def roll(pins)
return if finish?
 
current_frame_scores << pins
@total += pins
 
# Calculate bonus
if (!last_roll? && previous_frame_strike?) ||
(first_roll? && previous_frame_spare?)
@total += pins
@frame_totals[current_frame - 1] += pins
end
 
if first_roll? && previous_two_frames_strike?
@total += pins
@frame_totals[current_frame - 1] += pins
@frame_totals[current_frame - 2] += pins
end
 
@frame_totals[current_frame] = @total
 
if next_frame?
@current_frame += 1
yield if block_given?
end
end
 
# Check if game is finished
#
# @return [Boolean]
#
# @api public
def finish?
last_frame? && (last_roll? ||
(second_roll? && !(strike?(current_frame) || spare?(current_frame))))
end
 
private
 
def next_frame?
(strike?(current_frame) || spare?(current_frame) || second_roll?) && !last_frame?
end
 
def last_frame?
current_frame == MAX_FRAMES_INDEX
end
 
def previous_two_frames_strike?
previous_frame_strike? && current_frame > 1 && strike?(current_frame - 2)
end
 
def previous_frame_strike?
strike?(current_frame - 1) && current_frame > 0
end
 
def strike?(frame)
roll_first(frame) == 10
end
 
def previous_frame_spare?
spare?(current_frame - 1) && current_frame > 0
end
 
def spare?(frame)
(roll_first(frame) != 10) && (roll_first(frame) + roll_second(frame) == 10)
end
 
def first_roll?
!current_frame_scores[0].nil? && current_frame_scores[1].nil?
end
 
def roll_first(frame)
@frames[frame][0].to_i
end
 
def second_roll?
!current_frame_scores[1].nil?
end
 
def roll_second(frame)
@frames[frame][1].to_i
end
 
def last_roll?
!current_frame_scores[2].nil?
end
end # Score
end # Tenpin