Created
July 4, 2010 20:31
-
-
Save prasincs/463729 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; A snake program adapted from Stewart Halloway's Programming Clojure | |
; Author: Prasanna Gautam | |
(ns reader.snake | |
(:import (java.awt Color Dimension) | |
(javax.swing JPanel JFrame Timer JOptionPane JLabel) | |
(java.awt.event ActionListener KeyListener)) | |
(:use clojure.contrib.import-static [clojure.contrib.seq-utils :only (includes?)])) | |
(import-static java.awt.event.KeyEvent VK_LEFT VK_RIGHT VK_UP VK_DOWN) | |
(def width 75) | |
(def height 50) | |
(def point-size 10) | |
(def board-width (* width point-size)) | |
(def board-height (* height point-size)) | |
(def turn-millis 100) | |
(def board-color (Color. 0 0 0)) | |
(def win-length 12) | |
(def dirs {VK_LEFT [-1 0] | |
VK_RIGHT [1 0] | |
VK_UP [0 -1] | |
VK_DOWN [0 1]}) | |
(defn add-points [& pts] | |
(vec (apply map + pts))) | |
(defn point-to-screen-rect [pt] | |
(map #(* point-size %) | |
[(pt 0) (pt 1) 1 1])) | |
(defn create-apple [] { | |
:location [(rand-int width) (rand-int height)] | |
:color (Color. 210 50 90) | |
:type :apple}) | |
(defn create-board [] {:width board-width :height board-height :type :board}) | |
(defn init-score [] {:win 0 :loss 0 :eaten 0 :type :score}) | |
(defn inc-loss [score] (dosync ( alter score #(assoc % :loss (inc (:loss %)))))) | |
(defn inc-eaten [score] (dosync ( alter score #(assoc % :eaten (inc (:eaten %)))))) | |
(defn inc-win [score] (dosync ( alter score #(assoc % :win (inc (:win %)))))) | |
(defn create-snake [] {:body (list [1 1]) | |
:dir [1 0] | |
:type :snake | |
:color (Color. 15 160 70)}) | |
(defn move [{:keys [body dir] | |
:as snake} & grow] | |
(assoc snake :body (cons (add-points (first body) dir) | |
(if grow body (butlast body))))) | |
(defn win? [{body :body}] | |
(>= (count body) win-length)) | |
;(defn outside? [{[head & body] :body}] (let [x (head 0) y (head 1)] (println head x y) (or (>= x width) (<= x 0) (>= y height) (<= y 0)))) | |
(defn outside? [{[head & body] :body}] (def x (head 0)) (def y (head 1)) (true? (or (> x width) (< x 0) (> y height) (< y 0))) ) | |
(defn head-overlaps-body? [{[head & body] :body}] | |
(includes? body head)) | |
(defn lose? [snake] (or ( head-overlaps-body? snake) ( outside? snake))) | |
(defn eats? [{[snake-head] :body} {apple :location}] | |
(= snake-head apple)) | |
(defn turn [snake newdir] | |
(assoc snake :dir newdir)) | |
(defn reset-game [snake apple] | |
(dosync (ref-set apple (create-apple)) | |
(ref-set snake (create-snake))) | |
nil) | |
(defn update-direction [snake newdir] | |
(when newdir (dosync (alter snake turn newdir)))) | |
(defn update-positions [snake apple] | |
(dosync | |
(if ( eats? @snake @apple) | |
(do (ref-set apple (create-apple)) | |
(alter snake move :grow) | |
) | |
(alter snake move))) | |
nil) | |
(defn label-text [text] (JLabel. text)) | |
(defn fill-point [g pt color] | |
(let [[x y width height] (point-to-screen-rect pt)] | |
(.setColor g color) | |
(.fillRect g x y width height))) | |
(defmulti paint (fn [g object & _] (:type object))) | |
(defmethod paint :apple [g {:keys [location color]}] | |
(fill-point g location color)) | |
(defmethod paint :snake [g {:keys [body color]}] | |
(doseq [point body] | |
(fill-point g point color))) | |
(defmethod paint :score [g {:keys [win loss eaten]}] | |
(.drawString g (format "win: %d loss:%d eaten: %d" win loss eaten) 600 10) | |
) | |
(defmethod paint :board [g {:keys [width height]}] | |
(.setColor g board-color) | |
(.fillRect g 0 0 width height) | |
) | |
(defn game-panel [frame snake apple score] | |
(let [board (ref (create-board))] | |
(proxy [JPanel ActionListener KeyListener] [] | |
(paintComponent [g] | |
(proxy-super paintComponent g) | |
(paint g @board) | |
(paint g @snake) | |
(paint g @apple) | |
(paint g @score) | |
) | |
(actionPerformed [e] | |
(update-positions snake apple) | |
(outside? @snake) | |
(when (lose? @snake ) | |
(reset-game snake apple) | |
(inc-loss score) | |
(JOptionPane/showMessageDialog frame "You lose!")) | |
(when (win? @snake) | |
(reset-game snake apple) | |
(inc-win score) | |
(JOptionPane/showMessageDialog frame "You win!")) | |
(when (eats? @snake @apple) | |
(inc-eaten score)) | |
(.repaint this)) | |
(keyPressed [e] | |
(update-direction snake (dirs (.getKeyCode e)))) | |
(getPreferredSize [] | |
(Dimension. (* (inc width) point-size) | |
(* (inc height) point-size))) | |
(keyReleased [e]) | |
(keyTyped [e])))) | |
(defn game [] | |
(let [snake (ref (create-snake)) | |
apple (ref (create-apple)) | |
score (ref (init-score)) | |
frame (JFrame. "Snake") | |
panel (game-panel frame snake apple score) | |
timer (Timer. turn-millis panel)] | |
(doto panel | |
(.setFocusable true) | |
(.addKeyListener panel)) | |
(doto frame | |
(.add panel) | |
(.pack) | |
(.setVisible true)) | |
(.start timer) | |
[snake, apple, timer])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment