(def monkey-positions-2
"This implementations takes advantage of symmentry, allowing it to
concentrate its efforts on quadrant 1, where x and y are both
non-negative."
(letfn [(neighbors [[x y]]
[[(inc x) y]
[x (inc y)]])
(digit-value [d]
(Character/digit d 10))
(sum-of-digits [n]
(reduce + 0 (map digit-value (pr-str n))))
(accessible? [[x y]]
(>= 19 (+ (sum-of-digits (Math/abs x))
(sum-of-digits (Math/abs y)))))
(mirrors [[x y]]
(if (zero? x)
(if (zero? y)
[[x y]]
[[x y] [x (- y)]])
(if (zero? y)
[[x y] [(- x) y]]
[[x y] [(- x) y] [x (- y)] [(- x) (- y)]])))]
(let [sum-of-digits (memoize sum-of-digits)
accessible? (memoize accessible?)]
(fn monkey-positions
([]
(monkey-positions [0 0]))
([origin]
(monkey-positions #{} #{origin}))
([visited candidates]
(lazy-seq
(when (seq candidates)
(->> candidates (mapcat neighbors) set
(filter (every-pred (complement candidates)
(complement visited)
accessible?))
set
(monkey-positions (into visited candidates))
(concat (mapcat mirrors candidates))))))))))
(defn monkey-count []
(count (monkey-positions-2)))