   createPlayerO = -> computerPlayer()
 
   # player :: {
-  #   setup : (done: None -> None) -> None
-  #   play : None -> None
-  #   end? : None -> None
-  #   toString : None -> Str
+  #   setup : (done: ->) ->
+  #   teardown : ->
+  #   play : ->
+  #   toString : -> Str
   # }
 
   next = ->
+    unplayable()
+    markWins()
     player = if game.nextPlayer is X then playerX else playerO
     player.play()
 

  playerText = -> (decode game.nextPlayer).toLowerCase()

  # bus :: {
  #   open?
  #   postMessage : (message : Any) -> None
  #   onmessage
  #   close?
  #   toString
  # }
  messagingPlayer = (bus) ->
    setup: (done) ->
      bus.open?()
      bus.onmessage (e) ->
        hideSpinner()
        [i, j] = e.data.action
        $ "##{i}\\,#{j}"
          .text playerText()
          .highlight()
        game = game.play [i, j]
        next()
      done()
    play: ->
      unplayable()
      markWins()
      return if checkGameOver()
      playable()
      showSpinner()
      bus.postMessage command: 'play', args: game.state()
    end: -> bus.close?()
    toString: -> bus.toString()

  computerPlayer = (depth = 3) ->
    worker = new Worker 'scripts/minimax-worker.min.js'
    bus =
      open: -> worker.postMessage command: 'setup', args: depth
      postMessage: (m) -> worker.postMessage m
      onmessage: (f) -> worker.onmessage = f
      close: -> worker.terminate()
      toString: -> 'computer'
    messagingPlayer bus


    playerX.setup -> playerO.setup -> next()

  teardown = ->
    playerX?.teardown?()
    playerO?.teardown?()
    hideSpinner()
    $ '.tic-tac-toe'
      .removeClass 'x-won-board'
