                                 (filter (set (keys key-map)))
                                 (map key-map))))))
 
-;; Finally we arrived to the part where we put everything together, the game
-;; loop. The loop's bindings will serve us to keep the state we need, that is,
-;; the board and the action we want to perform. On each iteration, we either
-;; render the board or wait for a move event. Rendering the board means:
-;; - render the board in the translation phase,
-;; - wait for the transition animations,
-;; - render the board in the reveal phase, and
-;; - wait for the appearence animations.
-;; - If the game didn't end, start another iteration for the board and the :wait
-;;   action, but
-;; - if it did, stop looping.
-;; Wait for a move event means:
-;; - wait for a key event,
-;; - if the move was valid, loop again with the new board and the :render
-;;   action, but
-;; - if it wasn't valid, keep waiting for a valid move event with the current
-;;   board.
-;; The loop is started with a random initial board and the :render action. Even
-;; though there's nothing to show in the first translation phase, it happens so
-;; dast that it doesn't matters.
+;; ## The game loop
+
+;; Finally we arrived to the part where we put everything together. We'll start
+;; a loop that renders the board or waits for a event to make a move. The loop's
+;; bindings will serve us to keep the state we need to perform either of the
+;; previous actions on each iteration. The loop begins with a random initial
+;; board and the :render action.
+
+;; ### Rendering the board
+
+;; When the value of the action binding is :render:
+
+;; - we render the board in the translation phase,
+;; - and wait a bit while the translation animation finishes.
+;; - Then, we render the board again but in the reveal phase,
+;; - and wait while the appearence animation finishes.
+;; - Now, if the game ended we exit the loop, but, if it didn't, we start
+;;   another iteration for the current board and the :wait action.
+
+;; Even though there's nothing to show in the first translation phase, it
+;; happens so fast that it doesn't really matters.
+
+;; ### Waiting for a move event
+
+;; When the value of the action binding is :wait:
+
+;; - we wait for a key event, and try to perform a move in it's direction.
+;; - If the move was valid, that is something changed, we loop again with the
+;;   new board that results from the move and the :render action.
+;; - But, if it wasn't valid, we'll keep waiting for a valid move. We iterate
+;;   with the current board and the :wait action.
 
 (let [keys (keys-chan)]
   (go-loop [board (initial-board build-tile)

;; An empty square is represented by nil.

(def empty-board
  "A vector of board-order^2 nils."
  (vec (repeat (* board-order board-order) nil)))

;; Every time a tile is added to the board, it randomly appears in a empty
;; square. It's easy to choose what that square would be by getting the indexes
;; of the nil elements of the board representation, shuffling them and taking
;; the first.

(defn nil-indexes
  "Returns a set with the indexes of the nil elements of v."

  (-synth? [this]
    "Returns true if the tile can participate in a synthesis.")
  (-synth [this other]
    "Returns the result of the synthesis of the tile with other, which is
     another ITile when they can be synthesized or nil when they can't. No tile
     can be synthesized with nil."))

;; While two tiles might be able to participate in a synthesis they might not be
;; able to be synthesized together.

;; To synthesize a sequence of tiles, take the first two and:
;; - If they can be synthesized, accumulate the result of their synthesis and
;;   repeat the process for the rest of the tiles (a tile can't be synthesized
;;   more than once in one process).
;; - If they can't be synthesized, accumulate the first tile and repeat the
;;   process for all the tiles except that first one.
;; - If there's only one tile, accumulate it. (This can be reduced to the
;;   previous directive if we try to synthesize the tile with nil.)
;; - When there are no more tiles the process is done, and the accumulation is
;;   its result.

(defn synth-adjacent
  "Returns a sequence of the elements of tiles, replacing adjacent elements with
   the result of applying -synth to them when is not logically false."
