(defn cols [board]
  (mapv vec (apply map list board)))

(defn flipv [v]
  (mapv #(if (> % 0) 0 1) v))

(defn flip-row [board n]
  (assoc board n (flipv (get board n))))

(defn flip-col [board n]
  (cols (flip-row (cols board) n)))

(defn play-rand [board n]
  (if (= n 0)
    board
    (let [f (if (= (rand-int 2) 0) flip-row flip-col)]
      (recur (f board (rand-int (count board))) (dec n)))))

(defn rand-binary-vec [size]
  (vec (take size (repeatedly #(rand-int 2)))))

(defn rand-binary-board [size]
  (vec (take size (repeatedly #(rand-binary-vec size)))))

(defn numbers->letters [coll]
  (map #(char (+ 97 %)) coll))

(defn column-labels [size]
  (apply str (interpose " " (numbers->letters (range size)))))

(defn print-board [board]
  (let [size (count board)]
    (println "\t " (column-labels size))
    (dotimes [n size] (println (inc n) "\t" (board n)))))

(defn key->move [key]
  (let [start (int (first key))
        row-value (try (Long/valueOf key) (catch NumberFormatException e))]
    (cond
      (<= 97 start 122) [:col (- start 97)]
      (<= 65 start 90) [:col (- start 65)]
      (> row-value 0) [:row (dec row-value)]
     :else nil)))

(defn play-game [target-board current-board n]
  (println "\nTurn " n)
  (print-board current-board)
  (if (= target-board current-board)
    (println "You win!")
    (let [move (key->move (read-line))
          axis (first move)
          idx (second move)]
      (cond
        (= axis:row) (play-game target-board (flip-row current-board idx) (inc n))
        (= axis:col) (play-game target-board (flip-col current-board idx) (inc n))
       :else (println "Quitting!")))))

(defn -main
  "Flip the Bits Game!"
  [& args]
  (if-not (empty? args)
    (let [target-board (rand-binary-board (Long/valueOf (first args)))]
      (println "Target")
      (print-board target-board)
      (play-game target-board (play-rand target-board 3) 0))))