Skip to content

Instantly share code, notes, and snippets.

@janderit
Created December 3, 2019 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janderit/9396958efa04d65322c9da331d002854 to your computer and use it in GitHub Desktop.
Save janderit/9396958efa04d65322c9da331d002854 to your computer and use it in GitHub Desktop.
Functional solution to the Bowling Kata
//
// Functional Bowling Kata solution in F#
//
// uses recursive determination of the score starting with a certain frame number
// and lookahead for the bonus roll scores
//
let private frames_in_game = 10
type FrameType = Strike | Spare | Normal
let private skip number_of_elements elements =
if List.length elements < number_of_elements then [] else List.skip number_of_elements elements
let private take number_of_elements elements =
if List.length elements < number_of_elements then elements else List.take number_of_elements elements
let rec private score_for_frames_starting frame_number rolls =
if frame_number > frames_in_game
then 0
else
let is_strike = (take 1 rolls |> List.sum) = 10
let rolls_in_frame = if is_strike then 1 else 2
let net = take rolls_in_frame rolls |> List.sum
let frame =
match is_strike, net with
| true, _ -> Strike
| false, 10 -> Spare
| _ -> Normal
let next_rolls = skip rolls_in_frame rolls
let bonus =
match frame with
| Strike -> take 2 next_rolls |> List.sum
| Spare -> take 1 next_rolls |> List.sum
| Normal -> 0
net + bonus + score_for_frames_starting (frame_number + 1) next_rolls
let bowling rolls =
score_for_frames_starting 1 rolls
let test subject (rolls,expected) =
let actual = subject rolls
if actual = expected
then "OK\n"
else sprintf "Expected %d, but found %d\n" expected actual
let testcases =
[ [ 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ], 0
[ 1; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ], 1
[ 1; 4; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ], 5
[ 5; 5; 3; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ], 15 + 3
[ 10; 3; 2; 5; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0 ], 20 + 5
[ 10; 10; 10; 10; 10; 10; 10; 10; 10; 10; 10; 10 ], 300 ]
[<EntryPoint>]
let main argv =
testcases |> List.map(test bowling) |> List.iter (printf "%s")
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment