package TicTacToe;


/**
 * Matthew Amdur
 * MBA
 *
 * This class models the TicTacToe board. The Board is composed of 2d array.
 * The size of the array depends on how big a board you want to make, it uses
 * the value in the BoardSize interface.  When the Board is instantiated, it
 * sets all of its variables (whose turn it is, how many moves have been made,
 * and if the game is over) to the correct values. It then calls its own 
 * MakeNewBoard method. This makes a new instance of BlankPiece in each
 * index of the array. When these pieces are instantiated, they also draw
 * themselves out on the screen, so we take care of both the visual 
 * board and the data structure that holds onto the board.
 *
 * The easiest way to think of the Board is as squares. Each box of the 
 * TicTacToe board is made up of a square. All the types of Pieces are actually
 * GP Filled Rectangles, the triangles and circles are other shapes that they
 * contain. When I refer to a Piece as a square, that is its visual representation.
 *
 * Design Issue: I decided to model my Board as a 2 dimensional array.
 * Each index of the array has a reference to a piece, and it is a good
 * way to represent the board. It makes it easy to see if someone has one
 * since we just have to move through the array just like you would look at
 * a board to see if the game is over. For more details on how to check to
 * see if the game is over, skip to the WonTheGame method.
 **/

public class Board implements BoardSize {

  /**We need a two dimensional array of pieces, Piece[][]. We need a reference
    *to the container so other methods can pass the reference on when they
    *instantiate things. We also have two integers, _tie and _turn. _tie keeps
    *track of how many moves have been made, since if we have made the
    *maximum number of moves but no one has one, then the game has ended in a
    *tie. _turn takes care of whose turn it is, if turn is 1 then the next
    *piece that is made will be an )Piece, otherwise the next piece will be
    *an OPiece. I used an integer to keep track of this in case I decided to
    *extend the progam and make three types of pieces. The boolean _gameOver
    *keeps track of whether or not the game has ended. The _text variable 
    *is used to print out on the screen exactly whats going on: i.e. whose turn it
    *is, who won, or if its a tie. **/

  private Piece[][] _board;
  private GP.Container _cont;
  private int _tie, _turn;
  private boolean _gameOver;
  private GP.Graphics.Text _text;

  /**
   * This is the constructor for the Board class. This is the code that gets
   * executed when a Board is instantiated. We set all the varbiable to their
   * starting values. We initialize our array to be a 2 dimensional array of
   * the proper size. _tie is 0, since no moves have been made yet, turn is
   * is assigned to a random number so the first move isn't always of the
   * same piece. The game is not yet over, so _gameOver is false. Then we tell
   * the Board that it needs to make a new board, so it calls the MakeNewBoard
   * method.
   */

  public Board (GP.Container cont, GP.Graphics.Text text) {
    
    /**We have to initialize our array to be the proper size. **/

    _board = new Piece[BOARD_SIZE][BOARD_SIZE];
    
    _cont = cont;
    _tie = 0;
    _turn = cs015.SP.RandomNumberFactory.RandomNumber(0,1);
    _gameOver = false;

    /**Our _text variable is set equal to the text passed into the Board. Since 
      *the board has now decided whose turn it is, we need to write out to the
      *screen whose turn it is. **/
    
    _text = text;
    if (_turn == 0)
      _text.SetString("X's turn.");
    else _text.SetString("O's turn.");
    
    /**Now we want the actual board to be made.**/
    
    this.MakeNewBoard();
  }

  /**
   * This method is used to make a new board. This takes of the board on the
   * screen that the user sees and it intializes our data representation of
   * the board: our array. It puts a new instance of BlankPiece in each
   * index of the array. When a blank piece is clicked on, it tells the
   * that it has been clicked on, and that the board should insert the
   * proper piece into the array, provided that the game is not yet over.
   */

  public void MakeNewBoard() {
    
    /**These two for loops traverse the entire two dimensional array.
      *BOARD_SIZE is the size of the board tha the player wants, they can
      *set the size by changing it in the BoardSize interface and then
      *recompliling the code.**/


    for(int x = 0; x < BOARD_SIZE; x++)
      for(int y = 0; y < BOARD_SIZE; y++) {
	_board[x][y] = new BlankPiece(_cont, this, x, y);
      } 
    }

  /**
   * This method is used to insert the new piece into the array, and once its
   * is inserted in the array the Board tells the new piece to show its shape,
   * it doesn't know what that shape is, because the XPiece and OPiece classes
   * have redefined the show shape method to show their shape.
   */

