Skip to content

Instantly share code, notes, and snippets.

@pazworld
Last active September 23, 2020 12:50
Show Gist options
  • Save pazworld/496f4b7b4f53c3709ae9b73d29e5bab9 to your computer and use it in GitHub Desktop.
Save pazworld/496f4b7b4f53c3709ae9b73d29e5bab9 to your computer and use it in GitHub Desktop.
BowlingGameKata in Erlang
-module(bowling_game).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
-record(game, {
rolls={},
current_roll=0
}).
gutter_game_test() ->
G = new(),
G2 = roll_many(G, 20, 0),
?assertEqual(0, score(G2)),
ok.
all_ones_test() ->
G = new(),
G2 = roll_many(G, 20, 1),
?assertEqual(20, score(G2)),
ok.
one_spare_test() ->
G = new(),
G3 = roll_spare(G),
G4 = roll(G3, 3),
G5 = roll_many(G4, 17, 0),
?assertEqual(16, score(G5)),
ok.
roll_spare(Game) -> roll(roll(Game, 5), 5).
one_strike_test() ->
G = new(),
G2 = roll_strike(G),
G3 = roll(G2, 3),
G4 = roll(G3, 4),
G5 = roll_many(G4, 16, 0),
?assertEqual(24, score(G5)),
ok.
roll_strike(Game) -> roll(Game, 10).
perfect_game_test() ->
G = new(),
G2 = roll_many(G, 12, 10),
?assertEqual(300, score(G2)).
%%% end of tests
new() -> #game{rolls=list_to_tuple([0 || _ <- lists:seq(1, 21)])}.
roll(Game, Pins) -> #game{
rolls=setelement(Game#game.current_roll + 1, Game#game.rolls, Pins),
current_roll=Game#game.current_roll + 1
}.
roll_many(Game, N, Pins) ->
PinsList = [Pins || _ <- lists:seq(1, N)],
lists:foldl(fun(P, G) -> roll(G, P) end, Game, PinsList).
score(Game) ->
Rolls = Game#game.rolls,
F = fun(_, {FrameIndex, Acc}) ->
IsStrike = is_strike(Rolls, FrameIndex),
IsSpare = is_spare(Rolls, FrameIndex),
if IsStrike ->
{FrameIndex + 1, Acc + 10 + strike_bonus(Rolls, FrameIndex)}
; IsSpare ->
{FrameIndex + 2, Acc + 10 + spare_bonus(Rolls, FrameIndex)}
; true ->
{FrameIndex + 2, Acc + sum_of_rolls_in_frame(Rolls, FrameIndex)}
end
end,
{_, Bonus} = lists:foldl(F, {1, 0}, lists:seq(1, 10)),
Bonus.
sum_of_rolls_in_frame(Rolls, FrameIndex) ->
element(FrameIndex, Rolls) + element(FrameIndex + 1, Rolls).
spare_bonus(Rolls, FrameIndex) ->
element(FrameIndex + 2, Rolls).
strike_bonus(Rolls, FrameIndex) ->
element(FrameIndex + 1, Rolls) + element(FrameIndex + 2, Rolls).
is_spare(Rolls, Idx) ->
10 =:= element(Idx, Rolls) + element(Idx + 1, Rolls).
is_strike(Rolls, Idx) ->
10 =:= element(Idx, Rolls).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment