2011-05-14 14 views
6

He escrito un programa de pelotas de rebote multiproceso en clojure. Después de iniciar el hilo de la animación, hago-programa de bolas de rebote multiproceso usando agentes en Clojure

(send-balls) 

para comenzar los hilos de las pelotas de rebote. Las bolas no se mueven y esto se muestra en la consola:

(#<[email protected] FAILED: #<[email protected]: {:x 759, :y 629, :x-speed 3, :y-speed 1}>> #<[email protected] FAILED: #<[email protected]: {:x 794, :y 258, :x-speed 2, :y-speed 3}>> #<[email protected] FAILED: #<[email protected]: {:x 831, :y 251, :x-speed 4, :y-speed 2}>>) 

¿Alguien puede indicar qué está pasando aquí?

(import 
'(java.awt Color Graphics Dimension) 
'(java.awt.image BufferedImage) 
'(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def max-x (+ origin-x box-width (* 4 rad))) 
(def max-y (+ origin-y box-height (* 4 rad))) 
(def min-x origin-x) 
(def min-y origin-y) 

(defn init-x 
[] 
(+ (rand-int (- max-x min-x)) min-x)) 

(defn init-y 
[] 
    (+ (rand-int (- max-y min-y)) min-y)) 

(defstruct ball :x :y :x-speed :y-speed) 

(def balls 
(apply vector (map (fn [_] (ref (struct ball (init-x) (init-y) 
(rand-int 10) (rand-int 10)))) 
       (range number-of-balls)))) 

(def ball-agents (apply vector (map agent balls))) 

(defn get-ball 
[n] 
(balls n)) 


(defn set-new-x 
[ball] 
(let [x (@ball :x) 
     x-speed (@ball :x-speed) 
     new-x (+ x x-speed)] 
    (dosync 
    (if (and (>= new-x min-x) (<= new-x max-x)) 
     (ref-set ball (assoc @ball :x new-x)) 
      (ref-set ball (assoc @ball :x-speed (* -1 x-speed))))) 
    (println "the new x is " @(ball :x))) 
@ball) 

(defn set-new-y 
[ball] 
(let [y (@ball :y) 
     y-speed (@ball :y-speed) 
     new-y (+ y y-speed)] 
    (dosync 
    (if (and (>= new-y min-y) (<= new-y max-y)) 
      (ref-set ball (assoc @ball :y new-y)) 
      (ref-set ball (assoc @ball :y-speed (* -1 y-speed)))))) 
@ball) 

(defn paint-balls 
[bg x y] 
(doto bg 
    (.setColor (. Color red)) 
    (.fillOval x y rad rad))) 


(defn render 
[g] 
(let [img (new BufferedImage width height 
       (. BufferedImage TYPE_INT_ARGB)) 
     bg (. img (getGraphics))] 
    (doto bg 
    (.setColor (. Color white)) 
    (.fillRect 0 0 (. img (getWidth)) (. img (getHeight))) 
    (.setColor (. Color red)) 
    (.drawRect origin-x origin-y (+ origin-x box-width) (+ origin-y box-height))) 
    (dorun 
    (for [i (range number-of-balls)] 
     (do 
     (paint-balls bg (@(get-ball i) :x) (@(get-ball i) :y))))) 
    (. g (drawImage img 0 0 nil)) 
    (. bg (dispose)))) 

(def panel (doto (proxy [JPanel] [] 
         (paint [g] (render g))) 
      (.setPreferredSize (new Dimension 
            width 
            height)))) 

(def frame (doto (new JFrame) (.add panel) .pack .show)) 

(def animator (agent nil)) 

(defn bounce 
[x] 
(while true 
    (set-new-x @*agent*) 
    (set-new-y @*agent*) 
    (. Thread (sleep 100)) 
    (println "here in bounce " *agent*))) 




(defn animation 
[x] 
(send-off *agent* animation) 
(. panel (repaint)) 
(. Thread (sleep 100))) 

(defn send-balls 
[] 
(doall 
    (for [i (range number-of-balls)] 
    (do 
     (send-off (ball-agents i) bounce))))) 


(send-off animator animation) 
+0

Parece que su actualización de agente está fallando, probablemente debido a una excepción dentro de la función de rebote. Sospecho que un problema es que está haciendo demasiadas dereferencias, es decir, "@ * agente *" debería ser realmente "\ * agente \ *". – mikera

+0

@mikera - Lo intenté, pero eso no es ... – Pranav

Respuesta

3

Como veo el problema principal: las funciones que envía a los agentes NO funcionan con el agente, sino con su valor (el ref). Al eliminar @ en set-new-x y set-new-y funciones que podría hacer que funcione.

(ns balls) 

(import 
    '(java.awt Color Graphics Dimension) 
    '(java.awt.image BufferedImage) 
    '(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def max-x (+ origin-x box-width (* 4 rad))) 
(def max-y (+ origin-y box-height (* 4 rad))) 
(def min-x origin-x) 
(def min-y origin-y) 

(defn init-x 
[] 
(+ (rand-int (- max-x min-x)) min-x)) 

(defn init-y 
[] 
    (+ (rand-int (- max-y min-y)) min-y)) 

(defstruct ball :x :y :x-speed :y-speed) 

(def balls 
(apply vector (map (fn [_] (ref (struct ball (init-x) (init-y) 
(rand-int 10) (rand-int 10)))) 
       (range number-of-balls)))) 

(def ball-agents (apply vector (map agent balls))) 

(defn get-ball 
[n] 
(balls n)) 


(defn set-new-x 
    [ball] 
    (let [x (ball :x) 
     x-speed (ball :x-speed) 
     new-x (+ x x-speed)] 
    (dosync 
     (if (and (>= new-x min-x) (<= new-x max-x)) 
     (alter ball assoc :x new-x) 
     (alter ball assoc :x-speed (* -1 x-speed))))) 
    ball) 

(defn set-new-y 
    [ball] 
    (let [y (ball :y) 
     y-speed (ball :y-speed) 
     new-y (+ y y-speed)] 
    (dosync 
     (if (and (>= new-y min-y) (<= new-y max-y)) 
     (alter ball assoc :y new-y) 
     (alter ball assoc :y-speed (* -1 y-speed)))) 
    ball)) 

(defn paint-balls 
[bg x y] 
(doto bg 
    (.setColor (. Color red)) 
    (.fillOval x y rad rad))) 


(defn render 
[g] 
(let [img (new BufferedImage width height 
       (. BufferedImage TYPE_INT_ARGB)) 
     bg (. img (getGraphics))] 
    (doto bg 
    (.setColor (. Color white)) 
    (.fillRect 0 0 (. img (getWidth)) (. img (getHeight))) 
    (.setColor (. Color red)) 
    (.drawRect origin-x origin-y (+ origin-x box-width) (+ origin-y box-height))) 
    (dorun 
    (for [i (range number-of-balls)] 
     (do 
     (paint-balls bg (@(get-ball i) :x) (@(get-ball i) :y))))) 
    (. g (drawImage img 0 0 nil)) 
    (. bg (dispose)))) 

(def panel (doto (proxy [JPanel] [] 
         (paint [g] (render g))) 
      (.setPreferredSize (new Dimension 
            width 
            height)))) 

(def frame (doto (new JFrame) (.add panel) .pack .show)) 

(def animator (agent nil)) 

(defn bounce 
[ball_cur] 
(do 
    (Thread/sleep 100) 
    (send-off *agent* bounce) 
    (set-new-x (set-new-y ball_cur)))) 

(defn animation 
[x] 
(send-off *agent* animation) 
(. panel (repaint)) 
(. Thread (sleep 100))) 

(defn send-balls 
[] 
(doall 
    (for [i (range number-of-balls)] 
    (do 
     (send-off (ball-agents i) bounce))))) 


(send-off animator animation) 
(send-balls) 
1

Su función de envío (o envío) (en este caso: rebote) debe devolver el estado (nuevo) de los agentes. Esto se describe completamente en here.

1

Hay un par de problemas con el código -

  1. Como Maurits señaló, el rebote no devuelve el nuevo estado del agente.
  2. No hay lugar en la función de rebote donde rebote se agrega a la cola de acción del agente de nuevo. Esto es necesario ya que la nueva necesidad coordinada se debe calcular una y otra vez.
3

Creo que no necesita refs dentro de los agentes. Vea a continuación una versión de trabajo con solo agentes. Puedes cargar el código ej. a través de load-file y luego simplemente emita start. Aparecerá un cuadro con la animación deseada. Se puede detener por reset! ing el átomo devuelto a false. Puede tener tantos cuadros de animación independientes como desee iniciando llamadas más de una vez.

Espero que ayude.

(import 
'(java.awt Color Graphics Dimension) 
'(java.awt.image BufferedImage) 
'(javax.swing JPanel JFrame)) 

(def width 1000) 
(def height 1000) 

(def number-of-balls 3) 

(def rad 20) 

(def origin-x 100) 
(def origin-y 100) 
(def box-height 500) 
(def box-width 700) 
(def min-borders {:x origin-x 
        :y origin-y}) 
(def max-borders {:x (+ origin-x box-width (* 4 rad)) 
        :y (+ origin-y box-height (* 4 rad))}) 

(defn init 
[coord] 
(+ (rand-int (- (get max-borders coord) (get min-borders coord))) 
    (get min-borders coord))) 

(defn init-balls 
    [] 
    (->> (repeatedly number-of-balls 
        #(array-map :x (init :x) :y (init :y) 
           :x-speed (rand-int 10) 
           :y-speed (rand-int 10))) 
    (map agent) 
    vec)) 

(defn update-coordinate 
    [ball coord-key speed-key] 
    (let [coord (get ball coord-key) 
     speed (get ball speed-key) 
     new-c (+ coord speed)] 
    (if (<= (get min-borders coord-key) new-c (get max-borders coord-key)) 
     (assoc ball coord-key new-c) 
     (assoc ball speed-key (- speed))))) 

(defn paint-ball 
    [bg x y] 
    (doto bg 
    (.setColor Color/red) 
    (.fillOval x y rad rad))) 

(defn render 
    [g balls] 
    (let [img (BufferedImage. width height BufferedImage/TYPE_INT_ARGB) 
     bg (.getGraphics img)] 
    (doto bg 
     (.setColor Color/white) 
     (.fillRect 0 0 (.getWidth img) (.getHeight img)) 
     (.setColor Color/red) 
     (.drawRect origin-x origin-y 
       (+ origin-x box-width) (+ origin-y box-height))) 
    (doseq [b balls] 
     (let [ball @b] 
     (paint-ball bg (:x ball) (:y ball)))) 
    (.drawImage g img 0 0 nil))) 

(defn bounce 
    [ball running?] 
    (when @running? 
    (send-off *agent* bounce running?)) 
    (Thread/sleep 100) 
    (-> ball 
    (update-coordinate :x :x-speed) 
    (update-coordinate :y :y-speed))) 

(defn animation 
    [panel running?] 
    (while @running? 
    (javax.swing.SwingUtilities/invokeAndWait #(.repaint panel)) 
    (Thread/sleep 100))) 

(defn start 
    [] 
    (let [running? (atom true) 
     balls (init-balls) 
     panel (doto (proxy [JPanel] [] 
         (paint [g] (render g balls))) 
        (.setPreferredSize (Dimension. width height))) 
     frame (doto (JFrame.) (.add panel) .pack .show)] 
    (doseq [b balls] 
     (send-off b bounce running?)) 
    (future (animation panel running?)) 
    running?)) 
+0

Hay algo mal con la función de actualización de coordenadas. – Pranav

+0

@pranav Woops. Un error cut'n'paste. Fijo. – kotarak

Cuestiones relacionadas