meisterpropper
ServerGame starts a game at the server and then until end of the game repeats to get the game status and the current board from the server (Server.getBoard()), passes it to the player (Player.setBoard()) and commands the player to return a move (Player.move()) which is sent to the server again.
Board is the abstract representation of the status of a two player strategic game. Its subclasses must define all rules of the specific game (Board.getPossibleMove(), Board.isValidMove(), Board.isFinished()). Action represents a player's action which usually will contain a Move, but could be retirement or requesting a new game as well (if it is a human player).
The task of a Strategy (used by ComputerPlayer) is to calculate the "best" move on a given board. It may contain an "innerStrategy" to do parts of its work. meisterpropper for instance uses an OpeningStrategy that tries to find a move in its opening database. If it fails, it calls its inner strategy IterDepthStrategy that performs iterative deepening using aspiration window search (AspirationStrategy) with help of an alpha-beta search algorithm (NegaMaxStrategy) :-).
Last piece of the jigsaw puzzle: estimating the quality of a given board (rating).
To support multiple criterias when rating a board and different rating functions
for different game phases, the actual Rater can be composed of multiple
Raters like the LinearRater that combines several ratings into a
weighted sum. The PhasesRater contains a set of raters for the different
phases of a game.
public boolean isValidMove(int row, int col) {
int arow, acol;
byte piece;
if (board[row][col] != NONE) return false;
// look in upper direction
arow = row-1;
if (arow>0 && isEnemyPieceAt(arow, col)) {
for(;;) {
--arow;
if (arow<0 || (piece = board[arow][col]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in lower direction
arow = row+1;
if (arow<rows-1 && isEnemyPieceAt(arow, col)) {
for(;;) {
++arow;
if (arow>=rows || (piece = board[arow][col]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in left direction
acol = col-1;
if (acol>0 && isEnemyPieceAt(row, acol)) {
for(;;) {
--acol;
if (acol<0 || (piece = board[row][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in right direction
acol = col+1;
if (acol<cols-1 && isEnemyPieceAt(row, acol)) {
for(;;) {
++acol;
if (acol>=cols || (piece = board[row][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in left upper direction
arow = row-1;
acol = col-1;
if (arow>0 && acol>0 && isEnemyPieceAt(arow, acol)) {
for(;;) {
--arow;
--acol;
if (arow<0 || acol<0 || (piece = board[arow][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in right upper direction
arow = row+1;
acol = col-1;
if (arow<rows-1 && acol>0 && isEnemyPieceAt(arow, acol)) {
for(;;) {
++arow;
--acol;
if (arow>=rows || acol<0 || (piece = board[arow][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in right lower direction
arow = row+1;
acol = col+1;
if (arow<rows-1 && acol<cols-1 && isEnemyPieceAt(arow, acol)) {
for(;;) {
++arow;
++acol;
if (arow>=rows || acol>=cols || (piece = board[arow][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
// look in left lower direction
arow = row-1;
acol = col+1;
if (arow>0 && acol<cols-1 && isEnemyPieceAt(arow, acol)) {
for(;;) {
--arow;
++acol;
if (arow<0 || acol>=cols || (piece = board[arow][acol]) == NONE) break;
if (isOwnPiece(turn,piece)) return true;
}
}
return false;
}