import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;
import java.applet.*;

// *******************************************************************************
// *******************************************************************************
// 					Position class
// *******************************************************************************
// *******************************************************************************
class Position
{
	private int posX;
	private int posY;

	public static final int LIMIT = 15;

	// the linear of Positions
	public static final char HORIZONTAL = '-';
	public static final char VERTICAL = '|';
	public static final char LUDIAGONAL = '\\';
	public static final char RUDIAGONAL = '/';
	public static final char SAME = '.';
	public static final char ALLDIRECTIONS = '*';
	public static final char NOREL = '?';
	public static final char[] LINES = {HORIZONTAL, VERTICAL, LUDIAGONAL, RUDIAGONAL, SAME, ALLDIRECTIONS, NOREL};

	Position()
	{
		posX = -1;
		posY = -1;
	}

	Position(int x, int y)
	{
		posX = x;
		posY = y;
	}

	Position(Position p)
	{
		posX = p.getX();
		posY = p.getY();
	}

	// get the x and y coordinates
	public int getX()
	{
		return posX;
	}

	public int getY()
	{
		return posY;
	}

	// checks whether the Position can be used
	public boolean isUsed()
	{
		if ( (posX>=0)&&(posX=0)&&(posYp.getX() ) || ( (posX==p.getX())&&(posY>p.getY()) )  );
	}

	// prints the Position
	public void printPosition()
	{
		System.out.print("("+posX+","+posY+")");
	}

	// get the n th neighbor Positions
	public Position getNeighbor(char barline, int n)
	{
		Position p;
		switch(barline)
		{
			case HORIZONTAL:
				p = new Position(posX+n, posY);
				break;
			case VERTICAL:
				p = new Position(posX, posY+n);
				break;
			case LUDIAGONAL:
				p = new Position(posX+n, posY+n);
				break;
			case RUDIAGONAL:
				p = new Position(posX+n, posY-n);
				break;
			default:
				p = new Position(-1000, -1000);
				break;
		}		
		return p;
	}

	// returns the n positions at front
	public Position[] nFrontPos(char barline, int n)
	{
		Position[] bar = new Position[n];
		switch(barline)
		{
			case HORIZONTAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX+k, posY);
				break;
			case VERTICAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX, posY+k);
				break;
			case LUDIAGONAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX+k, posY+k);
				break;
			case RUDIAGONAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX+k, posY-k);
				break;
			default:
				bar[0] = new Position(-1000,-1000);
				break;
		}
		return bar;
	}

	// return the list of n Positions at the back
	public Position[] nBackPos(char barline, int n)
	{
		Position[] bar = new Position[n];
		switch(barline)
		{
			case HORIZONTAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX-k, posY);
				break;
			case VERTICAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX, posY-k);
				break;
			case LUDIAGONAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX-k, posY-k);
				break;
			case RUDIAGONAL:
				for (int k = 1; k <= n; k++)
					bar[k-1] = new Position(posX-k, posY+k);
				break;
			default:
				bar[0] = new Position(-1000,-1000);
				break;
		}
		return bar;
	}

	// returns the linear relation if they are both located in the same line. ('-', '|', '\', '/', '.')
	// else returns NOREL if they have no relation
	public char relation(Position p)
	{
		if (equal(p))
			return SAME;
		if (p.getY()==posY)
			return HORIZONTAL;
		if (p.getX()==posX)
			return VERTICAL;
		if ( (p.getX()-posX)==(p.getY()-posY) )
			return LUDIAGONAL;
		if ( (p.getX()-posX)==(posY-p.getY()) )
			return RUDIAGONAL;
		return NOREL;
	}

	// returns the distance between the two positions if they have relation 
	// else returns -9999
	public int distance(Position p)
	{
		char relate = relation(p);
		switch(relate)
		{
			case SAME:
				return 0;
			case HORIZONTAL:
				return p.getX()-posX;
			case VERTICAL:
				return p.getY()-posY;
			case LUDIAGONAL:
				return p.getX()-posX;
			case RUDIAGONAL:
				return p.getX()-posX;
			default:
				return -9999;
		}
	}

}
// end of Position class


// *******************************************************************************
// *******************************************************************************
// 					the GameBoard class
// *******************************************************************************
// *******************************************************************************
class GameBoard
{
	private char[][] blocks;
	private Position[] listEmptyOccupy;
	private int numEmpty;

	public static final int SIZE = Position.LIMIT;
	public static final int NUMBLOCKS = SIZE*SIZE;

	public static final char TICK = 'V';
	public static final char CROSS = 'X';
	public static final char EMPTY = 'E';
	public static final char UNUSED = 'U';

	public static final boolean BTICK = true;
	public static final boolean BCROSS = false;

	// transform from boolean to the char of the pawn
	public static final char bool2char(boolean b)
	{
		if (b)
			return TICK;
		else
			return CROSS;
	}

	// constructor
	GameBoard()
	{
		blocks = new char[SIZE][SIZE];
		listEmptyOccupy = new Position[NUMBLOCKS];
		resetAll();
	}

	// resets the gameboard
	public void resetAll()
	{
		Position p;
		numEmpty = NUMBLOCKS;
		for (int i = 0; i < SIZE; i++)
			for (int j = 0; j < SIZE; j++)
			{
				p = new Position(i,j);
				listEmptyOccupy[i*SIZE+j] = p;
				blocks[i][j] = EMPTY;
			}
	}

	// returns number of empty blocks
	public int numEmpty()
	{
		return numEmpty;
	}

	// returns number of occupy blocks
	public int numOccupy()
	{
		return NUMBLOCKS - numEmpty; 
	}

	// reverse to previous stage
	public void reverse()
	{
		if (numOccupy()!=0)
		{
			Position target = new Position(listEmptyOccupy[numEmpty]);
			blocks[target.getX()][target.getY()] = EMPTY;
			int i = numEmpty;
			if (i > 0)
			{
				while( !target.iBig(listEmptyOccupy[i-1]) )
				{
					listEmptyOccupy[i] = listEmptyOccupy[i-1];
					i--;
					if (i==0)
						break;
				}
				listEmptyOccupy[i] = target;
			}
			numEmpty++;
		}
	}

