Skip to content

Commit e10099a

Browse files
committed
Merging from the official book repository
1 parent 05f6545 commit e10099a

File tree

168 files changed

+65970
-7701
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+65970
-7701
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/Programming-Clojure.iml
32
/build.clj
43
/hello.out

classes/examples/tasklist.class

-5.61 KB
Binary file not shown.

classes/examples/tasklist__init.class

-3.71 KB
Binary file not shown.

clojurebreaker/Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: lein run

clojurebreaker/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# clojurebreaker
2+
3+
A website written in noir.
4+
5+
## Usage
6+
7+
```bash
8+
lein deps
9+
lein run
10+
```
11+
12+
## License
13+
14+
Copyright (C) 2011 FIXME
15+
16+
Distributed under the Eclipse Public License, the same as Clojure.
17+

clojurebreaker/project.clj

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
; START: clojurebreaker-project
2+
(defproject clojurebreaker "0.1.0-SNAPSHOT"
3+
:description "Clojurebreaker game for Programming Clojure 2nd Edition"
4+
:dependencies [[org.clojure/clojure "1.3.0"]
5+
[org.clojure/math.combinatorics "0.0.1"]
6+
[org.clojure/test.generative "0.1.3"]
7+
[noir "1.2.0"]]
8+
:main clojurebreaker.server)
9+
; END: clojurebreaker-project
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
html {
2+
margin:0;
3+
padding:0;
4+
border:0;
5+
}
6+
7+
body, div, span, object, iframe,
8+
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
9+
a, abbr, acronym, address, code,
10+
del, dfn, em, img, q, dl, dt, dd, ol, ul, li,
11+
fieldset, form, label, legend,
12+
table, caption, tbody, tfoot, thead, tr, th, td,
13+
article, aside, dialog, figure, footer, header,
14+
hgroup, nav, section {
15+
margin: 0;
16+
padding: 0;
17+
border: 0;
18+
font-weight: inherit;
19+
font-style: inherit;
20+
font-size: 100%;
21+
font-family: inherit;
22+
vertical-align: baseline;
23+
}
24+
25+
article, aside, dialog, figure, footer, header,
26+
hgroup, nav, section {
27+
display:block;
28+
}
29+
30+
body {
31+
line-height: 1.5;
32+
background: white;
33+
}
34+
35+
table {
36+
border-collapse: separate;
37+
border-spacing: 0;
38+
}
39+
40+
caption, th, td {
41+
text-align: left;
42+
font-weight: normal;
43+
float:none !important;
44+
}
45+
table, th, td {
46+
vertical-align: middle;
47+
}
48+
49+
blockquote:before, blockquote:after, q:before, q:after { content: ''; }
50+
blockquote, q { quotes: "" ""; }
51+
52+
a img { border: none; }
53+
54+
/*:focus { outline: 0; }*/
55+
56+
57+

clojurebreaker/scoring-table

+65,540
Large diffs are not rendered by default.