  public void InsertPiece(int xIndex, int yIndex) {
    
    /**We only want to insert the piece if the game isn't over yet. **/
    
    if (_gameOver == false) {     
       
      /** We add one to tie since another move has been made. We also hide
	* the blank piece that was at the old coordinates, so that once
	* we de-reference it it will get garbage collected. Remember that 
	* even if you don't have a reference to something on the screen,
	* GP will hold onto the reference unless you Hide whatever was on the
	* screen. **/
      
      _tie += 1;
      _board[xIndex][yIndex].Hide();
      
      /**Now we need to know whether or not its the X's turn or the O's turn.
	*As I said in my Applet and my journal, the Board keeps track of 
	*whose turn it is, using the _turn variable. If it is 1, we make an
	*OPiece, and then set turn to 0, so the next time we make a Piece
	*it will be an XPiece. **/

      
      /**So, we make the piece, and then update whose turn it is. We also need
	*to update the text on the screen to reflect whose turn it is. **/


      if (_turn == 1) {
	_board[xIndex][yIndex] = new OPiece(_cont, xIndex, yIndex);
	_turn = 0;
	_text.SetString("X's turn.");
      }
      else {
	_board[xIndex][yIndex] = new XPiece(_cont, xIndex, yIndex);
	_turn = 1;
	_text.SetString("O's turn.");
      }

      /**Once we have put the correct piece in the array, we want it to show
	*its shape, so we tell the piece at the inserted array indexes to
	*show its shape. **/

      _board[xIndex][yIndex].ShowShape();
    }
    
    /**Now that someone else has moved, we need to see if the game is over.
      *The WonTheGame() method takes care of everything that happens when
      *someone win's, loses's, or if there is a tie. If someone has won the
      *game, we don't them to be able to insert more pieces into the game, so
      *we set _gamOver to be true, so that when someone tries to insert the
      *board knows not to do it. **/

    
    /**Take a careful look at this if statement, it helps us to not perform
      *unecessary work. And if statement is evaluated left to right. The
      *&& operator means that it should only enter if both things are true, so
      *if the first condition is false it will not even check the second 
      *condition. This means that once someone has won the game and they click
      *on a blank piece, the Board will not check to see if someone has one the
      *game, since _gameOver is false it never calls this.WonTheGame(). This
      *saves us from performing pointless computations. **/

    if ( ( _gameOver == false) && (this.WonTheGame()) ) 
       _gameOver = true;
  }


  /**
   * This method is used to determine whether or not someone has won the game.
   * We only want to do all the work to test whether or not someone won if
   * we know its possible. The minimum numner of moves needed to win is just
   * 1 - twice the board size. This sounds confusing, but think about it for
   * a minute. If we have a three by three board, then the fastest win would
   * be if whoever went first got their first three pieces in a row. To win
   * you need 3 in a row, to have moved three times your opponent has to have
   * moved at least twice, so there have been 5 moves. Twice the sizeof the
   * board - 1! Still confused, try playing against yourself and see the 
   * fastest way you can win.
   */

  public boolean WonTheGame() {
    
    /**If the number of moves is greater than one less twice the size of the
      *board, then do the checking. **/

    if (_tie >= ((2*BOARD_SIZE)-1) ) {

      /**this.CheckRowColumn() checks the rows and columns to see if
	*there are the right # of the same type of pieces in a
	*row. This method will return true if there was, so it returns
	*true if someone has won the game.  We want WonTheGame to now
	*stop checking if we know someone has one, Otherwise we want
	*to check the diagnols, and then check to see if its a tie. If
	*all these are false, then we know the game is not over and we
	*return false. CheckDiagnols works the same way**/

      
      /**Test the value of CheckRowColumn(), if its true, return true, other-
	*wise keep checking. **/

      boolean bool = this.CheckRowColumn();
      if (bool)
        return true;

      /**Test the value of CheckDiagnols(), if its true, return true, other-
	*wise keep checking. **/
  
      bool = this.CheckDiagnols();
      if (bool)
	return true;

       /**If all the moves have been exhausted, yet no one has won, then we
	 *have a tie, so we want to return true since the game is over. **/

      if (_tie == ((BOARD_SIZE)*(BOARD_SIZE)) ) {
        _text.SetString("It was a tie!"); //Tell the user it was a tie
	return true;
      }

      /**We have now tested every possibility, and we know the game is not over
	*so we want to return false. **/

      return false;
    }
    
    /**This will get executed when there haven't been enough moves to win yet,
      *so we return false since they couldn't possibly have won yet. **/

    else
      return false;
  }