	// checks the block Condition at Position p
	public char blockCondition(Position p)
	{
		int px = p.getX();
		int py = p.getY();
		if ( (px >= 0)&&(px=0)&&(py max)
					return false;
				else
				{
					compare = new Position(listEmptyOccupy[mean]);
					if ( p.equal(compare) )
					{	
						numEmpty--;
						for (int i = mean; i < numEmpty; i++)
							listEmptyOccupy[i] = listEmptyOccupy[i+1];
						listEmptyOccupy[numEmpty] = target;
						return true;
					}
					else
					{
						if ( target.iBig(compare) )
							min = mean + 1;
						else
							max = mean - 1;
						mean = (max + min)/2;
					}
				}
			} // end of while

		}
		else
			return false;
	} 

	// the conditions of n Positions after p, line is the linear relations
	public char[] frontCondition(Position p, char line, int n)	
	{
		char[] barCond = new char[n];
		Position[] bar = p.nFrontPos(line, n);

		for (int i = 0; i < n; i++)
			barCond[i] = blockCondition(bar[i]);

		return barCond;
	}

	// the conditions of n Positions before p, line is the linear relations
	public char[] backCondition(Position p, char line, int n)	
	{
		char[] barCond = new char[n];
		Position[] bar = p.nBackPos(line, n);

		for (int i = 0; i < n; i++)
			barCond[i] = blockCondition(bar[i]);

		return barCond;
	}

	// gets the list of empty Positions
	public Position[] getEmptyList()
	{
		Position[] list = new Position[numEmpty];
		for (int i = 0; i < numEmpty; i++)
			list[i] = new Position(listEmptyOccupy[i]);
		return list;
	}

	// gets the list of occupied Positions
	public Position[] getOccupyList()
	{
		Position[] list = new Position[numOccupy()];
		for (int i = NUMBLOCKS-1; i >= numEmpty; i--)
			list[NUMBLOCKS-i-1] = new Position(listEmptyOccupy[i]);
		return list;
	}
		
	// gets the n previous block
	public Position previousBlock(int n)
	{
		if (numOccupy()-n>0)
			return listEmptyOccupy[numEmpty+n];
		else
			return new Position();
	}

	// prints the gameboard
	public void printBoard()
	{
		System.out.print(" ");
		for (int j = 0; j < SIZE; j++)
			System.out.print(j%10);
		System.out.println(" ");

		for (int i = 0; i< SIZE; i++)
		{
			System.out.print(i%10);
			for (int j = 0; j< SIZE; j++)
			{
				Position p = new Position(i,j);
				if (blockCondition(p)==GameBoard.EMPTY)
					System.out.print(" ");
				else
					System.out.print(blockCondition(p));
			}
			System.out.println(" ");
		}
	}

}
// end of GameBoard class


// *******************************************************************************
// *******************************************************************************
// 				the BoardController class
// *******************************************************************************
// *******************************************************************************
class BoardController
{
	public static final int TICKWIN = 1;
	public static final int CROSSWIN = 2;
	public static final int DRAW = 0;
	public static final int CONTINUE = -1;

	private GameBoard myboard;
	private boolean whoTurn;
	private int whoWin;
	private Position[] winPositions = new Position[5];

	// determines who play first
	private boolean whoFirst()
	{
		return ( ((int) (Math.random()*2)) == 0 );
	}

	// updates myboard
	private boolean updateBoard(Position p)
	{
		return myboard.allocate(p, whoTurn);
	}

	// updates whoTurn; return whoTurn			
	private boolean updatePlayer()
	{
		whoTurn = !whoTurn;
		return whoTurn;
	}

	// updates whoWin, winPositions; return whether there is a winner
	private boolean updateWin()
	{
		int px = previousAllocation(0).getX();
                	int py = previousAllocation(0).getY();
                	int countFront = -1;
                	int countBack = -1;
		char checkit = GameBoard.bool2char(whoTurn);
		boolean isWin = false;

		// check horizontal
		do
		{
			countBack++;
		}
		while ( myboard.blockCondition(new Position(px-1-countBack,py))==checkit );
		do
		{
			countFront++;
		}
		while ( myboard.blockCondition(new Position(px+1+countFront,py))==checkit );
		if (countBack+countFront+1>=5)
		{
			isWin = true;
			for (int i = -countBack; i < 5-countBack; i++)
				winPositions[i+countBack] = new Position(px+i, py);
		}
		else // check vertical
		{
			countFront = -1;
			countBack = -1;
			do
			{
				countBack++;
			}
			while (myboard.blockCondition( new Position(px,py-1-countBack) )==checkit);
			do
			{
				countFront++;
			}
			while (myboard.blockCondition( new Position(px,py+1+countFront) )==checkit);
			if (countBack+countFront+1>=5)
			{
				isWin = true;
				for (int i = -countBack; i < 5-countBack; i++)
					winPositions[i+countBack] = new Position(px, py+i);
			}
			else // check left up diagonal Positions
			{	
				countFront = -1;
				countBack = -1;
				do
				{
					countBack++;
				}
				while (myboard.blockCondition(new Position(px-1-countBack,py-1-countBack))==checkit);
				do
				{
					countFront++;
				}
				while (myboard.blockCondition(new Position(px+1+countFront,py+1+countFront))==checkit);
				if (countBack+countFront+1>=5)
				{
					isWin = true;
					for (int i = -countBack; i < 5-countBack; i++)
						winPositions[i+countBack] = new Position(px+i, py+i);
				}
				else // check right up diagonal
				{	
					countFront = -1;
					countBack = -1;
					do
					{
						countBack++;
					}
					while (myboard.blockCondition(new Position(px-1-countBack,py+1+countBack))==checkit);
					do
					{
						countFront++;
					}
					while (myboard.blockCondition(new Position(px+1+countFront,py-1-countFront))==checkit);
					if (countBack+countFront+1>=5)
					{
						isWin = true;
						for (int i = -countBack; i < 5-countBack; i++)
							winPositions[i+countBack] = new Position(px+i, py-i);
					}
				}
			}
		}

		if (isWin)
		{
			if (whoTurn)
				whoWin = TICKWIN;
			else
				whoWin = CROSSWIN;
			return true;
		}
		else if (myboard.numEmpty()==0)
		{
			whoWin = DRAW;
			return false;
		}
		else 
			return false;
	}

	// constructor
	BoardController()
	{
		myboard = new GameBoard();
		whoTurn = whoFirst();
		whoWin = CONTINUE;
	}

	// constructor
	BoardController(boolean first)
	{
		myboard = new GameBoard();
		whoTurn = first;
		whoWin = CONTINUE;
	}

	// gets the size of the gameboard	
	public static int getSize()
	{
		return GameBoard.SIZE;
	}

	// gets the total number of the blocks
	public static int numBlocks()
	{
		return GameBoard.NUMBLOCKS;
	}

	public void reset()
	{
		myboard.resetAll();
		whoTurn = whoFirst();
		whoWin = CONTINUE;
	}

	// returns number of empty blocks
	public int numEmpty()
	{
		return myboard.numEmpty();
	}

	// returns number of occupy blocks
	public int numOccupy()
	{
		return myboard.numOccupy();
	}

	// returns n previous allocated block
	public Position previousAllocation(int n)
	{
		return myboard.previousBlock(n);
	}

	// returns the block conditions at Position p
	public char blockCondition(Position p)
	{
		return myboard.blockCondition(p);
	}

	// checks whether the block at Position p is empty
	public boolean isEmpty(Position p)
	{
		return myboard.isEmpty(p);
	}

	// returns the list of blocks which are availiable to allocated
	public Position[] availiableList()
	{
		return myboard.getEmptyList();
	}

	// returns who play next
	public boolean whoTurn()
	{
		return whoTurn;
	}

	// returns whether the Positions is availiable by who to allocated
	public boolean isAvailable(Position p, boolean who)
	{
		return ( isEmpty(p)&&(whoTurn==who)&&(!isEnd()) );
	}

	// allocates the pawn by who
	public boolean allocate(Position p, boolean who)
	{
		if (!(isAvailable(p, who)))
			return false;
		else
		{
			updateBoard(p);
			updateWin();
			if (whoWin==CONTINUE)
				updatePlayer();
			return true;
		}
	}

	// returns whether a player has won the game
	public int whoWin()
	{
		return whoWin;
	}

