// OthelloBoard Class.  This class handles the board state and updating the board
// when Moves take place.



import java.io.*;
import java.util.*;

public class OthelloBoard implements Cloneable
{
	static final int NOWHERE = -1;
	
	static final int BLACK = 2;
	static final int WHITE = 1;
	static final int EMPTY = 0;
	static final int OKMOVE = 3;
	
	static final int PLAYER1 = BLACK;
	static final int PLAYER2 = WHITE;
	
  	static final int CHANGED = 16;
	
	// the zero column is not used, board is 8x8


        Vector paintPieces;
    
	int board[][] = new int[9][9];


	int GameTime = 0;


	// has to be three since USER is 2, COMPUTER is 1
	int score[] = new int[3];
        

        int gameTurn;
	boolean gameIsOver;			


        //Board Statistics

        int num_white;
        int num_black;
        int num_black_edges;
        int num_black_corners;
        int num_black_near_corners;

	

	/**
	 * Set up the board, load everything in so it's speedy
	 */
	

        public OthelloBoard copy() {
	  OthelloBoard newBoard = new OthelloBoard();
	  for (int i=0; i<9; i++) {
	    for (int j=0; j<9; j++) {
	      newBoard.board[i][j]=board[i][j];
	    }
	  }
	  for (int k=0; k<3; k++)
	    newBoard.score[k]=score[k];
	  newBoard.GameTime = GameTime;
	  newBoard.gameTurn = gameTurn;
	  newBoard.gameIsOver = gameIsOver;

	  return newBoard;
	}

	OthelloBoard()
	{
		// clear the board
		for (int row = 1; row < 9; row++)
			for (int col = 1; col < 9; col++)
				board[col][row] = EMPTY;
	
		// put the first pieces on the board
		board[4][4] = BLACK; board[4][5] = WHITE;
		board[5][4] = WHITE; board[5][5] = BLACK;

		score[PLAYER1] = 2;
		score[PLAYER2] = 2;
		gameIsOver = false;


		gameTurn = BLACK;
		GameTime = 0;

		paintPieces = new Vector(10);

	}



        public boolean gameOver() {
	  return gameIsOver;
	}
  
 


  // The folowing function returns a string  containing 
  // all of the board statistics.  They are the number white,
  // the number black, the number white edges, the number black edges,
  // the number white corners and the number black corners.

        public void updateBoardStatistics() {
	  
	  num_white = 0;
	  num_black = 0;
	  num_black_edges = 0;
	  num_black_corners = 0;
	  num_black_near_corners = 0;


	  for (int row = 1; row < 9; row++) {
	    for (int col = 1; col <9; col++) {
	      if ((board[col][row] == WHITE) || (board[col][row] == WHITE + CHANGED)){
		num_white++;
	      }
	      if ((board[col][row] == BLACK) || (board[col][row] == BLACK + CHANGED)){
		num_black++;
		if ((col==1) || (col==8) || (row==1) || (row==8)) {
		  num_black_edges++;
		}
		if (((col==1) || (col==8)) && ((row==1) || (row==8))) {
		  num_black_corners++;
		}
		if (((col==1) && ((row == 2) || (row == 7))) ||
		    ((col == 2) && ((row == 1) || (row == 2) || (row == 7) || (row==8))) ||
		    ((col == 7) && ((row == 1) || (row == 2) || (row == 7) || (row ==8))) || 
		    ((col == 8) && ((row == 2) || (row == 7)))) {
		  num_black_near_corners++;
		}
	      }
	    }
	  }

	}

        public String printBoardStatistics() {
 
	  updateBoardStatistics();

	  return "" + num_white + " " + num_black + " " 
	    + num_black_edges + " " + num_black_corners + " " 
            + num_black_near_corners;
	}


        public Vector possibleMoves(int color) {
	  

	  Vector moves = new Vector(8);
	  Move tempMove;

	  for (int col=1; col < 9; col++) {
	    for (int row=1; row <9; row++) {
	      if (isLegalMove(color, col, row)) {
		
		tempMove = new Move(col,row);
		moves.addElement(tempMove);
	      }
	    }
	  }
	  return moves;
	}

       int numPossibleMoves(int color) {
         

	 Vector moves = possibleMoves(color);

	 int numMoves = moves.size();
	 return numMoves;

       }

      Move getnthMove(int nthMove, int color) {

	Vector possibleMoves = possibleMoves(color);
	Move move;
        move = (Move)possibleMoves.elementAt(nthMove);
	return move;
      }

        void PrintBoard() {

	  Vector moves;

	  if (gameTurn==BLACK) 
	    moves = possibleMoves(BLACK);
	  else
	    moves = possibleMoves(WHITE);


	  String output = "\n";
	  for (int row=1; row < 9; row++) {
	    for (int col=1; col < 9; col++) {
	      if ((board[col][row] == BLACK) || (board[col][row] == BLACK+CHANGED))
		output = output + "o";
	      else if ((board[col][row] == WHITE) || (board[col][row] == WHITE+CHANGED))
		output = output + "O";
	      else
		output = output + ".";
	    }

	    if (row == 1) { 
	      output = output + "   Moves for ";
	      if (gameTurn==BLACK) output = output + "BLACK";
	      else
		output = output + "WHITE";
	    }
	    if (row == 2) {
	      output = output + " ";
	      for (int i=0; i<numPossibleMoves(gameTurn); i++) {
		output = output + getnthMove(i,gameTurn);
	      }
	    }
	    output = output + "\n";
	  }
	  System.out.println(output);
	}

