       [(int match[1]), (int match[2])]
     setup: (done) -> done()
     play: ->
-      unplayable()
-      markWins()
       return if checkGameOver()
       playableClassName = playable()
       $ ".#{playableClassName}"

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

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

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

  # bus :: {
  #   setup : (done : ->)
  #   teardown : ->
  #   postMessage : (message : Any) ->
  #   onMessage : (callback : (m: Any) ->) ->
  #   toString : -> Str
  # }
  messagingPlayer = (bus) ->
    onAction = ([i, j]) ->
      hideSpinner()
      $ "##{i}\\,#{j}"
        .text playerText()
        .highlight()
      game = game.play [i, j]
      next()
    setup: (done) ->
      bus.setup ->
        bus.onmessage (m) -> onAction m.action
        done()
    play: ->
      return if checkGameOver()
      playable()
      showSpinner()
      bus.postMessage command: 'play', args: game.state()
    teardown: -> bus.teardown()
    toString: -> bus.toString()

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