	// returns the win Positions
	public Position[] winPositions()
	{
		Position[] list = new Position[5];

		if ( (whoWin!=DRAW)&&(whoWin!=CONTINUE) )
		{
			for (int i = 0; i < 5; i++)
				list[i] = new Position(winPositions[i]);
		}
		else
		{
			for (int i = 0; i < 5; i++)
				list[i] = new Position();
		}
		
		return list;
	}

	// returns whether the game has ended
	public boolean isEnd()
	{
		return (whoWin>=0);
	}

	// print the board
	public void printBoard()
	{
		myboard.printBoard();
	}

}
// end of BoardController class


// *******************************************************************************
// *******************************************************************************
// 				the class ComputerAI
// *******************************************************************************
// *******************************************************************************
class ComputerAI
{
	public static final boolean mySide = true;
	public static final boolean enemySide = false;
	public static final char mySign = GameBoard.bool2char(mySide);
	public static final char enemySign = GameBoard.bool2char(enemySide);

	// random allocate an empty position
	protected Position myBestChoice(BoardController judge)
	{
		Position list[] = judge.availiableList();
		int index = (int) ( Math.random()*judge.numEmpty() );

		Position choice = list[index];
		return choice;
	}

	public Position myFinalChoice(BoardController judge)
	{
		Position myChoice = myBestChoice(judge);
		return myChoice;
	}


}
// end of ComputerAI class


// *******************************************************************************
// *******************************************************************************
// 					the class FirstAI
// *******************************************************************************
// *******************************************************************************
class FirstAI extends ComputerAI
{
	protected GameBoard myboard;
	protected Position myPreviousAllocation;
	protected Position enemyPreviousAllocation;

	// return it if who has a winning Position
	protected Position willWinPosition(boolean who)
	{
		Position myChoice = new Position();

		Position centerPosition;
		char bridge;
		char obstruct;
		if (who)
		{
			centerPosition = myPreviousAllocation;
			bridge = mySign;
			obstruct = enemySign;
		}
		else
		{
			centerPosition = enemyPreviousAllocation;
			bridge = enemySign;
			obstruct = mySign;
		}

		if (!centerPosition.isUsed())
			return new Position();

		boolean found = false;
		for (int k = 0; k < 4; k++)
		{
			int counter1 = 0;
			int counter2 = 0;
			Position temp1 = new Position();
			Position temp2 = new Position();
			boolean oddGap = false;

			for (int i = -4; i <= 4; i++)
			{
				Position checkPosition = centerPosition.getNeighbor(Position.LINES[k], i);
				char checkCond = myboard.blockCondition(checkPosition);
				
				if (checkCond==GameBoard.EMPTY)
				{
					oddGap = !oddGap;

					if (oddGap)
					{
						counter1 = 0;
						counter2++;
						if (counter2==5)
						{
							myChoice = checkPosition;
							found = true;
							break;
						}
						else
							temp2 = checkPosition;
					}
					else
					{
						counter2 = 0;
						counter1++;
						if (counter1==5)
						{
							myChoice = checkPosition;
							found = true;
							break;
						}
						else
							temp1 = checkPosition;
					}
				}
				else if ( (checkCond==GameBoard.UNUSED)||(checkCond==obstruct) )
				{
					if (i > 1)
						break;

					counter1 = 0;
					counter2 = 0;
				}
				else if (checkCond==bridge)
				{
					counter1++;
					counter2++;
					if (counter1 >= 5)
					{
						myChoice = temp1;
						found = true;
						break;
					}
					if (counter2 >= 5)
					{
						myChoice = temp2;
						found = true;
						break;
					}
				}
			} // end of inner for loop
			
			if (found)
				return myChoice;
		}// end of outer for loop

		return new Position();
	}// end of willWinPosition method

	// update myboard
	protected void updateBefore(BoardController judge)
	{
		myPreviousAllocation = judge.previousAllocation(1);
		enemyPreviousAllocation =  judge.previousAllocation(0);
		myboard.allocate(myPreviousAllocation, mySide);
		myboard.allocate(enemyPreviousAllocation, enemySide);
	}

	// return it if I have a winning Position, else return an unused Position
	protected Position attackPosition()
	{
		return willWinPosition(mySide);
	}

	// return it if enemy has a winning Position, else return an unused Position
	protected Position defendPosition()
	{
		return willWinPosition(enemySide);
	}

	// to win if there is a chance to win;
	// prevent lose if my enemy has a chance to win.
	protected Position myBestChoice(BoardController judge)
	{
		Position myChoice;
		myChoice = attackPosition();
		if (myChoice.isUsed())
			return myChoice;
		else
		{
			myChoice = defendPosition();
			return myChoice;
		}
	}

	// return a random Empty Position
	protected Position mySecondChoice(BoardController judge)
	{
		return super.myBestChoice(judge);
	}

	// constructor
	FirstAI()
	{
		myboard = new GameBoard();
		myPreviousAllocation = new Position();
		enemyPreviousAllocation = new Position();
	}

	// if myBestChoice returns a valid Position, returns it
	// else return mySecondChoice
	public Position myFinalChoice(BoardController judge)
	{
		updateBefore(judge);

		Position myChoice = myBestChoice(judge);
		if (myChoice.isUsed())
			return myChoice;
		else
			return mySecondChoice(judge);
	}

}
// end of FirstAI


// *******************************************************************************
// *******************************************************************************
// 					the class SecondAI
// *******************************************************************************
// *******************************************************************************
class SecondAI extends FirstAI
{
	protected Position[] attackPositions = new Position[25];
	protected Position[] defendPositions = new Position[25];
	protected int numAttackPositions = 0;
	protected int numDefendPositions = 0;

	// to update all the data members in SecondAI
	private void updatePositions()
	{
		numAttackPositions = 0;
		numDefendPositions = 0;

		Position[] list = myboard.getEmptyList();
		for (int i = 0; i < myboard.numEmpty(); i++)
		{
			if (twoHeadsSnake(mySide, list[i]))
			{
				attackPositions[numAttackPositions] = list[i];
				numAttackPositions++;
			}
			if (twoHeadsSnake(enemySide, list[i]))
			{
				defendPositions[numDefendPositions] = list[i];
				numDefendPositions++;
			}
		}
	}

	// used in mySecondChoice
	// returns whether it is a two head snake position allocated by who
	private boolean twoHeadsSnake(boolean who, Position p)
	{
		Position saveMyPrev = myPreviousAllocation;
		Position saveEnemyPrev = enemyPreviousAllocation;

		Position firstAllocation, secondAllocation, thirdAllocation;
		Position[] list = myboard.getEmptyList();
		
		firstAllocation = p;
		if (who)
			myPreviousAllocation = firstAllocation;
		else
			enemyPreviousAllocation = firstAllocation;
		myboard.allocate(firstAllocation, who);
		
		secondAllocation = willWinPosition(who);
		if (secondAllocation.isUsed())
		{
			if (!who)
				myPreviousAllocation = firstAllocation;
			else
				enemyPreviousAllocation = firstAllocation;
			myboard.allocate(secondAllocation, !who);
			
			thirdAllocation = willWinPosition(who);
			if (thirdAllocation.isUsed())
			{
				myboard.reverse();
				myboard.reverse();
				myPreviousAllocation = saveMyPrev;
				enemyPreviousAllocation = saveEnemyPrev;
				return true;
			}
			else
				myboard.reverse();
		}
			
		myboard.reverse();
		myPreviousAllocation = saveMyPrev;
		enemyPreviousAllocation = saveEnemyPrev;

		return false;
	}

