非OOP版はこちら↓
1. 実行環境
2. ソースコード
bowling.rb
#!/usr/bin/env ruby # frozen_string_literal: true require_relative 'game' shots = ARGV[0].split(',') game = Game.new(shots) puts game.score
game.rb
# frozen_string_literal: true require_relative 'frame' class Game def initialize(shots) @shots = shots end def score @frames = build_frames game_score = 0 (0..9).each do |idx| frame = Frame.new(@frames[idx]) game_score += frame.score @frames[idx + 1] ||= [] @frames[idx + 2] ||= [] game_score += calc_bonus_point(idx, frame) end game_score end def build_frames frame = [] frames = [] @shots.each do |s| frame << s if frames.length < 10 if frame.length >= 2 || s == 'X' frames << frame.dup frame.clear end else frames.last << s end end frames end def calc_bonus_point(idx, frame) if frame.strike? next_two_shots = (@frames[idx + 1] + @frames[idx + 2]).slice(0, 2) bonus_point = next_two_shots.sum { |s| Shot.new(s).score } elsif frame.spare? next_shot = @frames[idx + 1][0] bonus_point = Shot.new(next_shot).score else bonus_point = 0 end end end
frame.rb
# frozen_string_literal: true require_relative 'shot' class Frame def initialize(frame) @first_shot = Shot.new(frame[0]) @second_shot = Shot.new(frame[1]) @third_shot = Shot.new(frame[2]) end def score [ @first_shot.score, @second_shot.score, @third_shot.score ].sum end def strike? @first_shot.score == 10 end def spare? score == 10 end end
shot.rb
# frozen_string_literal: true class Shot def initialize(mark) @mark = mark end def score @mark == 'X' ? 10 : @mark.to_i end end