                              :winner (inc @winner)
                              :turn 0))))]
     (go
+      ;; Start out by notifying both sides of the board state
       (doseq [ch-out ch-outs]
         (notify ch-out))
       ;; During the game
       (loop []
         (when-let [[{:keys [type move] :as msg} ch-in] (alts! ch-ins)]
-          (when msg
-            (let [actor (.indexOf ch-ins ch-in)
-                  ch-out (ch-outs actor)]
-              (cond
-                (= type "state_request")
-                (notify ch-out)
-                (and (= type "move")
-                     (= @turn actor)
-                     (process-move state winner turn move))
-                (doseq [ch-out ch-outs]
-                  (notify ch-out))
-                :else (put! ch-out {:type :ignored :msg msg})))
-            (when-not @winner
-              (recur)))))
-      ;; Cleanup
-      (doseq [{:keys [latch ch-out]} players]
-        (notify ch-out)
-        (put! ch-out {:type (if @winner "end" "disconnected")})
-        (async/close! latch)))))
+          (let [actor (.indexOf ch-ins ch-in)
+                ch-out (ch-outs actor)]
+            (if-not msg
+              ;; Cleanup
+              (doseq [{ch-out0 :ch-out :as player0} players
+                      :when (not= ch-out ch-out0)]
+                (notify ch-out0)
+                (put! ch-out0 {:type "disconnected"})
+                (initial-loop player0))
+              (do (cond
+                    (= type "state_request")
+                    (notify ch-out)
+                    (and (= type "move")
+                         (= @turn actor)
+                         (process-move state winner turn move))
+                    (doseq [ch-out ch-outs]
+                      (notify ch-out))
+                    :else (put! ch-out {:type :ignored :msg msg}))
+                  (if-not @winner
+                    (recur)
+                    ;; Cleanup
+                    (doseq [{:keys [ch-out0] :as player0} players]
+                      (notify ch-out0)
+                      (put! ch-out0 {:type "end"})
+                      (initial-loop player0)))))))))))
 
 (defn match-once [{:keys [id] :as player0}]
   (if-let [player1 (->> (vals @awaiting)

                         (fn [{other-id :id}]
                           (@match-count #{id other-id})))
                        first)]
    (do (swap! awaiting dissoc (:uid player1))
        (async/close! (:waiter player1))
        (swap! match-count update-in [#{(:id player0) (:id player1)}] (fnil inc 0))
        (game-loop [player0 player1]))
    (let [waiter (chan)]
      (go-loop []
        (alt!
          waiter :done
          (:ch-in player0)
          ([msg]
           (if-not msg
             (swap! awaiting dissoc (:uid player0))
             (do (put! (:ch-out player0)
                       {:type :ignored :msg msg :reason "waiting for match"})
                 (recur))))))
      (swap! awaiting assoc (:uid player0) (assoc player0 :waiter waiter)))))

(defn matcher-init []
  (let [ch (chan)]
    (go-loop []
      (when-let [player (<! ch)]
        (match-once player)
        (recur)))
    (when-let [prev-ch @matcher]
      (async/close! prev-ch))
    (reset! matcher ch)))

;;; Game loop
(defn game-init [s]
  (let [ch-in (chan)
        ch-out (chan)
        uid (swap! uid-counter inc)]
    ;; Incoming messages
    (st/connect (st/map #(parse-string % true) s) ch-in)
    ;; Outgoing messages
    (st/connect (st/map generate-string ch-out) s)
    ;; Event loop for the connection
    (go-loop []
      (when-let [msg (<! ch-in)]
        (let [{:keys [type id]} msg]
          (if (and (= type "start") id)
            (let [latch (chan)]
              (>! @matcher {:uid uid :id id :ch-in ch-in :ch-out ch-out :latch latch})
              ;; Waits here until game ends
              (<! latch))
            (put! ch-out {:type "ignored" :msg msg}))
          (recur))))
    (st/on-drained s (fn [] (swap! awaiting dissoc uid)))
    {:status 200 :body "success!"}))

;;; Websocket connection for the game protocol

    (reset! winner (get-winner @state i))
    true))

(declare initial-loop)
(defn game-loop [players]
  (let [ch-ins (mapv :ch-in players)
        ch-outs (mapv :ch-out players)
        state (atom (vec (repeat (* ncols nrows) 0)))
        turn (atom (rand-int 2))
        winner (atom nil)
        notify (fn [ch]
                 (put! ch (cond->