clojurebreaker/snippets.clj

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
;; this file contains the intermediate steps in building the
2+
;; Clojurebreaker game. See the clojurebreaker/src directory for the
3+
;; completed code.
4+
5+
; START:exact-matches-shell
6+
(defn exact-matches
7+
"Given two collections, return the number of positions where
8+
the collections contain equal items."
9+
[c1 c2])
10+
; END:exact-matches-shell
11+
12+
; START:integers-closed
13+
(defspec closed-under-addition
14+
+'
15+
[^long a ^long b]
16+
(assert (integer? %)))
17+
; END:integers-closed
18+
19+
; START:incorrect-spec
20+
(defspec incorrect-spec
21+
+'
22+
[^long a ^long b]
23+
(assert (< a %))
24+
(assert (< b %)))
25+
; END:incorrect-spec
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
(ns clojurebreaker.game
2+
(:use clojure.pprint)
3+
(:require [clojure.data :as data]
4+
[clojure.math.combinatorics :as comb]
5+
[clojure.java.io :as io]))
6+
7+
;; START:exact-matches
8+
(defn exact-matches
9+
"Given two collections, return the number of positions where
10+
the collections contain equal items."
11+
[c1 c2]
12+
(let [[_ _ matches] (data/diff c1 c2)]
13+
(count (remove nil? matches))))
14+
;; END:exact-matches
15+
16+
;; START:unordered-matches
17+
(defn unordered-matches
18+
"Given two collections, return a map where each key is an item
19+
in both collections, and each value is the number of times the
20+
value occurs in the collection with fewest occurrences."
21+
[c1 c2]
22+
(let [f1 (select-keys (frequencies c1) c2)
23+
f2 (select-keys (frequencies c2) c1)]
24+
(merge-with min f1 f2)))
25+
;; END:unordered-matches
26+
27+
;; START:score
28+
(defn score
29+
[c1 c2]
30+
(let [exact (exact-matches c1 c2)
31+
unordered (apply + (vals (unordered-matches c1 c2)))]
32+
{:exact exact :unordered (- unordered exact)}))
33+
;; END: score
34+
35+
;; START: generate-turn-inputs
36+
(defn generate-turn-inputs
37+
"Generate all possible turn inputs for a clojurebreaker game
38+
with colors and n columns"
39+
[colors n]
40+
(-> (comb/selections colors n)
41+
(comb/selections 2)))
42+
;; END: generate-turn-inputs
43+
44+
;; START: score-inputs
45+
(defn score-inputs
46+
"Given a sequence of turn inputs, return a lazy sequence of
47+
maps with :secret, :guess, and :score."
48+
[inputs]
49+
(map
50+
(fn [[secret guess]]
51+
{:secret (seq secret)
52+
:guess (seq guess)
53+
:score (score secret guess)})
54+
inputs))
55+
;; END: score-inputs
56+
57+
(->> (generate-turn-inputs [:r :g :b] 2)
58+
(score-inputs))
59+
60+
;; step 17 score-table
61+
#_(score-all-games [:R :G :B] 3)
62+
63+
;; step 18 could check either the clj or the tabular form of score-all-games
64+
;; into source control and use it as a regression test
65+
;; (add clojure.java.io)
66+
(use 'clojure.pprint)
67+
(with-open [w (io/writer "scoring-table")]
68+
(binding [*out* w]
69+
(print-table (->> (generate-turn-inputs [:r :g :b :y] 4)
70+
(score-inputs)))))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(ns clojurebreaker.models.game
2+
(:require [clojure.data :as data]))
3+
4+
(defn create []
5+
(vec (repeatedly 4 (fn [] (rand-nth ["r" "g" "b" "y"])))))
6+
7+
(defn exact-matches
8+
"Given two collections, return the number of positions where
9+
the collections contain equal items."
10+
[c1 c2]
11+
(let [[_ _ matches] (data/diff c1 c2)]
12+
(count (remove nil? matches))))
13+
14+
(defn unordered-matches
15+
"Given two collections, return a map where each key is an item
16+
in both collections, and each value is the number of times the
17+
value occurs in the collection with fewest occurrences."
18+
[c1 c2]
19+
(let [f1 (select-keys (frequencies c1) c2)
20+
f2 (select-keys (frequencies c2) c1)]
21+
(merge-with min f1 f2)))
22+
23+
(defn score
24+
[c1 c2]
25+
(let [exact (exact-matches c1 c2)
26+
unordered (apply + (vals (unordered-matches c1 c2)))]
27+
{:exact exact :unordered (- unordered exact)}))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
(ns clojurebreaker.server
2+
(:require [noir.server :as server]))
3+
4+
(server/load-views "src/clojurebreaker/views/")
5+
6+
(defn -main [& m]
7+
(let [mode (keyword (or (first m) :dev))
8+
port (Integer. (get (System/getenv) "PORT" "8080"))]
9+
(server/start port {:mode mode
10+
:ns 'clojurebreaker})))
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(ns clojurebreaker.views.common
2+
(:use noir.core
3+
hiccup.core
4+
hiccup.page-helpers))
5+
6+
(defpartial layout [& content]
7+
(html5
8+
[:head
9+
[:title "Clojurebreaker"]
10+
(include-css "/css/reset.css")]
11+
[:body
12+
[:div#wrapper
13+
content]]))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
(ns clojurebreaker.views.welcome
2+
(:require [noir.session :as session]
3+
[clojurebreaker.views.common :as common]
4+
[clojurebreaker.models.game :as game])
5+
(:use [noir.core :only (defpartial defpage render)]
6+
[hiccup.form-helpers :only (form-to text-field submit-button)]))
7+
8+
; START: clojurebreaker-partial
9+
(defpartial board [{:keys [one two three four exact unordered]}]
10+
(when (and exact unordered)
11+
[:div "Exact: " exact " Unordered: " unordered])
12+
(form-to [:post "/guess"]
13+
(text-field "one" one)
14+
(text-field "two" two)
15+
(text-field "three" three)
16+
(text-field "four" four)
17+
(submit-button "Guess")))
18+
; END: clojurebreaker-partial
19+
20+
; START: clojurebreaker-page
21+
(defpage "/" {:as guesses}
22+
(when-not (session/get :game)
23+
(session/put! :game (game/create)))
24+
(common/layout (board (or guesses nil))))
25+
; END: clojurebreaker-page
26+
27+
; START: clojurebreaker-post
28+
(defpage [:post "/guess"] {:keys [one two three four]}
29+
(let [result (game/score (session/get :game) [one two three four])]
30+
(if (= (:exact result) 4)
31+
(do (session/remove! :game)
32+
(common/layout
33+
[:h2 "Congratulations, you have solved the puzzle!"]
34+
(form-to [:get "/"]
35+
(submit-button "Start A New Game"))))
36+
(do (session/flash-put! result)
37+
(render "/" {:one one
38+
:two two
39+
:three three
40+
:four four
41+
:exact (:exact result)
42+
:unordered (:unordered result)})))))
43+
; END: clojurebreaker-post
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
;; START:invariants
2+
(ns clojurebreaker.game-test
3+
(:use [clojure.test.generative :only (defspec) :as test])
4+
(:require [clojure.test.generative.generators :as gen]
5+
[clojurebreaker.game :as game]
6+
[clojure.math.combinatorics :as comb]))
7+
8+
(defn matches
9+
"Given a score, returns total number of exact plus
10+
unordered matches."
11+
[score]
12+
(+ (:exact score) (:unordered score)))
13+
14+
(defn scoring-is-symmetric
15+
[secret guess score]
16+
(= score (game/score guess secret)))
17+
18+
(defn scoring-is-bounded-by-number-of-pegs
19+
[secret guess score]
20+
(< 0 (matches score) (count secret)))
21+
(defn reordering-the-guess-does-not-change-matches
22+
[secret guess score]
23+
(= #{(matches score)}
24+
(into #{} (map
25+
#(matches (game/score secret %))
26+
(comb/permutations guess)))))
27+
;; END:invariants
28+
29+
;; START:random-secret
30+
(defn random-secret
31+
[]
32+
(gen/vec #(gen/one-of :r :g :b :y) 4))
33+
;; END:random-secret
34+
35+
;; START:score-invariants
36+
(defspec score-invariants
37+
game/score
38+
[^{:tag `random-secret} secret
39+
^{:tag `random-secret} guess]
40+
(assert (scoring-is-symmetric secret guess %))
41+
(assert (scoring-is-bounded-by-number-of-pegs secret guess %))
42+
(assert (reordering-the-guess-does-not-change-matches secret guess %)))
43+
;; END:score-invariants

data/.svn/all-wcprops

-5
This file was deleted.

data/.svn/entries

-34
This file was deleted.

data/sequences/.svn/all-wcprops

-11
This file was deleted.

0 commit comments

Comments
 (0)