 (defn add-san-move-sequence
   "Like add-san-move, but adds a sequence of moves rather than a single move. 
   This is faster than calling add-san-move multiple times, because we don't
-  have to unzip and zip the tree for each added move."
-  [game san-moves & {:keys [node-id]}]
+  have to unzip and zip the tree for each added move. If 
+  remove-existing-moves? is true, any previously existing moves at the point
+  of insertion are removed."
+  [game san-moves & {:keys [node-id remove-existing-moves?]}]
   (add-move-sequence game board/move-from-san san-moves
-                     (or node-id (-> game :current-node :node-id))))
+                     (or node-id (-> game :current-node :node-id))
+                     remove-existing-moves?))
 
 
 (defn add-uci-move-sequence
   "Like add-uci-move, but adds a sequence of moves rather than a single move. 
   This is faster than calling add-uci-move multiple times, because we don't
-  have to unzip and zip the tree for each added move."
-  [game uci-moves & {:keys [node-id]}]
+  have to unzip and zip the tree for each added move. If
+  remove-existing-moves? is true, any previously existing moves at the point
+  of insertion are removed."
+  [game uci-moves & {:keys [node-id remove-existing-moves?]}]
   (add-move-sequence game board/move-from-uci uci-moves
-                     (or node-id (-> game :current-node :node-id))))
+                     (or node-id (-> game :current-node :node-id))
+                     remove-existing-moves?))
 
 
 (defn add-key-value-pair

(defn add-move
  "Takes a game, a move function (a function that, given a board and
  some other value, translates that value to a chess move), a
  a value representing a move, and an optional node id as input, and
  returns an updated game where the move has been added as the last
  child at the given node. If no node id is supplied, the current node
  of the game is used."
  [game move-function move node-id]
  (let [z (-> (game-zip game node-id)
              (zip-add-move move-function move)
              zip/down
              zip/rightmost)]
    (assoc game :root-node (zip/root z)

(defn- zip-add-move
  "Takes a zipper, a move function (a function that, given a board
  and some other value, translates that value to a chess move),
  a value representing a move, and a boolean that says whether any previous
  moves at the current location should be removed, and returns a new zipper
  for a modified game tree where the move has been added at the zipper
  location."
  [zipper move-function move remove-existing-moves?]
  (let [board (-> zipper zip/node :board)]
    (zip/append-child (if remove-existing-moves?
                        (zip-remove-children zipper)
                        zipper)
                      {:board (board/do-move board
                                             (move-function board move))
                       :node-id (generate-id)})))

(def ^:private zip-add-san-move #(zip-add-move %1 board/move-from-san %2 false))
(def ^:private zip-add-uci-move #(zip-add-move %1 board/move-from-uci %2 false))
(def ^:private zip-add-plain-move #(zip-add-move %2 (fn [_ m] m) %2 false))

(defn- zip-add-move-sequence
  "Takes a zipper, a move function (a function that, given a board and some
  other value, translates that value to a chess move), a sequence of
  values representing chess moves, and a boolean that says whether any
  previous moves at the current node should be removed, and returns a new
  zipper for a modified game tree where the moves have been added at the
  zipper location."
  [zipper move-function moves remove-existing-moves?]
  (reduce (fn [z m] 
            (-> (zip-add-move z move-function m remove-existing-moves?)
                (zip/down)
                (zip/rightmost)))
          zipper
          moves))

(def ^:private zip-add-san-move-sequence 
  #(zip-add-move-sequence %1 board/move-from-san %2 false))

(def ^:private zip-add-uci-move-sequence
  #(zip-add-move-sequence %2 board/move-from-uci %2 false))

(defn- zip-add-key-value-pair
  [zipper key value]
