Some time ago I blogged about my first experience with F#. I took a course Functional Programming Principles in Scala recently and it somewhat opened my eyes on problem solving in functional style. After that I felt confident enough to do something more complex than fizzbuzz with F# so the logical next step was Bowling game kata.
Without further ado here are the tests:
let throwmany(amount, pins) = [ for n in 1..amount -> pins ] [<TestFixture>] type BowlingGameTests()= [<Test>] member x.``Bowling guttergame``() = let throws = throwmany(20, 0) score throws |> should equal 0 [<Test>] member x.``Throw all ones``() = let throws = throwmany(20, 1) score throws |> should equal 20 [<Test>] member x.``Throw one spare``() = let sparethrows = [5; 5; 3] let manythrows=throwmany (17, 0) let throws = sparethrows @ manythrows score throws |> should equal 16 [<Test>] member x.``Throw one strike``() = let throws = [10; 3; 4] @ throwmany (16, 0) score throws |> should equal 24 [<Test>] member x.``Perfect game``() = let throws = throwmany (12, 10) score throws |> should equal 300
Tests are same as in the kata slides. Throwmany-function creates a list with as many items as given in amount-parameter and each item has the value given in pins-parameter.
Being the OOP-guy that I am I originally started thinking I need a Game-class that holds the state of the game. Each throw should be registered to Game using throw-method and so on. Then I tried to start thinking in a more functional way. If I give up maintaining state, I wouldn't need any throw-method. Then I wouldn't need any Game-class at all and I could do with just a score-function that takes list of throws. This is what I ended up with:
let private calculate_strike_score (throws: int list) = if throws.Length>3 then 10+throws.Item(1)+throws.Item(2) else 10 let private calculate_spare_score (throws:int list) = 10+throws.Item(2) let rec private score_throws (throws: int list) (score:int) = match throws with |  -> score | throws when throws.Head = 10 -> score_throws throws.Tail score + calculate_strike_score(throws) | throws when (throws.Head + throws.Tail.Head = 10) -> score_throws throws.Tail.Tail score + calculate_spare_score(throws) | _ -> score_throws throws.Tail.Tail score + throws.Head+throws.Item(1) let score throws = score_throws throws 0
Score-function calls recursive score_throws-function with initial score of 0. In score_throws the correct route is chosen with pattern matching. If the throws-list is empty, then everything has been done and the final score should be returned. If the first element is 10, then it's a strike. If two first elements combined is 10, then it's a spare. Otherwise it's a regular frame.
That's it. Tests are green. Time to move on to something more complex.