  /**
   * This method is used to check so see if there is a Tic-Tac-Toe in either
   * one of the rows or in one of the columns. We check both at once since
   * it is easy, we can just test _board[x][y] and _board[y][x], since this
   * gets the rows and the columns in one pass. We can find out who won
   * by adding up the rows and the columns. Adding rows and columns, what
   * are you talking about? Well, its really quite simple.*
   *
   * All the piece's must re-define the method Counter(). A blank piece 
   * redefines this method to return 0, an OPiece returns 1, and an XPiece
   * returns -1. This way we can add up the row, and if the number we get
   * is + or - the size of the board, we know someone's one. For instance,
   * if we have a three by three board, and when we add a row we get 3, then
   * we know that there are three O's in a row, and the O's have one. To see
   * more about why I did it this way, take a look at the comments in the
   * Piece class.
   */

  public boolean CheckRowColumn() {
    
    /**We need these two integers so we hvae variable to use while counting
      *each row and column. Since we are counting, we want them to be start
      *as 0.**/
    int rowCounter, columnCounter;
    rowCounter = 0;
    columnCounter = 0;

    /**We add up the rows and columns by traversing through the array. The
      *row counter adds up the rows, while the columnCounter counts up the
      *columns. For instance, if this is the board:
      x x x    the when x is 0 it test * * * then x * x then x x *
      x x x                            * x x      * * *      x x *
      x x x                            * x x      x * x      * * *
      **/
    

    for(int x = 0; x < BOARD_SIZE; x++) {
      for(int y = 0; y < BOARD_SIZE; y++) {
        
	/**If y is 0, then we are counting up a new row and a new column, so
	  *we need to reset our counters to 0, or else we will have weird
	  *results. **/

	if (y == 0) {
	  rowCounter = 0;
	  columnCounter = 0;
        }

	/**This adds the value of the current space to the counters.**/

        rowCounter += _board[x][y].Counter();
        columnCounter += _board[y][x].Counter();
      
      }

      /**At this point we have counted up a row and a column, so we want
	*to see if there was a TicTacToe in either row or column. We need
	*to split up the testing in the rows in columns, because we add
	*behaviors to the winning line of pieces. If it was in a row, we
	*know which row it was by the loop counter (x). X is the number
	*of the row or column where the winning line is.**/

      /**This tests to see if there was a TicTacToe in the rows. **/

      if ( (rowCounter == BOARD_SIZE) || (rowCounter == -BOARD_SIZE) ) {
        
	/**If there was a TicTacToe, then we know it was in row x. Since x
	  * has the value of the current row we are seaching. We want to
	  * add the ColorBehavior (which makes the piece blink) to the
	  * line of pieces that is making the TicTacToe. We know the pieces
	  * are in row x, so all the pieces in row x get the behavior added
	  * to them in this for loop. **/

        for(int i = 0; i < BOARD_SIZE; i++) {
	  /**Each piece needs a new instance of the behavior, and the behavior
	    *needs a reference to the Piece of the color that it is changing.
	    *So when we instantiate the behavior we pass it its piece. **/
	  
	  ColorBehavior behave = new ColorBehavior(_board[x][i]);
	  
	  /**No we have to add the behavior to the piece. Any GP shape
	    *knows how to add a behavior, so we just have to tell it to. **/

	  _board[x][i].AddBehavior(behave);
	  
	  /**Now that the piece has the Behavior and the Behavior has the 
	    *piece, we need to tell the Behavior to start changing the piece's
	    *color. the start method takes the time (in milliseconds) between
	    *calls to the method that will change the piece's color. Take a 
	    *look at the ColorBehavior class to learn more. **/
	  
	  behave.Start(500);

	  /**Now we know by whose turn it is who won the game. If it is X's turn,
	    *it means that O's moved last, and hence the last O piece won the game,
	    *since we just discovered the game is over. Hence, we figure out who
	    *won and update the text on the screen. **/

	  if (_turn == 0)
	    _text.SetString("O's won the game!");
	  else _text.SetString("X's won the game!");
	}

	/**Since there was a TicTacToe, we don't need to check anymore, and
	  *we can just return true. **/
	
	return true;
      }

      /**Now we have to do the samething to check to see if we had
	*a TicTacToe in on of the columns. **/

      else 
	if ( (columnCounter == BOARD_SIZE) || (columnCounter == -BOARD_SIZE) ) {
	
	/**If there was a TicTacToe, then we know it was in column x. Since x
	  * has the value of the current column we are seaching. We want to
	  * add the ColorBehavior (which makes the piece blink) to the
	  * line of pieces that is making the TicTacToe. We know the pieces
	  * are in column x, so all the pieces in col x get the behavior added
	  * to them in this for loop. **/
	  
	for(int i = 0; i < BOARD_SIZE; i++) {
	  /**Each piece needs a new instance of the behavior, and the behavior
	    *needs a reference to the Piece of the color that it is changing.
	    *So when we instantiate the behavior we pass it its piece. **/

	  ColorBehavior behave = new ColorBehavior(_board[i][x]);
	  
	  /**No we have to add the behavior to the piece. Any GP shape
	    *knows how to add a behavior, so we just have to tell it to. **/

	  _board[i][x].AddBehavior(behave);
	  
	  /**Now that the piece has the Behavior and the Behavior has the 
	    *piece, we need to tell the Behavior to start changing the piece's
	    *color. the start method takes the time (in milliseconds) between
	    *calls to the method that will change the piece's color. Take a 
	    *look at the ColorBehavior class to learn more. **/

	  behave.Start(500);

	  /**Now we know by whose turn it is who won the game. If it is X's turn,
	    *it means that O's moved last, and hence the last O piece won the game,
	    *since we just discovered the game is over. Hence, we figure out who
	    *won and update the text on the screen. **/

	  if (_turn == 0)
	    _text.SetString("O's won the game!");
	  else _text.SetString("X's won the game!");
	}
       /**Now we have to do the samething to check to see if we had
	*a TicTacToe in on of the columns. **/

	return true;
      }
    }
    /**If we have made it this far, it means that there were no TicTacToe's,
      *and that the game isn't over yet. So we need to return false. **/

    return false;
  }

