1. (def monkey-positions-2
  2.   "This implementations takes advantage of symmentry, allowing it to
  3. concentrate its efforts on quadrant 1, where x and y are both
  4. non-negative."
  5.   (letfn [(neighbors [[x y]]
  6.             [[(inc x) y]
  7.              [x (inc y)]])
  8.           (digit-value [d]
  9.             (Character/digit d 10))
  10.           (sum-of-digits [n]
  11.             (reduce + 0 (map digit-value (pr-str n))))
  12.           (accessible? [[x y]]
  13.             (>= 19 (+ (sum-of-digits (Math/abs x))
  14.                       (sum-of-digits (Math/abs y)))))
  15.           (mirrors [[x y]]
  16.             (if (zero? x)
  17.               (if (zero? y)
  18.                 [[x y]]
  19.                 [[x y] [x (- y)]])
  20.               (if (zero? y)
  21.                 [[x y] [(- x) y]]
  22.                 [[x y] [(- x) y] [x (- y)] [(- x) (- y)]])))]
  23.     (let [sum-of-digits (memoize sum-of-digits)
  24.           accessible? (memoize accessible?)]
  25.       (fn monkey-positions
  26.         ([]
  27.            (monkey-positions [0 0]))
  28.         ([origin]
  29.            (monkey-positions #{} #{origin}))
  30.         ([visited candidates]
  31.            (lazy-seq
  32.             (when (seq candidates)
  33.                 (->> candidates (mapcat neighbors) set
  34.                      (filter (every-pred (complement candidates)
  35.                                          (complement visited)
  36.                                          accessible?))
  37.                      set
  38.                      (monkey-positions (into visited candidates))
  39.                      (concat (mapcat mirrors candidates))))))))))
  40.  
  41. (defn monkey-count []
  42.   (count (monkey-positions-2)))