      c))
 
 ;; The second function will return a channel only with the events that we care
-;; about, that is keyup events of the document that happens when an arrow key is
-;; pressed. Also, we would like something more descriptive than the raw DOM
-;; event. So, we'll take every keyup event of the document, map it to its key
-;; code, stop if they don't belong to an arrow key or map it to either :left,
-;; :up, :right or :down when they do. The second function returns a channel that
-;; does just that.
+;; about, that is, keyup events of the document that happens when an arrow key
+;; is pressed. Also, we would like something more descriptive than a raw DOM
+;; event. We'll take every keyup event of the document, map it to its key code,
+;; stop if they don't belong to an arrow key or map it to either :left, :up,
+;; :right or :down when they do.
 
 (defn keys-chan
   "Returns a channel of :left, :up, :right and :down events sourced from arrow

  (-> v nil-indexes shuffle first))

;; Then, we associate the index with a new tile in the board representation. A
;; function that builds the tile must be provided because the details about what
;; a tile looks like aren't really important and somebody else should take care 
;; of them.

(defn add-tile
  "Takes a board and returns a new one with one more tile, where tile-fn is a
   function that returns a new tile."
  [tile-fn board]
  (assoc board (rand-nil-index board) (tile-fn)))


;; - :key, some keyword that uniquely identifies the tile
;; - :new, the boolean true
;; The same function will also take two tiles and return the result of merging
;; them together, that is, a new tile described by:
;; - :val, the sum of the :val of the source tiles
;; - :key, some keyword that uniquely identifies the tile
;; - :src, a vector containing the source tiles, responsible for originating
;;   this one

;; ## Specification

(defn build-tile
  "Returns a map with :val associated to val and :key to an unique keyword. If
   no val is supplied, it defaults to 2 most of the time but it might default to
   4, and the key :new is mapped to true. Alternatively, when applied to two
   tiles, x and y, the result is the same as calling it with the sum of the
   tiles :val and associng the key :src to a vector containing x and y."
  ([] (assoc (build-tile (if (< (rand) 0.8) 2 4)) :new true))
  ([val] {:val val :key (keyword (gensym ""))})
  ([x y] (assoc (build-tile (+ (:val x) (:val y))) :src [x y])))

;; Before going further, an implementation of the ITile protocol, presented in
;; section 'Tile synthesis', must be provided. The synthesis of two tiles with
;; the same :val is another tile (described above), but the synthesis of two
;; tiles with different :val is nil. Also, a tile with a :val of 2048 can't be
;; synthesized anymore.

(extend-type cljs.core/PersistentArrayMap
