     ""
     [is-first-player state timeout grid-width grid-height]
     ; TODO Return if timeout
-    (let [[negamax-value move] (negamax-inner state Double/NEGATIVE_INFINITY Double/POSITIVE_INFINITY timeout is-first-player 5 grid-width grid-height)]
+    (let [[negamax-value move] (negamax-inner state Double/NEGATIVE_INFINITY Double/POSITIVE_INFINITY timeout is-first-player 3 grid-width grid-height)]
       (prn "Negamax-value" negamax-value)
         move))
 


    (reduce + (map (fn [path]
                     (assert (= :empty (nth path 5)))
                     (+
                       (get-in heuristic-dict (take 5 path))
                       (get-in heuristic-dict (reverse (take-last 5 path))))
                     ) paths))))

(defn get-value-for-state


(def heuristic-dict (fill-heuristics-dict))

(defn assoc-in!
  "Associates a value in a nested associative structure, where ks is a
  sequence of keys and v is the new value and returns a new nested structure.
  If any levels do not exist, hash-maps will be created."
  {:added  "1.0"
   :static true}
  [m [k & ks] v]
  (if ks
    (assoc! m k (assoc-in! (get m k) ks v))
    (assoc! m k v)))

(defn compute-path-value
  [path]
  (loop [left-part (reverse (take 5 path))
         right-part (take-last 5 path)

         ; States
         prev-left-is-dead false
         prev-right-is-dead false
         prev-left-direct-streak-is-dead false
         prev-right-direct-streak-is-dead false

         prev-left-streak-type (first left-part)
         prev-left-streak-count 0
         prev-left-partial-streak-count 0
         prev-left-direct-streak 0

         prev-right-streak-type (first right-part)
         prev-right-streak-count 0
         prev-right-partial-streak-count 0
         prev-right-direct-streak 0]
    (if (or
          (prn prev-left-direct-streak prev-left-streak-type prev-right-streak-type prev-right-direct-streak)
          (prn prev-left-is-dead prev-right-is-dead)
          (empty? left-part)
            (and prev-left-is-dead prev-right-is-dead))
      (if (and (not= prev-left-streak-type prev-right-streak-type);
               (not= prev-left-streak-type :wall)
               (not= prev-right-streak-type :wall))
        ; Types differents
        (+ (cond
             (prn prev-left-partial-streak-count prev-right-partial-streak-count) -3332
             (= :wall prev-left-streak-type) 0
             (= 4 prev-left-direct-streak) (cond (= prev-left-streak-type :max) Double/POSITIVE_INFINITY
                                                 (= prev-left-streak-type :min) 1000000
                                                 :else 0)
             (and
               (= 3 prev-left-direct-streak)
               (< 0 prev-left-partial-streak-count)
               (< 0 prev-right-partial-streak-count)
               (= 0 prev-right-direct-streak)) (if (= prev-left-streak-type :min) 50000 24998)

             (and
               (= 4 prev-left-direct-streak)
               (= 0 prev-left-partial-streak-count)
               (or (= 0 prev-right-direct-streak)
                   (and (< 0 prev-right-direct-streak)
                        (not= prev-left-streak-type prev-right-streak-type)))) (if (= prev-left-streak-type :min) 50000 24998)

             (<= 4 (+ prev-left-streak-count prev-left-partial-streak-count)) (+ prev-left-direct-streak prev-left-streak-count)
             :else 0)

           (cond
             (prn prev-left-partial-streak-count prev-right-partial-streak-count) -333
             (= :wall prev-right-streak-type) 0
             (= 4 prev-right-direct-streak) (cond
                                              (= prev-right-streak-type :max) Double/POSITIVE_INFINITY
                                                  (= prev-right-streak-type :min) 1000000
                                                  :else 0)
             (and
               (= 3 prev-right-direct-streak)
               (< 0 prev-right-partial-streak-count)
               (< 0 prev-left-partial-streak-count)
               (= 0 prev-left-direct-streak)) (if (= prev-right-streak-type :min) 50000 24998)

             (and
               (= 4 prev-right-direct-streak)
               (= 0 prev-right-partial-streak-count)
               (or (= 0 prev-left-direct-streak)
                   (and (< 0 prev-left-direct-streak)
                        (not= prev-left-streak-type prev-right-streak-type)))) (if (= prev-right-streak-type :min) 50000 24998)

             (<= 4 (+ prev-right-streak-count prev-right-partial-streak-count)) (+ prev-right-direct-streak prev-right-streak-count)
             :else 0)
           )
        ; Types identiques ou mur
        (cond
          (= :wall prev-left-streak-type prev-right-streak-type) 0;
          (= 4 (+ prev-left-direct-streak prev-right-direct-streak)) (cond (= prev-left-streak-type :max) Double/POSITIVE_INFINITY
                                                                           (= prev-left-streak-type :min) 1000000
                                                                           (= prev-right-streak-type :max) Double/POSITIVE_INFINITY
                                                                           (= prev-right-streak-type :min) 1000000
                                                                           :else 0);
          (and (= 3 (+ prev-left-direct-streak prev-right-direct-streak)) (>= (+ prev-left-partial-streak-count prev-right-partial-streak-count) 2)) (if (or
                                                                                                                                                           (= prev-left-streak-type :min)
                                                                                                                                                           (= prev-right-streak-type :min))
                                                                                                                                                          50000 24998)
          (<= 5 (+ prev-left-direct-streak prev-right-direct-streak)) 0

          :else (+ prev-left-direct-streak
                   prev-left-streak-count
                   prev-right-direct-streak
                   prev-right-streak-count)))

      (let [left (first left-part)
            right (first right-part)
            left-is-dead (or prev-left-is-dead (= left :wall) (not (or (= left :empty) (= prev-left-streak-type :empty) (= left prev-left-streak-type))))
            right-is-dead (or prev-right-is-dead (= right :wall) (not (or (= right :empty) (= prev-right-streak-type :empty) (= right prev-right-streak-type))))

            left-direct-streak-is-dead (or prev-left-direct-streak-is-dead
                                           (= left :empty)
                                           (= left :wall)
                                           (not= left prev-left-streak-type))
            right-direct-streak-is-dead (or prev-right-direct-streak-is-dead
                                            (= right :empty)
                                            (= right :wall)
                                            (not= right prev-right-streak-type))


            left-streak-type (if (= :empty prev-left-streak-type) left prev-left-streak-type)
            right-streak-type (if (= :empty prev-right-streak-type) right prev-right-streak-type)

            left-streak-count (cond (or left-is-dead (= left :empty)) prev-left-streak-count
                                    :else (inc prev-left-streak-count))
            right-streak-count (cond (or right-is-dead (= right :empty)) prev-right-streak-count
                                     :else (inc prev-right-streak-count))

            left-partial-streak-count (cond left-is-dead prev-left-partial-streak-count
                                            :else (inc prev-left-partial-streak-count))
            right-partial-streak-count (cond right-is-dead prev-right-partial-streak-count
                                             :else (inc prev-right-partial-streak-count))

            left-direct-streak (if left-direct-streak-is-dead prev-left-direct-streak (inc prev-left-direct-streak))
            right-direct-streak (if right-direct-streak-is-dead prev-right-direct-streak (inc prev-right-direct-streak))

            ]
        (recur
          (rest left-part)
          (rest right-part)

          ; States
          left-is-dead
          right-is-dead

          left-direct-streak-is-dead
          right-direct-streak-is-dead

          left-streak-type
          left-streak-count
          left-partial-streak-count
          left-direct-streak

          right-streak-type
          right-streak-count
          right-partial-streak-count
          right-direct-streak)))))

(defn build-heuristic-dict-with-awesomeness
  []
  (persistent!
    (reduce
      (fn [col path]
        (assoc-in! col path (compute-path-value path)))
      (transient {})
      []))
  )

(def adjacent-transform
  (for [c1 (range -2 3)
        c2 (range -2 3)]
    [c1 c2]))

(defn in-bounds?
