(def max-piles-count 7)
(def max-stones-count 10)
(defn inc-val [col key] (assoc col key (inc (col key 0))))
(defn dec-val [col key] (let [val (col key)] (if (== 1 val) (dissoc col key) (assoc col key (dec val)))))
(defn take-stones [state position count] (inc-val (dec-val state position) (- position count)))
(defn move-from [state]
(for [pos (keys state) cnt (range 1 4) :when (<= cnt pos)]
(take-stones state pos cnt)))
(defn next-state [state]
(let [pos (first (filter #(< 0 %) (sort < (keys state))))]
(case pos
nil nil
1 (-> state (dec-val 1) (inc-val 0))
(let [val (+ (state 0 0) (state (dec pos) 0) 1)]
(-> state (dec-val pos) (dissoc 0) (assoc (dec pos) val))))))
(defn update-values [[state-values state]] [(reduce (fn [sv st] (assoc sv st true)) state-values (move-from state)) state])
(defn find-state [[state-values state]] [state-values (->> (iterate next-state state) (drop 1) (drop-while #(state-values %)) first)])
(defn calculate []
(let [root {(dec max-stones-count) max-piles-count}]
(->> (iterate (comp update-values find-state) [{root true} root])
(some #(when (nil? (% 1)) (% 0))))))
(defn number->state [number]
((reduce (fn [[st n] _] [(inc-val st (rem n 10)) (quot n 10)]) [{} number] (range max-piles-count)) 0))
(defn get-moves [number]
(for [[pos tens] (take max-piles-count (iterate (fn [[n e]] [(inc n) (* 10 e)]) [0 1])) cnt (range 1 4)
:when (< cnt (- max-stones-count (rem (quot number tens) 10)))] (+ number (* cnt tens))))
(defn solve [number]
(let [state-values (calculate)]
(if (state-values (number->state number))
(do (println "First win")
(doseq [move (filter #(not (state-values (number->state %))) (get-moves number))]
(print (str move " "))))
(println "Second win"))))
;main
(solve 16)