(ns user)

(defn collatz-distance
  ([n] (collatz-distance 0 n))
  ([acc n]
   (cond
    (= n 1) acc
    (even? n) (recur (inc acc) (quot n 2))
    :else (recur (inc acc) (inc (* 3 n))) ) ) )

(def rnd (new java.util.Random))

(defn random-positive-number []
  (let [n (. rnd nextInt)]
    (if (> n 0)
      n
      (random-positive-number))))

(def best-number (ref 1))
(def biggest-distance (ref 0))
(def who-found-it (ref :nobody))

(defn try-a-number [my-value who]
  (let [new-number (random-positive-number)
        new-distance (collatz-distance new-number)]
    (if (> new-distance my-value)
      (dosync
        (if (> new-distance @biggest-distance)
          (do
            (ref-set best-number new-number)
            (ref-set biggest-distance new-distance)
            (ref-set who-found-it who)
            new-distance )       ; value I found becomes my new value
          @biggest-distance ) )  ; get biggest-distance as my  new value
      my-value ) ) )             ; keep myqui old value

(def donatello     (agent 0))
(def raphael       (agent 0))
(def leonardo      (agent 0))
(def michaelangelo (agent 0))

(defn dump []
  (println @who-found-it "found" @biggest-distance "for" @best-number)
  (println "donatello" @donatello ", raphael" @raphael
           ", leonardo" @leonardo ", michaelangelo" @michaelangelo))

(defn main [how-many-tries]
  (if (zero? how-many-tries)
    (do
      (await donatello raphael leonardo michaelangelo)
      (dump)
      [@who-found-it @best-number @biggest-distance] ) ; final result
    (do
      (send donatello     try-a-number :donatello)
      (send raphael       try-a-number :raphael)
      (send leonardo      try-a-number :leonardo)
      (send michaelangelo try-a-number :michaelangelo)
      (recur (dec how-many-tries))
    ) ) )
