在 Clojure 中使用代理的多线程弹跳球程序

发布于 2024-11-07 01:42:44 字数 3240 浏览 1 评论 0原文

我用 clojure 编写了一个多线程弹跳球程序。启动动画线程后,我开始

(send-balls) 

启动弹跳球线程。球不动,这显示在控制台上 -

(#<Agent@5675b3ee FAILED: #<Ref@313d21d6: {:x 759, :y 629, :x-speed 3, :y-speed 1}>> #<Agent@22cf3539 FAILED: #<Ref@247881db: {:x 794, :y 258, :x-speed 2, :y-speed 3}>> #<Agent@51af4309 FAILED: #<Ref@445ead9d: {:x 831, :y 251, :x-speed 4, :y-speed 2}>>)

有人能指出这里发生了什么吗?

(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)

I have written a multithreaded bouncing balls program in clojure. After starting the animation thread, I do-

(send-balls) 

to start the bouncing balls threads. The balls dont move and this is displayed on the console -

(#<Agent@5675b3ee FAILED: #<Ref@313d21d6: {:x 759, :y 629, :x-speed 3, :y-speed 1}>> #<Agent@22cf3539 FAILED: #<Ref@247881db: {:x 794, :y 258, :x-speed 2, :y-speed 3}>> #<Agent@51af4309 FAILED: #<Ref@445ead9d: {:x 831, :y 251, :x-speed 4, :y-speed 2}>>)

Can someone point out whats happening here?

(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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

顾忌 2024-11-14 01:42:44

正如我所看到的主要问题 - 您发送给代理的函数不是与代理一起操作,而是与它的值(参考)一起操作。通过消除 set-new-xset-new-y 函数中的 @ ,你可以让它工作。

(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)

As i see the main problem - functions that you send-off to agents operate NOT with agent, but with its value (the ref). By eliminating @ in set-new-x and set-new-y functions you could make it work.

(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)
站稳脚跟 2024-11-14 01:42:44

我认为你不需要特工内部的裁判。请参阅下面的仅包含代理的工作版本。您可以加载代码,例如。通过 load-file 然后简单地发出 start 。将弹出一个带有所需动画的框架。可以通过将返回的原子reset!设置为false来停止它。通过多次调用 start,您可以根据需要拥有任意数量的独立动画帧。

希望有帮助。

(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?))

I think you don't need refs inside agents. Please see below for a working version with just agents. You can load the code eg. via load-file then simply issue start. A frame will pop up with the desired animation. It can be stopped by reset!ing the returned atom to false. You can have as you many independent animation frames as you wish by calling start more than once.

Hope that helps.

(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?))
巴黎夜雨 2024-11-14 01:42:44

您的发送(或发送)函数(在本例中为:退回)应返回代理的(新)状态。 此处对此进行了完整描述。

Your send (or send-off) function (in this case: bounce) should return the (new) state of the agents. This is fully described here.

我是有多爱你 2024-11-14 01:42:44

代码存在一些问题 -

  1. 正如 Maurits 指出的那样,反弹不会返回代理的新状态。
  2. 弹跳函数中没有任何地方可以将弹跳再次添加到代理的操作队列中。这是必要的,因为新的协调需要一次又一次地计算。

There are a couple of problems with the code -

  1. As Maurits pointed out, bounce does not return the new state of the agent.
  2. There is no place in the bounce function where bounce is added to the action queue of the agent again. This is needed as the new coordinated need to be calculated again and again.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文