On the Java Interop page (http://clojure.org/java_interop), the proxy
macro is described as creating "...a instance of a proxy class that
implements the named class/interface(s)...". Is this done using Java
Dynamic Proxy Classes (http://java.sun.com/j2se/1.5.0/docs/guide/
reflection/proxy.html)?
Background to this question: I came across a blog post (http://
www.plt1.com/1070/even-smaller-snake/) which claims to implement the
game "Snake" in 35 lines of clojure. However, it doesn't run; for one
thing, in line 26, the syntax for doseq is wrong. Another problem has
to do with calling methods from the JPanel class on the proxied JPanel
object created in the run-snake function. It looks like you shouldn't
call methods on proxied classes that aren't the ones you supplied when
creating the proxy - is that true?
> Hi,
> I ran it with the changes and got the message:
> java.lang.IllegalArgumentException: Don't know how to create ISeq
> from: Symbol (NO_SOURCE_FILE:22)
>
> What can be the problem?
I recommend you try this:
- copy and paste the code from the website into a file called
snake.clj stored at the top level of a directory that's in classpath.
- replace the "import" form at the top of the page with this (be
careful with quoting in this edit):
(ns snake
(:import (java.awt.event KeyEvent ActionListener KeyListener)
(javax.swing JPanel JFrame Timer)))
- fix the doseq and doto forms
Then, at the repl run it with:
user=> (require 'snake)
nil
user=> (snake/run-snake)
Click on the window that comes up and use the arrow keys at the
keyboard to control the snake.
If you still have trouble, please post info about it here. At that
point we should have more to work with.
--Steve
java -cp clojure.jar clojure.lang.Repl snake.clj
--Chouser
Very cool demo, Abhishek, thanks.
--Steve
(import '(java.awt Color) '(javax.swing JPanel JFrame Timer)
'(java.awt.event KeyEvent ActionListener KeyListener))
(defn gen-apple [_] [(rand-int 750) (rand-int 550)])
(defn move [{:keys [body dir] :as snake} & grow]
(assoc snake :body (cons (vec (map #(+ (dir %) ((first body) %)) [0
1]))
(if grow body (butlast body)))))
(defn turn [snake newdir] (if newdir (assoc snake :dir newdir) snake))
(defn collision? [{[b] :body} a]
(every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1]))
(defn paint [g p c] (.setColor g c) (.fillRect g (p 0) (p 1) 10 10))
(def dirs {KeyEvent/VK_LEFT [-10 0] KeyEvent/VK_RIGHT [10 0]
KeyEvent/VK_UP [0 -10] KeyEvent/VK_DOWN [0 10]})
(def apple (atom (gen-apple nil)))
(def snake (atom {:body (list [10 10]) :dir [10 0]}))
(def colors {:apple (Color. 210 50 90) :snake (Color. 15 160 70)})
(def panel (proxy [JPanel ActionListener KeyListener] []
(paintComponent [g] (proxy-super paintComponent g)
(paint g @apple (colors :apple))
(doseq [p (:body @snake)]
(paint g p (colors :snake))))
(actionPerformed [e] (if (collision? @snake @apple)
(do (swap! apple gen-apple)
(swap! snake move :grow))
(swap! snake move))
(.repaint this))
(keyPressed [e] (swap! snake turn (dirs (.getKeyCode e))))
(keyReleased [e])
(keyTyped [e])))
(doto panel (.setFocusable true)(.addKeyListener panel))
(doto (JFrame. "Snake")(.add panel)(.setSize 800 600)(.setVisible true))
(.start (Timer. 75 panel))
Would you be willing to explain why you think it's correct to use
atoms here? I considered it, but wasn't sure it was right. There are
two mutable objects, after all -- do they not need to be coordinated?
I realize that in a program like this it doesn't really matter, and
maybe that's part of my problem.
Great use of :grow instead of 'true' when calling 'move'. So sharp, Stephen!
--Chouser
On Wed, Dec 24, 2008 at 1:44 AM, Stephen C. Gilardi <sque...@mac.com> wrote:Based on Chouser's version, but using atoms, a splash of color, a littlemore destructuring and more separation of model and view.
Would you be willing to explain why you think it's correct to use atoms here? I considered it, but wasn't sure it was right. There are two mutable objects, after all -- do they not need to be coordinated?
Great use of :grow instead of 'true' when calling 'move'. So sharp, Stephen!
Snake frame would appear with square ball that moves and another that does not move.Below is what I got each time I try to play with arrow keys. I count on you as always to come to my help.
user=> (require 'snake)
nil
user=> (snake/run-snake)nil
user=>
Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: keyReleased
at clojure.proxy.javax.swing.JPanel$ActionListener$KeyListener.keyReleased(Unknown Source)
at java.awt.Component.processKeyEvent(Unknown Source)
at javax.swing.JComponent.processKeyEvent(Unknown Source)
at clojure.proxy.javax.swing.JPanel$ActionListener$KeyListener.processKeyEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at clojure.proxy.javax.swing.JPanel$ActionListener$KeyListener.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
It was to avoid this exception that my version included an empty
implementation of keyReleased.
--Chouser
> Please send me yours then.
Already did:
http://groups.google.com/group/clojure/msg/4f00d2a3b5da8444
And Mr. Gilardi improved on it here:
http://groups.google.com/group/clojure/msg/90316675320091cf
--Chouser
--
R. Mark Volkmann
Object Computing, Inc.
To my eye, those uses of % _are_ within an anonymous function:
(defn collision? [{[b] :body} a]
(every? #(<= (- (a %) 10) (b %) (+ 10 (a %))) [0 1]))
Randall Schulz