Would love to see what other folks on this list have to say. If you
look at my version, it is worth walking through the commits one by one
to see the changes I made in going from an OO accent to more "Sequence-
Oriented Programming."
Cheers,
Stu
[1] http://blog.objectmentor.com/articles/2009/07/19/uncle-bob-jsps-learning-clojure
[2] http://github.com/stuarthalloway/clojure-bowling
(use 'clojure.contrib.test-is)
; A game is a sequence of numbers, representing how many pins were
knocked down for that roll
(defn sum [s] (reduce + s))
(defn score [game]
(cond
(< (count game) 3) (sum game),
(= (first game) 10) (+ (sum (take 3 game))
(score (drop 1 game))),
(= (sum (take 2 game)) 10)
(+ (sum (take 3 game)) (score (drop 2 game))),
:else (+ (sum (take 2 game)) (score (drop 2 game)))))
(deftest sample-games
(is (score [1 0 1 10 2 2 10 3 3 10 1 10 3 10 10 1 2]) 108)
(is (score [1 0 1 10 2 2 10 3 3 10 1 10 3 10 1 10 10 8 0]) 121)
(is (score [1 0 1 10 2 2 10 3 3 10 1 10 3 10 1 10 8 10 9]) 120))
;;;;;;;;;;;;
You can improve efficiency by enforcing an input of vectors and using
subvec, or you can keep the generality of sequences but change the
first test to something like (= (count (take game 3)) 3), but really,
why bother doing *anything* at the expense of clarity for a problem
where the inputs are so small that efficiency is a non-issue.
(defn frames
"Converts a sequence of rolls to a sequence of frames"
[rolls]
(if rolls
(lazy-seq (cons (take (balls-to-score rolls) rolls)
(frames (drop (frame-advance rolls) rolls)))))Unfortunately, I misused the "is" macro (forgot to put =), which
prevented me from catching my incorrect tests.
The result is similar in spirit to Stuart's code, but arguably a bit
more compact.
(use 'clojure.contrib.test-is)
; A game is a sequence of numbers, representing how many pins were
knocked down for that roll
(defn sum [s] (reduce + s))
(defn frame-scores [game]
(cond
(< (count game) 3) [(sum game)],
(= (first game) 10) (cons (sum (take 3 game)) (frame-scores
(drop 1 game))),
(= (sum (take 2 game)) 10) (cons (sum (take 3 game))
(frame-scores (drop 2 game))),
:else (cons (sum (take 2 game)) (frame-scores (drop 2 game)))))
(defn score [games] (sum (take 10 (frame-scores games))))
(deftest sample-games
(is (= (score [6 1 9 0 8 2 5 5 8 0 6 2 9 1 7 2 8 2 9 1 7]) 127))
(is (= (score [10 10 7 3 8 2 10 9 1 10 10 10 10 7 3]) 232))
(is (= (score [10 10 7 3 8 2 10 9 1 10 10 10 7 2]) 210))
(is (= (score [5 5 8 2 9 1 7 3 8 2 6 4 9 1 7 3 6 4 4 5]) 163))
(is (= (score [10 10 10 10 10 10 10 10 10 10 10 10]) 300)))
Stuart Halloway <stuart....@gmail.com> writes:
> Uncle Bob Martin, a very well-respected OO and agile guy, is learning
> Clojure. He has posted an example [1] and asked for feedback from the
> Clojure community. I have made my suggestions in code [2] and will be
> writing them up shortly.
>
> Would love to see what other folks on this list have to say.
My first version came out rather similar to yours, and then I started
thinking about turning the problem on its head and making the concept of
"types of rolls" more explicit. I'm still not sure how I feel about
this, but the line of thinking led me to code like this:
(ns bowling-game
(:use clojure.contrib.seq-utils))
(def *roll-types*
[{:name "strike"
:satisfies #(= (first %) 10)
:consumes 3
:advances 1}
{:name "spare"
:satisfies #(= (apply + (take 2 %))
10)
:consumes 3
:advances 2}
{:name "regular (underachieving?)"
:satisfies (constantly true)
:consumes 2
:advances 2}])
(defn roll-type [rolls]
(find-first #((:satisfies %) rolls)
*roll-types*))
(defn frames [rolls]
(when (seq rolls)
(let [{:keys [consumes advances]} (roll-type rolls)]
(cons (take consumes rolls)
(frames (drop advances rolls))))))
(defn score-game [rolls]
(reduce + (map #(reduce + %)
(take 10 (group-frames rolls)))))
Cheers,
Mark
--
Mark Triggs
<mark.h...@gmail.com>
Cheers,
Mark
artg <artgit...@gmail.com> writes:
> What is "group-frames"?
>
> --art
>
> On Jul 21, 12:00 am, Mark Triggs <mark.h.tri...@gmail.com> wrote:
[...]
>> (defn score-game [rolls]
>> (reduce + (map #(reduce + %)
>> (take 10 (group-frames rolls)))))
--
Mark Triggs
<mark.h...@gmail.com>