Skip to content

Instantly share code, notes, and snippets.

@jmgimeno
Last active August 29, 2015 13:56
Show Gist options
  • Save jmgimeno/8976148 to your computer and use it in GitHub Desktop.
Save jmgimeno/8976148 to your computer and use it in GitHub Desktop.
; 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