	protected void updateBefore(BoardController judge)
	{
		super.updateBefore(judge);
		updatePositions();
	}

	// find two heads Snake
	protected Position mySecondChoice(BoardController judge)
	{
		if (numAttackPositions>0)
			return attackPositions[0];
		else if (numDefendPositions>0)
			return defendPositions[0];
		else
			return new Position();
	}

	// random allocation
	protected Position myThirdChoice(BoardController judge)
	{
		return super.mySecondChoice(judge);
	}

	// final choice
	public Position myFinalChoice(BoardController judge)
	{
		updateBefore(judge);

		Position myChoice = myBestChoice(judge);
		if (myChoice.isUsed() )
			return myChoice;

		myChoice = mySecondChoice(judge);
		if ( myChoice.isUsed() )
			return myChoice;

		myChoice = myThirdChoice(judge);
			return myChoice;
	}

}
// end of SecondAI


// *******************************************************************************
// *******************************************************************************
// 					the class ThirdAI
// *******************************************************************************
// *******************************************************************************
class ThirdAI extends SecondAI
{
	public static final int[] series = {1, 2, 3, 5, 8, 13, 21};

	protected final int attackFactor;
	protected final int defendFactor;

	protected int attackValue[][][];
	protected int defendValue[][][];
	protected int largestBiasValue;
	protected Position variablePosition;

	// initialization, used in constructor
	private void initialization()
	{
		int size = Position.LIMIT;
		attackValue = new int[size][size][5];
		defendValue = new int[size][size][5];

		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				Position p = new Position(i,j);
				for (int k = 0; k < 5; k++)
				{
					attackValue[i][j][k] = 0;
					defendValue[i][j][k] = 0;
				}
				calculateValues(p, Position.ALLDIRECTIONS);
			}
		}
		findLargestValues();
	} // end of initialization

	// called by updateValues
	// return the "new" attack value
	private void calculateValues(Position p, char line)
	{
		// lineIndex = the corresponding index to the char LINES
		// oldAttackValue = the old attackValue
		// oldDefendValue = the old defendValue
		int px = p.getX();
		int py = p.getY();
		int lineIndex = 0;
		int oldAttackValue;
		int oldDefendValue;

		// check line
		if (line==Position.ALLDIRECTIONS)
		{
			for (int k = 0; k < 4; k++)
				calculateValues(p, Position.LINES[k]);
			return;
		}
		else
		{
			boolean isValid = false;
			for (int k = 0; k < 4; k++)
			{
				if (Position.LINES[k]==line)
				{
					isValid = true;
					lineIndex = k;
					break;
				}
			}
			if (!isValid)
				return;	
		}

		// check p
		if (p.isUsed())
		{
			oldAttackValue = attackValue[px][py][lineIndex];
			oldDefendValue = defendValue[px][py][lineIndex];
		}
		else
			return;

		// if p is allocated, the values are -ve
		if (!myboard.isEmpty(p))
		{
			attackValue[px][py][lineIndex] = -1;
			defendValue[px][py][lineIndex] = -1;
		}
		else
		{
			// store the conditions of p's neighbors
			char[][] cond = new char[2][5];
			cond[0] = myboard.backCondition(p, line, 5);
			cond[1] = myboard.frontCondition(p, line, 5);

			// 0 is back, 1 is front
			// numEnemy = number of Enemies is counted before a friend is found
			// numFriend = number of Friends is counted before an enemy is found
			// firstEnemy = the distance between first enemy and p
			// firstFriend = the distance between first friend and p
			// friendsPower = total Power of friends, the closer to p, the more powerful of it
			// enemiesPower = total Power of enemies, the closer to p, the more powerful of it
			// emptyBeforeFirstFriend = the block before the first friend is empty
			// emptyBeforeFirstEnemy = the block before the first enemy is empty

			int numEnemies = 0;
			int numFriends = 0; 
			int friendsPower = 0;
			int enemiesPower = 0;
			int[] firstEnemy = new int[2]; 
			int[] firstFriend = new int[2];
			boolean[] emptyBeforeFirstFriend = new boolean[2];
			boolean[] emptyBeforeFirstEnemy = new boolean[2];

			// find the values of the above 8 variables
			for (int n = 0; n < 2; n++)
			{
				firstFriend[n] = 5;	// default distance
				firstEnemy[n] = 5;	// default distance
				emptyBeforeFirstFriend[n] = true;
				emptyBeforeFirstEnemy[n] = true;

				boolean foundFriend = false;
				boolean foundEnemy = false;
				for (int i = 0; i < 5; i++)
				{
					if (cond[n][i]==mySign)
					{
						if (!foundEnemy)
						{
							numFriends++;
							friendsPower += series[5-i];
						}
						if (!foundFriend)
						{
							foundFriend = true;
							firstFriend[n] = i+1;
							if (i>0)
								if (cond[n][i-1]==enemySign)
									emptyBeforeFirstFriend[n] = false;
						}
					}
					else if (cond[n][i]==enemySign)
					{
						if (!foundFriend)
						{
							numEnemies++;
							enemiesPower += series[5-i];
						}
						if (!foundEnemy)
						{
							foundEnemy = true;
							firstEnemy[n] = i+1;
							if (i>0)
								if (cond[n][i-1]==mySign)
									emptyBeforeFirstEnemy[n] = false;
						}
					}
					else if (cond[n][i]==GameBoard.UNUSED)
					{
						foundFriend = true;
						foundEnemy = true;
						firstFriend[n] = i+1;
						firstEnemy[n] = i+1;
						break;
					}
				}
			}// end of outermost for loop n

			// distFriends = the distance betweens friends
			// distEnemies = the distance betweens enemies
			int distFriends = firstFriend[0] + firstFriend[1] - 1;
			int distEnemies = firstEnemy[0] + firstEnemy[1] - 1;
			int friendsMult = 1;
			int enemiesMult = 1;

			for (int n = 0; n < 2; n++)
			{
				if (emptyBeforeFirstEnemy[n])
					friendsMult *= 2;
			}

			for (int n = 0; n < 2; n++)
			{
				if (emptyBeforeFirstFriend[n])
					enemiesMult *= 2;
			}

			if (distFriends < 5)
				defendValue[px][py][lineIndex] = 0;
			else 
				defendValue[px][py][lineIndex] = (enemiesPower*numEnemies + distFriends) * enemiesMult;
			
			if (distEnemies < 5)
				attackValue[px][py][lineIndex] = 0;
			else
				attackValue[px][py][lineIndex] = (friendsPower*numFriends + distEnemies) * friendsMult;
		}// end of else

		attackValue[px][py][4] += attackValue[px][py][lineIndex]-oldAttackValue;
		defendValue[px][py][4] += defendValue[px][py][lineIndex]-oldDefendValue;

	} // end of calculateValue method

	// called by updateValues
	// find out the largest values	
	private void findLargestValues()
	{
		Position[] list = myboard.getEmptyList();
		largestBiasValue = -9999;
		int same = 1;

		for (int i = 0; i < myboard.numEmpty(); i++)
		{
			Position checkit = list[i];
			int myBiasValue = getBiasValue(checkit);
			if (myBiasValue>largestBiasValue)
			{
				largestBiasValue = myBiasValue;
				variablePosition = checkit;
			}
			else if (myBiasValue==largestBiasValue)
			{
				same++;
				int number = ((int) (Math.random()*same));
				if ( number==0 )
				{
					largestBiasValue = myBiasValue;
					variablePosition = checkit;
				}
			}
		}
	}

	// update all the values
	private void updateAllValues()
	{
		Position[] checkPosition = new Position[2];
		int numCheckPos = 0;
		if (myPreviousAllocation.isUsed())
		{
			checkPosition[numCheckPos] = myPreviousAllocation;
			numCheckPos++;
		}
		if (enemyPreviousAllocation.isUsed())
		{
			checkPosition[numCheckPos] = enemyPreviousAllocation;
			numCheckPos++;
		}

		for (int n = 0; n < numCheckPos; n++)
		{
			calculateValues(checkPosition[n], Position.ALLDIRECTIONS);	
			for (int k = 0; k < 4; k++)
			{
				char line = Position.LINES[k];
				for (int i = 0; i < 5; i++)
				{
					Position backPosition = checkPosition[n].getNeighbor(line, -i);
					Position frontPosition = checkPosition[n].getNeighbor(line, i);
					if (myboard.isEmpty(backPosition))
						calculateValues(backPosition, line);

					if (myboard.isEmpty(frontPosition))
						calculateValues(frontPosition, line);
				}
			}
		}		
		findLargestValues();

	} // end of updateAllValues

	protected void updateBefore(BoardController judge)
	{
		super.updateBefore(judge);
		updateAllValues();
	}

	protected Position myBestChoice(BoardController judge)
	{
		return super.myBestChoice(judge);
	}

	protected Position mySecondChoice(BoardController judge)
	{
		Position myChoice;

		if (numAttackPositions>0)
		{
			myChoice = attackPositions[0]; 
			for (int i = 1; i < numAttackPositions; i++)
			{
				if (getBiasValue(attackPositions[i])>getBiasValue(myChoice))
					myChoice = attackPositions[i];
			}
			return myChoice;
		}
		else if (numDefendPositions>0)
		{
			myChoice = defendPositions[0];
			for (int i = 0; i < numDefendPositions; i++)
			{
				if (getBiasValue(defendPositions[i])>getBiasValue(myChoice))
					myChoice = defendPositions[i];
			}
			return myChoice;
		}
		else
			return new Position();
	}

	protected Position myThirdChoice(BoardController judge)
	{
		return variablePosition;
	}

	// constructor
	ThirdAI(int aFac, int dFac)
	{
		attackFactor = aFac;
		defendFactor = dFac;
		initialization();
	}

	// returns attackValue
	public int getAttackValue(Position p)
	{
		int px = p.getX();
		int py = p.getY();

		return attackValue[px][py][4];
	}

	// returns defendValue
	public int getDefendValue(Position p)
	{
		int px = p.getX();
		int py = p.getY();

		return defendValue[px][py][4];
	}

	// returns biasValue
	public int getBiasValue(Position p)
	{
		return attackFactor * getAttackValue(p) + defendFactor * getDefendValue(p);
	}

	// returns largestBiasValue
	public int getLargestBiasValue()
	{
		return largestBiasValue;
	}

	// returns variablePosition
	public Position getVariablePosition()
	{
		return variablePosition;
	}

}
// end of ThirdAI


