/**
   * Respond to when user pressed on the PlayButton.
   *
   * @param e the Event that initiates the play of a game.
   */
  public void actionPerformed(ActionEvent e) {
    setup();

    // now that players are set up, we need to have the XPlayer be the current Player
    controller.reset();

    // if xType is computer, have him go first now
    if (computerGoesFirst) {
      controller.playTurn();
    }

    if (computerPlaysSelf) {
      int i = 0;
      while (controller.playTurn() == GameController.IN_PROGRESS) {
        // prevent infinite loop by arbitrarily halting after
        // 100 turns. Note the use of PRE-increment within if
        if (++i > 100) {
          break;
        }
      }

      int state = controller.getCurrentState();
      switch (state) {
        case GameController.DRAW:
          applet.output("Game is drawn");
          break;

        case GameController.X_WINS:
          applet.output("X Wins!");
          break;

        case GameController.O_WINS:
          applet.output("O Wins!");
          break;
      }
    }

    // refresh view
    applet.repaint();
  }
  protected void setup() {
    String gameType = applet.getSelectedGameType();
    Logic logic = applet.getGameLogic(gameType);
    if (logic == null) {
      applet.output("You must select a game type.");
      return;
    }

    controller = new GameController(logic);

    // Find out the X Player
    String xType = applet.getXPlayChoice();

    // Find out the O Player
    String oType = applet.getOPlayChoice();

    computerGoesFirst = false;
    computerPlaysSelf = true;

    boolean setOpponentO = false;
    boolean setOpponentX = false;

    Player p;
    if (oType.equals(TicTacToeApplet.Human)) {
      // Even though this is a human player, it will be involved in
      //
      p = new MousePlayer(Player.OMARK);
      p.score(new BoardEvaluation());

      computerPlaysSelf = false;
      humanPlayer = (MousePlayer) p;
    } else {
      p = PlayerFactory.createPlayer(oType, Player.OMARK);
      if (p == null) {
        int ply = 5; // default
        try {
          ply = Integer.valueOf(applet.getOPly().getText());
        } catch (Exception _e) {

        }
        p = PlayerFactory.createPlayerWithPly(oType, Player.OMARK, ply);
        setOpponentO = true;
      }
    }
    controller.setOPlayer(p);

    if (xType.equals(TicTacToeApplet.Human)) {
      p = new MousePlayer(Player.XMARK);
      p.score(new BoardEvaluation());

      computerPlaysSelf = false;
      humanPlayer = (MousePlayer) p;
    } else {
      computerGoesFirst = true;
      p = PlayerFactory.createPlayer(xType, Player.XMARK);
      if (p == null) {
        int ply = 5; // default
        try {
          ply = Integer.valueOf(applet.getXPly().getText());
        } catch (Exception _e) {

        }
        p = PlayerFactory.createPlayerWithPly(xType, Player.XMARK, ply);
        setOpponentX = true;
      }
    }
    controller.setXPlayer(p);

    // set logic.
    ((Player) controller.getXPlayer()).logic(logic);
    ((Player) controller.getOPlayer()).logic(logic);

    // set opponents.
    if (setOpponentX) {
      ((IntelligentAgent) controller.getXPlayer()).opponent(controller.getOPlayer());
    }
    if (setOpponentO) {
      ((IntelligentAgent) controller.getOPlayer()).opponent(controller.getXPlayer());
    }
  }
  /**
   * React only to MouseClicked Events (where user presses and releases).
   *
   * <p>Can't be called until after the mousePlayer has been properly initialized.
   *
   * @param e the MouseEvent created by user.
   */
  public void mouseClicked(MouseEvent e) {
    // no game set up yet.
    if (controller == null) {
      return;
    }

    // prevent any action for a game that isn't in progress.
    if (controller.getCurrentState() != GameController.IN_PROGRESS) {
      return;
    }

    // If no human player (i.e., computer vs. computer) do nothing
    if (humanPlayer == null) {
      return;
    }

    // leave if it is not OUR turn.
    if ((controller.getCurrentTurn() == GameController.XTURN)
        && (humanPlayer.getMark() != Player.XMARK)) {
      return;
    }
    if ((controller.getCurrentTurn() == GameController.OTURN)
        && (humanPlayer.getMark() != Player.OMARK)) {
      return;
    }

    int x = e.getX();
    int y = e.getY();

    // invert the calculations from drawSpot()
    Cell cell = controller.interpretXY(x, y);
    Move m = controller.interpretMove(cell, humanPlayer);

    if (m == null) {
      applet.output("Invalid move. Try again");
      return;
    }

    // once we set the move for the player, it will be retrieved
    // by the controller who then asks the player for his next
    // move. Pretty tricky, huh?
    humanPlayer.setMove(m);
    int rc = controller.playTurn();

    // refresh to ensure that move is visible again.
    applet.repaint();

    if (rc != GameController.IN_PROGRESS) {
      if (rc == GameController.DRAW) {
        applet.output("Game is drawn");
      } else {
        applet.output("Game over. You Win!");
      }
    } else {
      // update humanPlayer and deal with auto-play
      Player currentPlayer;
      int turn = controller.getCurrentTurn();
      if (turn == GameController.XTURN) {
        currentPlayer = (Player) controller.getXPlayer();
      } else {
        currentPlayer = (Player) controller.getOPlayer();
      }

      if (currentPlayer instanceof MousePlayer) {
        humanPlayer = (MousePlayer) currentPlayer;
        return;
      }

      // since the current player is NOT human, we auto play.
      rc = controller.playTurn();
      if (rc != GameController.IN_PROGRESS) {
        if (rc == GameController.DRAW) {
          applet.output("Game is drawn");
        } else {
          applet.output("Game over. You Lose!!!!!");
        }
      }
    }
  }
 /**
  * Responsible for drawing the board.
  *
  * @param g
  */
 public void drawBoard(Graphics g) {
   if (controller != null) {
     controller.drawBoard(g);
   }
 }