	void makeMove (int color, int col, int row)
	{
		score[color] += 1;
		board[col][row] = color;
		for (int colinc = -1; colinc < 2; colinc++) {
			for (int rowinc = -1; rowinc < 2; rowinc++) {
				flipRow(color, col, row, colinc, rowinc, true,
					true);
			}
		}
		GameTime++;
		if (color==BLACK)
		  if (numPossibleMoves(WHITE)>0) {
		    gameTurn = WHITE;
		  } else if (numPossibleMoves(BLACK)>0) {
		    gameTurn=BLACK;
		  } else {
		    gameIsOver=true;
		  }
		else
		  if (numPossibleMoves(BLACK)>0) {
		    gameTurn = BLACK;
		  } else if (numPossibleMoves(WHITE)>0) {
		    gameTurn = WHITE;
		  } else {
		    gameIsOver=true;
		  }
	}

	/**
	 * make an actual move, put the new piece on the board
	 * flip the rest of the pieces
	 */
	void FakemakeMove (int color, int col, int row)
	{
		score[color] += 1;
		board[col][row] = color;
		for (int colinc = -1; colinc < 2; colinc++) {
			for (int rowinc = -1; rowinc < 2; rowinc++) {
			    flipRow(color, col, row, colinc, rowinc, true, 
				    false);
			}
		}
	}


	/**
	 * try and flip a row in a particular direction
	 * if really_flipping, then go ahead and flip 'em
	 * return number of pieces flipped
	 */
	int flipRow (int color, int col, int row, int colinc,
				 int rowinc, boolean really_flipping,
		     boolean really_painting)
	{
		int newcol = col + colinc;
		int newrow = row + rowinc;
		int opponent = BLACK + WHITE - color;
		int count = 0;
	
		// if not incrementing (moving in a direction), then forget it
		if ((colinc == 0) && (rowinc == 0))
			return 0;
	
		if (newcol == 0 || newcol > 8 || newrow == 0 || newrow > 8)
			return 0;
			
		// if we aren't flipping an opponent, then forget it 
		// have to include the CHANGED in case the screen update
		// has not happened yet (grr.. this is annoying about java..)
		if ((board[newcol][newrow] != opponent) &&
			(board[newcol][newrow] != opponent+CHANGED))
			return 0;
	
		// try to flip as many as possible
		while ((board[newcol][newrow] == opponent) ||
			   (board[newcol][newrow] == opponent+CHANGED)) {
			newcol += colinc;
			newrow += rowinc;
			count++;
			if (newcol == 0 || newcol > 8 || newrow == 0 || newrow > 8)
				return 0;
		}
	
		// is there a matching piece on the other end?
		if ((board[newcol][newrow] != color) && (board[newcol][newrow] != color + CHANGED))
			return 0;
	
		// if we're really flipping them now, then do it..
		if (really_flipping) {
			while ((col != newcol) || (row != newrow)) 
			  {
			      if (board[col][row] != color)
				board[col][row] = color + CHANGED;
			      if (really_painting) {
				Move tempMove = new Move(col, row);
				paintPieces.addElement(tempMove);
			      }
			      col += colinc;
			      row += rowinc;
			      score[color] += 1;
			      score[opponent] -= 1;
			  }
			// ok, so we got a little over-excited
			score[color] -= 1;
			score[opponent] += 1;
		}
		return count;
	}


	// can you even move there?
	boolean isLegalMove (int color, int col, int row)
	{
		if ((board[col][row] != EMPTY) && (board[col][row] != OKMOVE)) {
			return false;
		}
		for (int colinc = -1; colinc < 2; colinc++) {
			for (int rowinc = -1; rowinc < 2; rowinc++) {
				if (flipRow(color, col, row, colinc, rowinc, 
					    false, false) > 0) {
					return true;
				}
			}
		}
		return false;
	}


	/**
	 * does this color have anywhere to go?
	 */
	boolean hasMove (int color)
	{
		for ( int col = 1; col < 9; col++ )	{
			for ( int row = 1; row < 9; row++) {
				if (numPossibleMoves(color) > 0) {
					return true;
				}
			}
		}
		return false;
	}


        //  This can get overwritten if we want to do something at the end of a game.
	void endGame ()
	{
	}
}



// This class defines a move record.
class Move {
  

  // The column and row of a move.
  private int col;
  private int row;

  // the value of a move.  ie the value of the board possition once it is done.
  // this is initially set to 0 and later change.
  private double value;
  
  Move(int col, int row) {
    this.row = row;
    this.col = col;
    value = 0;
  }
  
  public int col() {
    return col;
  }
  
  public int row() {
    return row;
  }
  

  public double value() {
    return value;
  }

  public void setValue(double val) {
    value = val;
  }

  public String toString() {
    String output = "(" + row + "," + col + ") ";
    return output;
  }

}  
  