class FourthAI extends ThirdAI
{
	private int attackVarFactor;
	private int defendVarFactor;
	private int totalAttackValue;
	private int totalDefendValue;

	protected void updateBefore(BoardController judge)
	{
		super.updateBefore(judge);
		updateTotalValues();
	}

	protected void updateTotalValues()
	{
		totalAttackValue = 0;
		totalDefendValue = 0;
		for (int i = 0; i < Position.LIMIT; i++)
		{
			for (int j = 0; j < Position.LIMIT; j++)
			{
				Position p = new Position(i,j);
				totalAttackValue += getAttackValue(p);
				totalDefendValue += getDefendValue(p);
			}
		}
		attackVarFactor = totalAttackValue/GameBoard.NUMBLOCKS+1;
		defendVarFactor = totalDefendValue/GameBoard.NUMBLOCKS+1;
	}

	FourthAI(int a, int d)
	{
		super(a,d);
		attackVarFactor = 1;
		defendVarFactor = 1;
	}

	public int getBiasValue(Position p)
	{
		return attackFactor*attackVarFactor*getAttackValue(p) + defendFactor*defendVarFactor*getDefendValue(p);
	}

}


// *******************************************************************************
// *******************************************************************************
//	 				the class ComputerPlayer
// *******************************************************************************
// *******************************************************************************
class ComputerPlayer
{
	public static final int NUMCOMP = 7;
	public static final String[] NAME = {"Baciu", "Brain", "Chanson", "Fred", "Horner", "Muppala", "Wood", "Human Player"};
	public static final int[][] ratios = { {1,7}, {2,6}, {3,5}, {4,4}, {5,3}, {6,2}, {7,1} };

	private int myID;
	private boolean mySide;
	private ComputerAI brain;

	ComputerPlayer(int who, boolean side)
	{
		myID = who%NUMCOMP;
		mySide = side;
		brain = new FourthAI(ratios[who][0], ratios[who][1]);
	}

	public boolean mySide()
	{
		return mySide;
	}

	public boolean humanSide()
	{
		return !mySide;
	}

	public Position myAllocation(BoardController judge)
	{
		Position myChoice = brain.myFinalChoice(judge);
		judge.allocate(myChoice, mySide);
		return myChoice;
	}

}


class GameTable extends Applet implements MouseListener
{
	public static final String[] text = {"COMPUTER", "PLAYER"};
	public static final String[] logoName = {"Cross", "Not", "Add", "Each", "Tick", "Triangle"};
	public static final int NUMLOGO = 6;

	public static final int SET = 0;
	public static final int PLAY = 1;

	public static final int ONEPLAYMODE = 0;
	public static final int TWOPLAYMODE = 1;

	public static final int PLAYER1 = 0;
	public static final int PLAYER2 = 1;
	public static final boolean int2bool(int player)
	{
		return (player==PLAYER1);
	}

	public static final int BLOCKSIZE = 30;
	public static final int NUMBLOCK = Position.LIMIT;
	public static final int BOARDSIZE = BLOCKSIZE * NUMBLOCK;
	public static final int RELATIVEX = 155;
	public static final int RELATIVEY = 145;

	public static final int ONEPLAYBOX = 1;
	public static final int TWOPLAYBOX = 2;
	public static final int PLAYER1LOGOBUTTON = 3;
	public static final int PLAYER2LOGOBUTTON = 4;
	public static final int COMPCHOICE = 5;
	public static final int PLAYBUTTON = 6;
	public static final int CLEARBUTTON = 7;
	public static final int PLAYER1FIRSTBOX = 8;
	public static final int PLAYER2FIRSTBOX = 9;
	public static final int RANDOMBOX = 10;

