Last active
February 24, 2021 14:41
-
-
Save kakutani/096e0ecbbbf81e76c73ac82f74a30f4c to your computer and use it in GitHub Desktop.
end-less methods bowling (object-oriented)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Bowling | |
class Game | |
def initialize(marks) = (@frame_builder = Frame.builder(marks)) | |
def score = frames.sum(&:score) | |
private | |
def frames = (@frames ||= Array.new(10){ build_frame(final?(_1)) }) | |
def build_frame(final) = @frame_builder.call(final) | |
def final?(index) = (index == 9) | |
end | |
class Frame | |
def self.builder(marks) = Builder.new(marks) | |
def initialize(rolls:, bonus:) = (@rolls, @bonus = rolls, bonus) | |
def score = (@rolls + @bonus).sum | |
module Bonus | |
class << self | |
def frame_if(sym, pins) = (bonus?(sym, pins) && bonus(sym).frame(pins)) | |
def strike?(pins) = bonus?(:strike, pins) | |
private | |
def bonus?(sym, pins) = bonus(sym).satisfied?(pins) | |
def bonus(sym) = const_get(sym.capitalize) | |
end | |
module Strike | |
class << self | |
def point = 10 | |
def satisfied?(pins) = (pins.first == Strike.point) | |
def frame(pins) = {rolls: [pins.shift], bonus: pins.take(2)} | |
end | |
end | |
module Spare | |
class << self | |
def satisfied?(pins) = (!Bonus.strike?(pins) && (pins.take(2).sum == 10)) | |
def frame(pins) = {rolls: pins.shift(2), bonus: pins.take(1)} | |
end | |
end | |
module MarkXasStrike | |
refine String do def to_i(base = 10) = (self == 'X' ? Strike.point : super) end | |
end | |
end | |
class Builder | |
def initialize(marks) = (@marks = marks) | |
def call(final) = Frame.new(**(final ? final_frame : nonfinal_frame)) | |
private | |
def final_frame = {rolls: pins.shift(3), bonus: []} | |
def nonfinal_frame = (frame_if(:strike) || frame_if(:spare) || open_frame) | |
def frame_if(bonus) = Bonus.frame_if(bonus, pins) | |
def open_frame = {rolls: pins.shift(2), bonus: []} | |
def pins = (@pins ||= parse_marks) | |
using Bonus::MarkXasStrike | |
def parse_marks = @marks.split(',').map(&:to_i) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require 'minitest/autorun' | |
require 'minitest/pride' | |
require_relative 'bowling' | |
class BowlingTest < Minitest::Test | |
def calculate_score(marks) | |
Bowling::Game.new(marks).score | |
end | |
def test_score1 | |
marks = '6,3,9,0,0,3,8,2,7,3,X,9,1,8,0,X,6,4,5' | |
assert_equal 139, calculate_score(marks) | |
end | |
def test_score2 | |
marks = '6,3,9,0,0,3,8,2,7,3,X,9,1,8,0,X,X,X,X' | |
assert_equal 164, calculate_score(marks) | |
end | |
def test_score3 | |
marks = '0,10,1,5,0,0,0,0,X,X,X,5,1,8,1,0,4' | |
assert_equal 107, calculate_score(marks) | |
end | |
def test_score4 | |
marks = '6,3,9,0,0,3,8,2,7,3,X,9,1,8,0,X,X,0,0' | |
assert_equal 134, calculate_score(marks) | |
end | |
def test_perfect_game | |
marks = 'X,X,X,X,X,X,X,X,X,X,X,X' | |
assert_equal 300, calculate_score(marks) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment