/*
 * Copyright (c) 1999 Software Architects, All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies.
 *
 * SOFTWARE ARCHITECTS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SOFTWARE 
 * ARCHITECTS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 
 * DERIVATIVES.
 */

//  package Java.TicTacToe.Game;
/*
 * Usage : java TicTacToe <ORBArgs>
 *	   	ORBArgs => options for initializing the Corba ORB
 *	   	   i.e. -ORBInitialPort 1050
 */

import RemoteInterface.*;

/**
  *A TicTacToe-specific class. This is the Game class for TicTacToe. 
  *
  */
class TicTacToe
    extends Game
{
    protected RemotePlayer remotePlayer0 = null;
    protected RemotePlayer remotePlayer1 = null;
    final static int gamePositions = 9;
    protected int[] gameState = new int[gamePositions];
    static boolean[] won = new boolean[1 << gamePositions];
    static final int DONE = (1 << gamePositions) - 1;
    protected int player0, player1;

	/**
  	  *class object method
	  *Calculates whether the Game has been won
 	  *@param pos The position that has just been changed
  	  */
	// PreCondition: pos >= 0 and pos <= 8
      //               
      // PostCondition: won holds indication if game is won
      //                
    public static void hasWon(int pos)
    {
	// All the different possible winning scenarios
	for(int i = 0; i < DONE; i++) {
	    if((i & pos) == pos) {
		won[i] = true;
	    }
	}
    }

	/**
	  *Calculates whether the Game has been won
 	  *@return boolean Returns true if game is tied
  	  */
	// PreCondition: none
      //               
      // PostCondition: no state change
      //                
	public boolean isTieGame(){
		if(!( (won[player0] == true) || (won[player1] == true) )  ){
			boolean flag = true;
			for(int i = 0; i<gameState.length; i++){
				if(!(gameState[i] == 1 || gameState[i] == 0)){
					flag = false;
				}
			}	
			return flag;
		}
		return false;
	}

    static {
	hasWon((1 << 0) | (1 << 1) | (1 << 2));
	hasWon((1 << 3) | (1 << 4) | (1 << 5));
	hasWon((1 << 6) | (1 << 7) | (1 << 8));
	hasWon((1 << 0) | (1 << 3) | (1 << 6));
	hasWon((1 << 1) | (1 << 4) | (1 << 7));
	hasWon((1 << 2) | (1 << 5) | (1 << 8));
	hasWon((1 << 0) | (1 << 4) | (1 << 8));
	hasWon((1 << 2) | (1 << 4) | (1 << 6));
    }

    /**
	  *Obtains references for the two players
 	  *
  	  */
    // PreCondition: Game.isConnected()
    //               
    // PostCondition: (not remotePlayer0 = null) and (not remotePlayer1 = null) 
    //                    
    public void setRemotePlayers()
    {
	
	remotePlayer0 = getRemotePlayer("Player0");
	remotePlayer1 = getRemotePlayer("Player1");
    }

    /**
	  *This initiates the play of the game
 	  *It does not return until the game is over
  	  */
    // PreCondition: not remotePlayer = null
    //               
    // PostCondition: game.isOver()
    //                    
    public void play()
    {
	try {
	    remotePlayer0.yourMove(gameState);
	}
	catch (Exception e) {
		e.printStackTrace();
	 }
    }


    
    public static void main(String args[])
    {
	try { 

	    TicTacToe game = new TicTacToe();
	    game.connect(args);
	    game.setRemotePlayers();
	    game.play();

	    // wait for invocations from clients
	    java.lang.Object sync = new java.lang.Object();
	    synchronized (sync) {
		sync.wait();
	    }

	}
	catch (Exception e) {
	    System.out.println("Error in main loop" + e);
	    System.exit(1);
	}
    }

    /**
	  *The game state is reset to the initial condition
 	  *
  	  */
    // PreCondition: not remotePlayer0 = null and not remotePlayer1 = null
    //               
    // PostCondition: isPlaying()
    //                    
    public void resetGame()
    {
	
	try {
	    // reset game and remove token from play
	    remotePlayer0.resetGame();
	    remotePlayer1.resetGame();
	}
	catch (Exception e) { }

	player1 = 0;
	player0 = 0;

	// Reset the game board
	for(int i = 0; i < gameState.length; i++)
	    gameState[i] = 2;

	play();
    }

    /**
	  *class object method - constructor
 	  *
  	  */
    // PreCondition: none 
    //               
    // PostCondition: instance object has been created
    //                    
    public TicTacToe()
    {
	player0 = 0;
	player1 = 0;

	// Reset the game board
	for(int i = 0; i < gameState.length; i++)
	    gameState[i] = 2;
    }

    /**
	  *Accessor that returns the current state of the game
 	  *@return int[] the array of integers 
  	  */
    // PreCondition: none 
    //               
    // PostCondition: no state change
    //                    
    public int[] getCurrentState()
    {
	return gameState;
    }

    /**
	  *Updates the gameState to include the newMove
 	  *@param newMove the GameBoardPosition selected by a Player
  	  */
    // PreCondition: isPlaying()
    //               
    // PostCondition: 
    //                    
    public void setMove(RemoteInterface.Move newMove) 
    {

	java.lang.Object sync = new java.lang.Object();
	
	gameState[(int)newMove.newPosition] = (int)newMove.playerId;
	try {
	    if(newMove.playerId == 1) {
		// Player with id 1 has won
		player1 |= 1 << newMove.newPosition;
		if(won[player1] == true) {
		    remotePlayer1.wonGame(gameState);
		    remotePlayer0.lostGame(gameState);
		    synchronized (sync) {sync.wait(5000);  }
		    resetGame();
		}
		else if (this.isTieGame()){
		    remotePlayer1.tieGame(gameState);
		    remotePlayer0.tieGame(gameState);	
		    synchronized (sync) {sync.wait(5000);  }
		    resetGame();
		}
		else {
		    remotePlayer0.yourMove(gameState);
		}
	    }
	    else if(newMove.playerId == 0) {
		// Player with id 0 has won
		player0 |= 1 << newMove.newPosition;
		if(won[player0] == true) {
		    remotePlayer0.wonGame(gameState);
		    remotePlayer1.lostGame(gameState);
		    synchronized (sync) {sync.wait(5000);  }
		    resetGame();
		}
		else if (this.isTieGame()){
		    remotePlayer1.tieGame(gameState);
		    remotePlayer0.tieGame(gameState);	
		    synchronized (sync) {sync.wait(5000);  }
		    resetGame();
		}
		else {
		    remotePlayer1.yourMove(gameState);

		}
	    }
	}
	catch(Exception e){
	    // interupt exception from wait
	    // or corba exception from remotePlayer
	}
    }
}








