Last active
August 29, 2015 13:56
-
-
Save jmgimeno/8976148 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
; From: http://stackoverflow.com/questions/21756079/implementing-snake-with-no-state-almost-in-clojure | |
(ns snake-2 | |
(:import (java.awt Color Dimension) | |
(javax.swing JPanel JFrame Timer JOptionPane) | |
(java.awt.event ActionListener KeyListener) | |
(java.awt.event KeyEvent))) | |
;Constants | |
(def width 80) | |
(def height 60) | |
(def point-size 10) | |
(def time-delay 75) | |
(def dirs {KeyEvent/VK_LEFT [-1 0] | |
KeyEvent/VK_RIGHT [ 1 0] | |
KeyEvent/VK_UP [ 0 -1] | |
KeyEvent/VK_DOWN [ 0 1]}) | |
;Structures | |
(defn create-snake [] | |
{:type :snake | |
:body [[1 0] [0 0]] | |
:dir [1 0]}) | |
(defn create-frog [] | |
{:type :frog | |
:pos [(rand-int width) (rand-int height)]}) | |
(defn create-game [] | |
{:type :game | |
:snake (create-snake) | |
:frog (create-frog)}) | |
;Game Logic | |
(defn add-points [& pts] | |
(vec (apply map + pts))) | |
(defn eat? [snake frog] | |
(= (frog :pos) | |
(first (snake :body)))) | |
(defn lose? [snake] | |
(let [head (first (snake :body)) | |
body (rest (snake :body))] | |
(contains? (set body) head))) | |
(defn turn [snake new-dir] | |
(if (not= new-dir (map #(* -1 %) | |
(snake :dir))) | |
(assoc snake :dir new-dir) | |
snake)) | |
(defn grow-snake [snake] | |
(assoc snake :body (cons (add-points (first (snake :body)) | |
(snake :dir)) | |
(snake :body)))) | |
(defn step [game] | |
(let [grown-snake (grow-snake (game :snake))] | |
(if (eat? grown-snake (game :frog)) | |
(assoc game :snake grown-snake | |
:frog (create-frog)) | |
(assoc game :snake (assoc grown-snake | |
:body (butlast (grown-snake :body))))))) | |
;Interface | |
(defn point-to-screen-rect [pt] | |
(map #(* point-size %) | |
[(pt 0) (pt 1) 1 1])) | |
(defn draw-point [g pt] | |
(let [[x y width height] (point-to-screen-rect pt)] | |
(.setColor g Color/WHITE) | |
(.fillRect g x y width height))) | |
(defn paint [g game] | |
(draw-point g ((game :frog) :pos)) | |
(doseq [pt ((game :snake) :body)] | |
(draw-point g pt)) | |
nil) | |
;The only function that mutates state | |
(defn game-panel [frame game] | |
(proxy [JPanel ActionListener KeyListener] [] | |
(paintComponent [g] | |
(proxy-super paintComponent g) | |
(paint g @game)) | |
(actionPerformed [e] | |
(dosync (alter game step)) | |
(when (lose? (@game :snake)) | |
(dosync (ref-set game (create-game))) | |
(JOptionPane/showMessageDialog frame "You lose!")) | |
(.repaint this)) | |
(keyPressed [e] | |
(dosync | |
(ref-set game (assoc @game :snake (turn (@game :snake) | |
(.getKeyCode e)))))) | |
(getPreferredSize [] | |
(Dimension. (* (inc width) point-size) | |
(* (inc height) point-size))) | |
(keyReleased [e]) | |
(keyTyped [e]))) | |
;Main | |
(defn start-game [] | |
(let [game (ref (create-game)) | |
frame (JFrame. "Snake") | |
panel (game-panel frame game) | |
timer (Timer. time-delay panel)] | |
(doto panel | |
(.setFocusable true) | |
(.addKeyListener panel) | |
(.setBackground Color/BLACK)) | |
(doto frame | |
(.setDefaultCloseOperation (JFrame/DISPOSE_ON_CLOSE)) | |
(.add panel) | |
(.pack) | |
(.setVisible true)) | |
(.start timer) | |
game)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment