Skip to content

Commit cae7a31

Browse files
added win/lose
reorganized code
1 parent 9ae41ec commit cae7a31

File tree

1 file changed

+66
-24
lines changed

1 file changed

+66
-24
lines changed

examples/snake.clj

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
; Mark Volkmann's snake: http://www.ociweb.com/mark/programming/ClojureSnake.html
44

55
(ns examples.snake
6-
(:import (java.awt Color) (javax.swing JPanel JFrame Timer)
6+
(:import (java.awt Color) (javax.swing JPanel JFrame Timer JOptionPane)
77
(java.awt.event ActionListener KeyListener))
8-
(:use clojure.contrib.import-static))
8+
(:use clojure.contrib.import-static
9+
[clojure.contrib.seq-utils :only (includes?)]))
910
(import-static java.awt.event.KeyEvent VK_LEFT VK_RIGHT VK_UP VK_DOWN)
1011

1112
; Game board and coordinates. points are [x,y] vectors
1213
(def width 75)
1314
(def height 50)
1415
(def point-size 10)
1516
(def turn-millis 75)
17+
(def win-length 5)
1618

1719
(defn add-points [& pts]
1820
(vec (apply map + pts)))
@@ -27,12 +29,22 @@
2729
VK_DOWN [ 0 1]})
2830

2931
; apple
30-
(defn random-apple [] [(rand-int width) (rand-int height)])
32+
(def *apple* (ref nil))
3133

32-
(def *apple* (ref (random-apple)))
34+
(defn create-apple []
35+
{:location [(rand-int width) (rand-int height)]
36+
:color (Color. 210 50 90)
37+
:type :apple})
3338

3439
; snake
35-
(def *snake* (ref {:body (list [1 1]) :dir [1 0]}))
40+
(def *snake* (ref nil))
41+
42+
(defn create-snake []
43+
{:body (list [1 1])
44+
:dir [1 0]
45+
:type :snake
46+
:color (Color. 15 160 70)})
47+
3648

3749
(defn move [{:keys [body dir] :as snake} & grow]
3850
(assoc snake :body (cons (add-points (first body) dir)
@@ -41,53 +53,83 @@
4153
(defn turn [snake newdir]
4254
(if newdir (assoc snake :dir newdir) snake))
4355

44-
; per-game-turn update
45-
(defn collision? [{[snake-head] :body} apple]
56+
(defn win? [{body :body}]
57+
(>= (count body) win-length))
58+
59+
(defn head-overlaps-body? [{[head & body] :body}]
60+
; have proposed to SS that argument order be reversed:
61+
(includes? head body))
62+
63+
(def lose? head-overlaps-body?)
64+
65+
(defn collision? [{[snake-head] :body} {apple :location}]
4666
(= snake-head apple))
4767

48-
(defn update-positions [snake-ref apple-ref]
68+
; state updates
69+
(defn update-positions [snake apple]
4970
(dosync
50-
(if (collision? @snake-ref @apple-ref)
51-
(do (ref-set apple-ref (random-apple))
52-
(alter snake-ref move :grow))
53-
(alter snake-ref move))))
71+
(if (collision? @snake @apple)
72+
(do (ref-set apple (create-apple))
73+
(alter snake move :grow))
74+
(alter snake move))))
5475

55-
; drawing
56-
(def colors {:apple (Color. 210 50 90) :snake (Color. 15 160 70)})
76+
(defn update-direction [snake newdir]
77+
(dosync (alter snake turn newdir)))
78+
79+
(defn reset-game []
80+
(dosync (ref-set *apple* (create-apple))
81+
(ref-set *snake* (create-snake))))
5782

58-
(defn paint [g pt color]
83+
(reset-game)
84+
85+
; drawing
86+
(defn fill-point [g pt color]
5987
(let [[x y width height] (point-to-screen-rect pt)]
6088
(.setColor g color)
6189
(.fillRect g x y width height)))
6290

63-
(defn paint-snake [g {:keys [body]}]
91+
(defmulti paint (fn [g object & _] (:type object)))
92+
93+
(defmethod paint :snake [g {:keys [body color]}]
6494
(doseq [point body]
65-
(paint g point (colors :snake))))
95+
(fill-point g point color)))
6696

67-
(defn paint-apple [g apple]
68-
(paint g apple (colors :apple)))
97+
(defmethod paint :apple [g {:keys [location color]}]
98+
(fill-point g location color))
6999

70100
; gui elements
101+
(def frame (JFrame. "Snake"))
102+
71103
(def panel
72104
(proxy [JPanel ActionListener KeyListener] []
73105
(paintComponent [g]
74106
(proxy-super paintComponent g)
75-
(paint-snake g @*snake*)
76-
(paint-apple g @*apple*))
107+
(paint g @*snake*)
108+
(paint g @*apple*))
77109
(actionPerformed [e]
78110
(update-positions *snake* *apple*)
111+
(when (lose? @*snake*)
112+
(reset-game)
113+
(JOptionPane/showMessageDialog frame "You lose!"))
114+
(when (win? @*snake*)
115+
(reset-game)
116+
(JOptionPane/showMessageDialog frame "You win!"))
79117
(.repaint this))
80118
(keyPressed [e]
81-
(dosync (alter *snake* turn (dirs (.getKeyCode e)))))
119+
(update-direction *snake* (dirs (.getKeyCode e))))
82120
(keyReleased [e])
83121
(keyTyped [e])))
122+
123+
(def timer (Timer. turn-millis panel))
84124

85125
(doto panel
86126
(.setFocusable true)
87127
(.addKeyListener panel))
88128

89-
(doto (JFrame. "Snake")
129+
(doto frame
90130
(.add panel)
91131
(.setSize (* width point-size) (* height point-size))
92132
(.setVisible true))
93-
(.start (Timer. turn-millis panel))
133+
(.start timer)
134+
135+

0 commit comments

Comments
 (0)