  /**
   * This method is used to check to see if there was a tictactoe in either
   * of the two diagnols. It works the same way as the CheckRowColumn method,
   * but rather than cloud up a checking method with four counters, I made
   * this a sepereate check. This could all be done in one for loop, but the
   * point of this program is to explain how stuff works, and that would have
   * been way too long and messy,
   */


  public boolean CheckDiagnols() {
    
    /**Again we have two counters, row and column, that will each count
      *up one of the two diagnols. Again, they should start being 0. **/

    int rowCounter, columnCounter;
    rowCounter = 0;
    columnCounter = 0;

    /**Since there are only two diagnols, we can run through the array and then
      *check to see if someone won as opposed to having to check each row
      *and column. **/

    /**This for loop traverses the array and check each diagnol, we need
      *to look at BOARD_SIZE-x-1 since arrays start at 0 not at 1. **/

    for(int x  = 0; x < BOARD_SIZE; x++) {
      rowCounter += _board[x][x].Counter();
      columnCounter += _board[x][BOARD_SIZE-1-x].Counter();
    }

    /**If there is a TicTacToe in topleft to bottom right diagnol, then
      * we add the color changing behavior to these squares. **/
    if ( (rowCounter == BOARD_SIZE) || (rowCounter == -BOARD_SIZE) ) {
      
      /**What this for loop is doing is explained in the previous method. **/

      for(int i = 0; i < BOARD_SIZE; i++) {
	ColorBehavior behave = new ColorBehavior(_board[i][i]);
	_board[i][i].AddBehavior(behave);
	behave.Start(500);
      }

      /**Now we know by whose turn it is who won the game. If it is X's turn,
	*it means that O's moved last, and hence the last O piece won the game,
	*since we just discovered the game is over. Hence, we figure out who
	*won and update the text on the screen. **/

      if (_turn == 0)
        _text.SetString("O's won the game!");
      else _text.SetString("X's won the game!");
      return true;
    }
    
    /**If there is a TicTacToe in the bottom left to top right diagnol, then
      * we add the color changing behavior to these squares. **/

    else 
      if ( (columnCounter == BOARD_SIZE) || (columnCounter == -BOARD_SIZE) ) {
	
	/**Again, this code is explained in the method above. It could have
	  * been abstracted out into its own method, but then it would require
	  * sending x's and y's to the method so it knew which pieces it was
	  * adding behavior to, and it got very meesy. To make it easier to
	  * understand, i just cut and pasted the code. **/

	for(int i = 0; i < BOARD_SIZE; i++) {
	  ColorBehavior behave = new ColorBehavior(_board[i][BOARD_SIZE-i-1]);
	  _board[i][BOARD_SIZE-i-1].AddBehavior(behave);
	  behave.Start(500);
	}
	
	/**Now we know by whose turn it is who won the game. If it is X's turn,
	  *it means that O's moved last, and hence the last O piece won the game,
	  *since we just discovered the game is over. Hence, we figure out who
	  *won and update the text on the screen. **/
	
	if (_turn == 0)
	  _text.SetString("O's won the game!");
	else _text.SetString("X's won the game!");
	return true;
      }

    /**If we make it herem then there is no TicTacToe and we return false. **/
    return false;
  }
}
