Uncle Bob’s Bowling Game Kata
August 11, 2009
Uncle Bob wrote lots of code and lots of tests, but this task is actually very simple; note whether the current frame is a strike, a spare, or an open frame, calculate the appropriate score, and add it to the score of the rest of game, calculated recursively:
(define (pins . xs)
((10 a b . x) (+ 10 a b (if (null? x) 0 (apply pins a b x))))
((a b c . x) (= (+ a b) 10) (+ 10 c (if (null? x) 0 (apply pins c x))))
((a b . x) (+ a b (if (null? x) 0 (apply pins x))))))
List-match, which is provided by the Standard Prelude, performs pattern-matching on lists. The first clause identifies strikes when the first ball is 10; it adds 10 plus the next two balls, then calls
pins recursively. The second clause uses an optional fender
(= (+ a b) 10) to identify spares; it adds 10 plus the next ball, then calls
pins recursively. The third clause identifies open frames; it adds the two balls, then calls
pins recursively. All three clauses return 0 when the input is exhausted.
Here’s how the sample game looks:
> (pins 1 4 4 5 6 4 5 5 10 0 1 7 3 6 4 10 2 8 6)
To my mind, the suggested solution is far preferable to Uncle Bob’s solution. It is simple enough that it doesn’t really need any tests; since the code so neatly expresses the task definition, it is easy to see that it is correct. My code worked perfectly the first time it ran, and successfully passed a large series of tests. By comparison, I got lost far before I got to the end of Uncle Bob’s presentation — why would anybody purposely write code that they know is wrong just to satisfy a methodology that purports to eventually get it right, when it is so easy to just get it right in the first place?
You can run the code at http://programmingpraxis.codepad.org/oissVw14.
Pages: 1 2