	private int state = SET;
	private int vsMode = ONEPLAYMODE;
	private int whoFirst = (int) (Math.random() * 2);
	private int[] logoIndex = new int[2];
	private int compIndex = 0;
	private boolean isRandom = true;
		
	private BoardController judge;
	private ComputerPlayer professor;

	private Image[] logoImage = new Image[2];
	private Image[] negImage = new Image[2];
	private Image[] blackImage = new Image[2];
	private Image[] playerImage = new Image[2];
	private Label[] vsModeLabel = new Label[2];

	GameTableGUI gui = new GameTableGUI(this);

	GameTable()
	{
		logoIndex[PLAYER1] = 0;
		logoIndex[PLAYER2] = 1;
	}
	public void init()
	{
		for (int n = 0; n < 2; n++)
		{
			vsModeLabel[n] = new Label(text[1], Label.CENTER);
			vsModeLabel[n].setFont(new Font ("Times", Font.BOLD, 18) );
			logoImage[n] = getImage(getCodeBase(), "Logo/"+logoName[n]+".gif");
		}

		playerImage[PLAYER1] = getImage(getCodeBase(), "Image/Player1.gif");
		playerImage[PLAYER2] = getImage(getCodeBase(), "Image/"+ComputerPlayer.NAME[compIndex]+".gif");

		gui.init(vsModeLabel[0], vsModeLabel[1]);
		addMouseListener(this);
	}

    	public void destroy() 
	{
        		removeMouseListener(this);
    	}

    	public void mouseReleased(MouseEvent e) 
	{
		int x = e.getX()-RELATIVEX;
		int y = e.getY()-RELATIVEY;

		// Figure out the row/column
		int c = x/BLOCKSIZE;
		int r = y/BLOCKSIZE;
		Position choice = new Position(c,r);

		if (state==PLAY)
		{
			switch(vsMode)
			{
				case ONEPLAYMODE:
					if (judge.isAvailable(choice, professor.humanSide()))
					{
						judge.allocate(choice, professor.humanSide());
	    	
						switch (judge.whoWin())
						{
							case BoardController.CONTINUE:
								repaint();
								play(getCodeBase(), "Audio/place.au");

								professor.myAllocation(judge);
								if (judge.whoWin()==BoardController.CONTINUE)
								{
									repaint();
									play(getCodeBase(), "Audio/place.au");
								}
								else
								{
									repaint();
									if (judge.whoWin()==BoardController.CROSSWIN)
									{
										play(getCodeBase(), "Audio/youLose.au");
										return;
									}
									else
									{
										play(getCodeBase(), "Audio/draw.au");
										return;
									}
								}
								return;
						
							case BoardController.TICKWIN:
								repaint();
								play(getCodeBase(), "Audio/youWin.au");
								return;

							case BoardController.DRAW:
								repaint();
								play(getCodeBase(), "Audio/draw.au");
								return;
						}
					}
					else 
					{
						play(getCodeBase(), "Audio/notAvailable.au");
					}
					break;

				case TWOPLAYMODE:
					if ( judge.isAvailable(choice, judge.whoTurn()) )
					{
						judge.allocate(choice, judge.whoTurn());
	    		
						switch (judge.whoWin())
						{
	      						case BoardController.TICKWIN:
								repaint();
								play(getCodeBase(), "Audio/youWin.au");
								return;
		      					case BoardController.CROSSWIN:
								repaint();
								play(getCodeBase(), "Audio/youWin.au");
								return;
		      					case BoardController.DRAW:
								repaint();
								play(getCodeBase(), "Audio/draw.au");
								return;
			      				default:
								repaint();
								play(getCodeBase(), "Audio/place.au");
								break;
		    				}	
					}
					else 
					{
						play(getCodeBase(), "Audio/notAvailable.au");
					}
					break;
			}
		}
	}

    	public void mousePressed(MouseEvent e) 
	{
    	}

    	public void mouseClicked(MouseEvent e) 
	{
    	}

    	public void mouseEntered(MouseEvent e) 
	{
    	}

    	public void mouseExited(MouseEvent e) 
	{  
	}

	// draw the game board
	public void drawBoard(Graphics g)
	{
		int xoff = RELATIVEX;
		int yoff = RELATIVEY;

		Color saveColor = g.getColor();
		g.setColor(Color.black);
		Position[] winP = judge.winPositions();

		for (int i = 0; i <= NUMBLOCK; i++)
		{
			g.drawLine(xoff+i*BLOCKSIZE, yoff, xoff+i*BLOCKSIZE, yoff+BOARDSIZE);
			g.drawLine(xoff, yoff+i*BLOCKSIZE, xoff+BOARDSIZE, yoff+i*BLOCKSIZE);
		}

		for (int r = 0; r < NUMBLOCK; r++) 
		{
	    		for (int c = 0; c < NUMBLOCK; c++) 
			{
				if (judge.blockCondition(new Position(c,r))==GameBoard.TICK) 
		    			g.drawImage(logoImage[PLAYER1], xoff+c*BLOCKSIZE + 1, yoff+r*BLOCKSIZE + 1, this);
				else if (judge.blockCondition(new Position(c,r))==GameBoard.CROSS) 
		 	 	  	g.drawImage(logoImage[PLAYER2], xoff+c*BLOCKSIZE + 1, yoff+r*BLOCKSIZE + 1, this);
			}
		}		

		if (judge.whoWin()==BoardController.TICKWIN)
		{
			for (int i = 0; i < 5; i++)
		    		g.drawImage(negImage[PLAYER1], xoff+winP[i].getX()*BLOCKSIZE + 1, yoff+winP[i].getY()*BLOCKSIZE + 1, this);
		}
		else if (judge.whoWin()==BoardController.CROSSWIN)
		{
			for (int i = 0; i < 5; i++)
		    		g.drawImage(negImage[PLAYER2], xoff+winP[i].getX()*BLOCKSIZE + 1, yoff+winP[i].getY()*BLOCKSIZE + 1, this);
		}
		else
		{
			Position p = judge.previousAllocation(0);
			if (p.isUsed())
			{
				if (judge.blockCondition(p)==GameBoard.TICK)
		    			g.drawImage(blackImage[PLAYER1], xoff+p.getX()*BLOCKSIZE + 1, yoff+p.getY()*BLOCKSIZE + 1, this);
				else
		    			g.drawImage(blackImage[PLAYER2], xoff+p.getX()*BLOCKSIZE + 1, yoff+p.getY()*BLOCKSIZE + 1, this);
			}
		}
		
		g.setColor(saveColor);
	}

	public void paint(Graphics g)
	{
		Dimension d = getSize();

		g.drawImage(playerImage[PLAYER1], 105, 5, this);
		g.drawImage(playerImage[PLAYER2], d.width-195, 5, this);
		g.drawImage(logoImage[PLAYER1], 250, 50, this);
		g.drawImage(logoImage[PLAYER2], d.width-270, 50, this);

		if (state==PLAY)
		{
			Font useFont = new Font("Times", Font.BOLD, 16);
			g.setFont(useFont);
			g.drawString("'s Turn", d.width/2-32, 70);
			if (judge.whoTurn()==int2bool(PLAYER1))
				g.drawImage(logoImage[PLAYER1], d.width/2-15, 20, this);
			else
				g.drawImage(logoImage[PLAYER2], d.width/2-15, 20, this);
			drawBoard(g);
		}
	}

