/*
** ComputerMove is an object that selects a move for the
** the computer based on memory. The way this works is
** by letting the computer choose the first available move
** starting from position 1 thourgh 9. As the game progesses
** the computer will be told of losses caused by the
** unintelligent choises. The game that lead to a loss is
** therefore saved in memory, and it is avoided afterwards.
**
** There is this one problem though. The computer might at
** a point run out of possible end choices that would make
** it avoid a loss. That's when it memorises earlier steps
** that make it come to a end-losing-choices. (I hope I made
** sense!)
*/
import java.lang.Math;
class ComputerMove
{
//TttString currentBoard = new TttString();
// This is the last board containing the computer's
// last move (that might lead it to a loss
TttString lastBoard = new TttString();
//GameStatus currentGame = new GameStatus();
// This is an array of all possible bad moves. I am
// sure of my calculations, but I think this is
// correct. The number of all combinations of
// X's and O's are 512. There are 2^(9-1) (256) possible
// combinations of X's, and 256 combinations of O's.
// Add them together and you would get 1024 possible
// moves. Why (9-1), because there is always aleast on X
// or O on the board. Ahh! I don't want to explain
// too much. Just think about it.
TttString badMoves[] = new TttString[512];
// Number of bad moves in memory
int nBadMoves = 0;
// The board is symetrical about the middle, and
// is the same if rotated by 90 degrees. Therefore
// I am taking into account all possible moves including
// those moves that are similar.
int similarBoards[][] = {{1, 2, 3, 4, 5, 6, 7, 8, 9},
{3, 6, 9, 2, 5, 8, 1, 4, 7},
{9, 8, 7, 6, 5, 4, 3, 2, 1},
{7, 4, 1, 8, 5, 2, 9, 6, 3},
{3, 2, 1, 6, 5, 4, 9, 8, 7},
{1, 4, 7, 2, 5, 8, 3, 6, 9},
{7, 8, 9, 4, 5, 6, 1, 2, 3},
{9, 6, 3, 8, 5, 2, 7, 4, 1}};
int nSimilarBoards = 8;
// How many moves are available on the board. These
// are the empty locations.
private int availableMoves[] = new int[9];
//===============================================================
// This is brain of the computer. The computer selects a move
// if the move didn't lead to a loss the last time it was
// played. If there were more than one choice then it selects
// any one of them.
//===============================================================
public void MakeMove(TttString board)
{
int nAvailable;
int move;
boolean moveNotMade = true;
TttString tempBoard = new TttString();
// locate all available moves (empty locations).
nAvailable = GetAvailableMoves(board);
move = 0;
while (moveNotMade)
{
tempBoard.tttString = board.tttString;
// make a move in our test board
tempBoard.SetTttString(availableMoves[move], board.O);
// check to see if it's a bad move
if (!BadMove(tempBoard))
{
// if it's not a bad move then keep it.
moveNotMade = false;
}
else
{
// advance to the next location
move++;
// if we are out of good moves then
if (nAvailable == move)
{
// consider the computer a loser,
// and make any move. The computer
// memporizes.
moveNotMade = false;
Lost();
}
}
}
// Since we made a choice move then, save the board
// for later uses.
board.tttString = tempBoard.tttString;
lastBoard.tttString = board.tttString;
}
//===============================================================
// Find all the positions that are not accupied
//===============================================================
private int GetAvailableMoves(TttString b)
{
int i;
int nAvailable = 0;
for (i = 0; i < 9; i++)
{
if (b.GetXO(i + 1) == b.EMPTY)
{
availableMoves[nAvailable++] = i + 1;
}
}
return(nAvailable);
}
//===============================================================
// The computer lost and needs to save the move that made it
// loose.
//===============================================================
public void Lost()
{
// if the move that made us loose exists in
// memory then don't save it.
if (!BadMove(lastBoard))
{
// Assign a new TttString
badMoves[nBadMoves] = new TttString();
badMoves[nBadMoves++].tttString = lastBoard.tttString;
}
}
//===============================================================
// Check to see if a move is bad or not. Compare the given
// move with those in memory, and with all similar moves.
//===============================================================
private boolean BadMove(TttString testBoard)
{
int i, j, k;
TttString equivalentBoard = new TttString();
for (k = 0; k < nBadMoves; k++)
{
// make the different combinations of boards
// that have similar apperances
for (i = 0; i < nSimilarBoards; i++)
{
equivalentBoard.ClearTttString();
for (j = 0; j < 9; j++)
{
equivalentBoard.SetTttString(similarBoards[i][j], badMoves[k].GetXO(j + 1));
}
if (testBoard.tttString == equivalentBoard.tttString)
{
return(true);
}
}
}
return(false);
}
}