	public int setMode(int m)
	{
		vsMode = m;

		if (vsMode==ONEPLAYMODE)
			playerImage[PLAYER2] = getImage(getCodeBase(), "Image/"+ComputerPlayer.NAME[compIndex]+".gif");
		else if (vsMode==TWOPLAYMODE)
			playerImage[PLAYER2] = getImage(getCodeBase(), "Image/Player2.gif");
		repaint();

		vsModeLabel[PLAYER2].setText(text[m]);
		return vsMode;
	}

	public int setState(int s)
	{
		state = s;
		if (state==PLAY)
		{
			for (int n = 0; n < 2; n++)
			{
				negImage[n] = getImage(getCodeBase(), "Logo/Neg"+logoName[logoIndex[n]]+".gif");
				blackImage[n] = getImage(getCodeBase(), "Logo/Black"+logoName[logoIndex[n]]+".gif");
			}

			judge = new BoardController(int2bool(whoFirst));
			if (vsMode==ONEPLAYMODE)
			{
				professor = new ComputerPlayer(compIndex, int2bool(PLAYER2));
				if (whoFirst==PLAYER2)
					professor.myAllocation(judge);
			}	
		}
		else
		{
			if (isRandom)
				whoFirst = (int) (Math.random() * 2);
			judge.reset();
		}		

		repaint();

		return state;
	}

	public int setLogoIndex(int player, int index)
	{
		logoIndex[player] = index;
		logoImage[player] = getImage(getCodeBase(), "Logo/"+logoName[index]+".gif");
		repaint();
		return logoIndex[player];
	}

	public int setCompIndex(int index)
	{
		compIndex = index;
		playerImage[PLAYER2] = getImage(getCodeBase(), "Image/"+ComputerPlayer.NAME[index]+".gif");
		repaint();
		return compIndex;
	}

	public int setWhoFirst(int who)
	{
		whoFirst = who;
		return whoFirst;
	}

	public boolean setIsRandom(boolean is)
	{
		isRandom = is;
		return isRandom;
	}

	public int getMode()
	{
		return vsMode;
	}

	public int getState()
	{
		return state;
	}

	public int getLogoIndex(int player)
	{
		return logoIndex[player];
	}

	public int getCompIndex()
	{
		return compIndex;
	}

	public int getWhoFirst()
	{
		return whoFirst;
	}

	public void setEnabled(int which, boolean toggle)
	{
		gui.setEnabled(which, toggle);
	}
}
// end of GameTable class


class GameTableGUI
{
	private GameTable myApplet;

	private Panel leftPanel = new Panel();
	private Panel rightPanel = new Panel();
	private Panel upperLeftPanel = new Panel();
	private Panel lowerLeftPanel = new Panel();
	private Panel upperRightPanel = new Panel();
	private Panel lowerRightPanel = new Panel();

	private Panel modePanel = new Panel();
	private Panel buttonsPanel = new Panel();
	private Panel whoFirstPanel = new Panel();

	private CheckboxGroup vsMode;
	private Checkbox oneplay;
	private Checkbox twoplay;
	private Button logo1;
	private Button logo2;
	private Choice compChoice;
	private Button play;
	private Button clear;
	private CheckboxGroup whoFirst;
	private Checkbox player1First;
	private Checkbox player2First;
	private Checkbox random;

	private GameItemListener oneplayListener;
	private GameItemListener twoplayListener;
	private GameActionListener logo1Listener;
	private GameActionListener logo2Listener;
	private GameItemListener compChoiceListener;
	private GameActionListener playListener;
	private GameActionListener clearListener;
	private GameItemListener player1FirstListener;
	private GameItemListener player2FirstListener;
	private GameItemListener randomListener;

	public GameTableGUI(GameTable applet)
	{		
		myApplet = applet;

		oneplayListener = new GameItemListener(myApplet, GameTable.ONEPLAYBOX);
		twoplayListener = new GameItemListener(myApplet, GameTable.TWOPLAYBOX);
		logo1Listener = new GameActionListener(myApplet, GameTable.PLAYER1LOGOBUTTON);
		logo2Listener = new GameActionListener(myApplet, GameTable.PLAYER2LOGOBUTTON);
		compChoiceListener = new GameItemListener(myApplet, GameTable.COMPCHOICE);
		playListener = new GameActionListener(myApplet, GameTable.PLAYBUTTON);
		clearListener = new GameActionListener(myApplet, GameTable.CLEARBUTTON);
		player1FirstListener = new GameItemListener(myApplet, GameTable.PLAYER1FIRSTBOX);
		player2FirstListener = new GameItemListener(myApplet, GameTable.PLAYER2FIRSTBOX);
		randomListener = new GameItemListener(myApplet, GameTable.RANDOMBOX);
	}

	public void init (Label text1, Label text2)
	{
		vsMode = new CheckboxGroup();
		oneplay = new Checkbox("1 Player", vsMode, myApplet.getMode()==GameTable.ONEPLAYMODE);
		twoplay = new Checkbox("2 Players", vsMode, myApplet.getMode()==GameTable.TWOPLAYMODE);
		logo1 = new Button("Logo");
		logo2 = new Button("Logo");
		compChoice = new Choice();
		play = new Button("PLAY");
		clear = new Button("CLEAR");
		whoFirst = new CheckboxGroup();
		player1First = new Checkbox("player 1 first", whoFirst, false);
		player2First = new Checkbox("player 2 first", whoFirst, false);
		random = new Checkbox("random choose", whoFirst, true);

		GridBagLayout gridbag = new GridBagLayout();
		GridBagConstraints constraints = new GridBagConstraints();
		gridbag.setConstraints(play, constraints);
		gridbag.setConstraints(clear, constraints);
		gridbag.setConstraints(logo1, constraints);
		gridbag.setConstraints(logo2, constraints);

		// create the upper left part
		modePanel.setLayout(new GridLayout(2, 1, 20, 10));
		modePanel.add(oneplay);
		modePanel.add(twoplay);

		upperLeftPanel.setLayout(new GridLayout(3, 1, 10, 10));
		upperLeftPanel.add(modePanel);
		upperLeftPanel.add(text1);
		upperLeftPanel.add(logo1);

		// create the lower left part		
		setEnabled(GameTable.CLEARBUTTON, false);
		buttonsPanel.add(play);
		buttonsPanel.add(clear);

		lowerLeftPanel.setLayout(new GridLayout(2, 1, 10, 10));
		lowerLeftPanel.add(buttonsPanel);

		// create the left Panel
		leftPanel.setLayout(new GridLayout(2, 1, 10, 250));
		leftPanel.add(upperLeftPanel);
		leftPanel.add(lowerLeftPanel);
		
		// create the upper right Panel
		for (int i = 0; i < ComputerPlayer.NUMCOMP; i++)
			compChoice.addItem(ComputerPlayer.NAME[i]);

		upperRightPanel.setLayout(new GridLayout(3, 1, 10, 10));
		upperRightPanel.add(compChoice);
		upperRightPanel.add(text2);
		upperRightPanel.add(logo2);

		// create the lower right Panel
		lowerRightPanel.setLayout(new GridLayout(3, 1, 10, 10));
		lowerRightPanel.add(random);		
		lowerRightPanel.add(player1First);
		lowerRightPanel.add(player2First);

		// create the right Panel
		rightPanel.setLayout(new GridLayout(2, 1, 10, 250));
		rightPanel.add(upperRightPanel);
		rightPanel.add(lowerRightPanel);
		
		// create the whole Panel
		myApplet.setLayout(new GridLayout(1, 2, 560, 10));
		myApplet.add(leftPanel);
		myApplet.add(rightPanel);

		oneplay.addItemListener(oneplayListener);
		twoplay.addItemListener(twoplayListener);
		logo1.addActionListener(logo1Listener);
		logo2.addActionListener(logo2Listener);
		compChoice.addItemListener(compChoiceListener);
		play.addActionListener(playListener);
		clear.addActionListener(clearListener);
		player1First.addItemListener(player1FirstListener);
		player2First.addItemListener(player2FirstListener);
		random.addItemListener(randomListener);
	}

	public void setEnabled(int which, boolean toggle)
	{
		switch(which)
		{
			case GameTable.ONEPLAYBOX:
				oneplay.setEnabled(toggle);
				break;
			case GameTable.TWOPLAYBOX:
				twoplay.setEnabled(toggle);
				break;
			case GameTable.PLAYER1LOGOBUTTON:
				logo1.setEnabled(toggle);
				break;
			case GameTable.PLAYER2LOGOBUTTON:
				logo2.setEnabled(toggle);
				break;
			case GameTable.COMPCHOICE:
				compChoice.setEnabled(toggle);
				break;
			case GameTable.PLAYBUTTON:
				play.setEnabled(toggle);
				break;
			case GameTable.CLEARBUTTON:
				clear.setEnabled(toggle);
				break;
			case GameTable.PLAYER1FIRSTBOX:
				player1First.setEnabled(toggle);
				break;
			case GameTable.PLAYER2FIRSTBOX:
				player2First.setEnabled(toggle);
				break;
			case GameTable.RANDOMBOX:
				random.setEnabled(toggle);
				break;
		}		
	}
}
// end of GameTableGUI


// *******************************************************************************
// *******************************************************************************
// 				the class GameItemListener
// *******************************************************************************
// *******************************************************************************
class GameItemListener implements ItemListener
{
	private GameTable myApplet;
	private int command;

	GameItemListener(GameTable applet, int c)
	{
		myApplet = applet;
		command = c;
	}

	public void itemStateChanged(ItemEvent event)
	{
		switch(command)
		{
			case GameTable.ONEPLAYBOX:
				myApplet.setMode(GameTable.ONEPLAYMODE);
				myApplet.setEnabled(GameTable.COMPCHOICE, true);
				break;
			case GameTable.TWOPLAYBOX:
				myApplet.setMode(GameTable.TWOPLAYMODE);
				myApplet.setEnabled(GameTable.COMPCHOICE, false);
				break;
			case GameTable.COMPCHOICE:
				int which;
				for (which = 0; which < ComputerPlayer.NUMCOMP; which++)
				{
					if ( ComputerPlayer.NAME[which]==((String) event.getItem()) )
						break;
				}
				myApplet.setCompIndex(which);
				break;
			case GameTable.PLAYER1FIRSTBOX:
				myApplet.setIsRandom(false);
				myApplet.setWhoFirst(GameTable.PLAYER1);
				break;
			case GameTable.PLAYER2FIRSTBOX:
				myApplet.setIsRandom(false);
				myApplet.setWhoFirst(GameTable.PLAYER2);
				break;
			case GameTable.RANDOMBOX:
				myApplet.setIsRandom(true);
				int who = (int) (Math.random() * 2);
				myApplet.setWhoFirst(who);
				break;
		}	
	}
}
// end of class GameTable


// *******************************************************************************
// *******************************************************************************
// 				the class GameActionListener
// *******************************************************************************
// *******************************************************************************
class GameActionListener implements ActionListener
{
	private GameTable myApplet;
	private int command;

	GameActionListener(GameTable applet, int c)
	{
		myApplet = applet;
		command = c;
	}

	public void actionPerformed(ActionEvent event)
	{

		switch(command)
		{
			case GameTable.PLAYBUTTON:
				myApplet.setState(GameTable.PLAY);
				myApplet.setEnabled(GameTable.PLAYER1LOGOBUTTON, false);
				myApplet.setEnabled(GameTable.PLAYER2LOGOBUTTON, false);
				myApplet.setEnabled(GameTable.ONEPLAYBOX, false);
				myApplet.setEnabled(GameTable.TWOPLAYBOX, false);
				myApplet.setEnabled(GameTable.COMPCHOICE, false);
				myApplet.setEnabled(GameTable.PLAYER1FIRSTBOX, false);
				myApplet.setEnabled(GameTable.PLAYER2FIRSTBOX, false);
				myApplet.setEnabled(GameTable.RANDOMBOX, false);
				myApplet.setEnabled(GameTable.PLAYBUTTON, false);
				myApplet.setEnabled(GameTable.CLEARBUTTON, true);
				break;

			case GameTable.PLAYER1LOGOBUTTON:
				int iindex1 = myApplet.getLogoIndex(GameTable.PLAYER1);
				int iindex2 = myApplet.getLogoIndex(GameTable.PLAYER2);

				iindex1++;
				iindex1 %= GameTable.NUMLOGO;
				if (iindex1 == iindex2)
				{
					iindex1++;
					iindex1 %= GameTable.NUMLOGO;
				}

				myApplet.setLogoIndex(GameTable.PLAYER1, iindex1);
				break;

			case GameTable.PLAYER2LOGOBUTTON:
				int index1 = myApplet.getLogoIndex(GameTable.PLAYER1);
				int index2 = myApplet.getLogoIndex(GameTable.PLAYER2);

				index2++;
				index2 %= GameTable.NUMLOGO;
				if (index1 == index2)
				{
					index2++;
					index2 %= GameTable.NUMLOGO;
				}

				myApplet.setLogoIndex(GameTable.PLAYER2, index2);
				break;

			case GameTable.CLEARBUTTON:
				myApplet.setState(GameTable.SET);
				myApplet.setEnabled(GameTable.PLAYER1LOGOBUTTON, true);
				myApplet.setEnabled(GameTable.PLAYER2LOGOBUTTON, true);
				myApplet.setEnabled(GameTable.ONEPLAYBOX, true);
				myApplet.setEnabled(GameTable.TWOPLAYBOX, true);
				if (myApplet.getMode()==GameTable.ONEPLAYMODE)
					myApplet.setEnabled(GameTable.COMPCHOICE, true);
				myApplet.setEnabled(GameTable.PLAYER1FIRSTBOX, true);
				myApplet.setEnabled(GameTable.PLAYER2FIRSTBOX, true);
				myApplet.setEnabled(GameTable.RANDOMBOX, true);
				myApplet.setEnabled(GameTable.PLAYBUTTON, true);
				myApplet.setEnabled(GameTable.CLEARBUTTON, false);
				break;

			default:
				break;
		}
	}
}

    Source: geocities.com/hk/tampoki/tictactoe

               ( geocities.com/hk/tampoki)                   ( geocities.com/hk)