home *** CD-ROM | disk | FTP | other *** search
- #include <limits.h>
-
- #include "brdsize.hpp"
- #include "chess.hpp"
- #include "cplayer.hpp"
- #include "chessui.hpp"
-
- // returns a measurement of how much of the board is "covered" by
- // the pieces of a given player. lots of extra points are given
- // for "covering" the location around the opponent's king
- LOCAL int coverage
- (
- const BOARD &board,
- PIECECOLOR color,
- POSITION whereEnemyKing
- )
- {
- unsigned char map[NUMROWS][NUMCOLS];
- // bit flags for elements of map
- const unsigned char KINGAREA = 1;
- const unsigned char COVERED = 2;
- POSITION where;
- POSITIONLIST moves;
- int m, result = 0;
-
- // initialize map
- for (where.row = 0; where.row < NUMROWS; where.row++)
- for (where.col = 0; where.col < NUMCOLS; where.col++)
- map[where.row][where.col] = 0;
-
- // set covered flag on all covered locations
- for (where.row = 0; where.row < NUMROWS; where.row++)
- for (where.col = 0; where.col < NUMCOLS; where.col++)
- {
- if (board.whatPiece(where))
- if ((board.whatPiece(where)->whatColor() == color) &&
- (board.whatPiece(where)->whatType() != TYPEPAWN))
- {
- board.whatPiece(where)->legalMoves(where, board, moves);
- for (m = 0; m < moves.nMoves; m++)
- map[moves.end[m].row][moves.end[m].col] = COVERED;
- }
- }
-
- // flag locations to which enemy king could move
- board.whatPiece(whereEnemyKing)->
- legalMoves(whereEnemyKing, board, moves);
- for (m = 0; m < moves.nMoves; m++)
- map[moves.end[m].row][moves.end[m].col] |= KINGAREA;
-
- // accumulate coverage points
- for (where.row = 0; where.row < NUMROWS; where.row++)
- for (where.col = 0; where.col < NUMCOLS; where.col++)
- {
- if (map[where.row][where.col] & COVERED)
- {
- if (map[where.row][where.col] & KINGAREA)
- result += 20;
- else
- result += 1;
- }
- }
-
- return(result);
- }
-
- LOCAL POSITION whereKing
- (
- const BOARD &board,
- PIECECOLOR color
- )
- {
- POSITION where;
-
- for (where.row = 0; ; where.row++)
- for (where.col = 0; where.col < NUMCOLS; where.col++)
- {
- if (board.whatPiece(where))
- if (board.whatPiece(where)->whatColor() == color)
- if (board.whatPiece(where)->whatType() == TYPEKING)
- return(where);
- }
- }
-
- // positive difference between two integers
- LOCAL inline int absDiff(int a, int b)
- {
- a -= b;
- return(a < 0 ? -a : a);
- }
-
- // the change in difference from a goal value between a starting
- // and an ending value
- LOCAL int oneDimHowClose(int start, int end, int goal)
- {
- int a = absDiff(start, goal);
- int diff = a - absDiff(end, goal);
-
- if ((a < 2) && (diff > 0))
- return(0);
-
- return(diff);
- }
-
- // the change in "threat" metric caused by a given piece moving from
- // a starting position to an ending position in terms of trying to
- // threaten a goal position
- LOCAL int threatChange
- (
- POSITION start,
- POSITION end,
- POSITION goal,
- PIECE *p
- )
- {
- if (p->whatType() == TYPEPAWN)
- return(absDiff(start.col, end.col) * 2);
-
- return(oneDimHowClose(start.row, end.row, goal.row) +
- oneDimHowClose(start.col, end.col, goal.col));
- }
-
- // for a given list of moves, find the one that best improves the
- // "development" of a player's pieces. development is a combination
- // of covering alot of the board, getting pieces close to the enemy's
- // king, and restricting the enemy king's movement.
- LOCAL int bestDevelopMove
- (
- BOARD &board,
- PIECECOLOR moveColor,
- BESTMOVES &bestMoves
- )
- {
- POSITION whereEnemyKing = whereKing(board, OtherColor(moveColor));
- int testMetric, bestMetric = INT_MIN;
- int bestIndex, testIndex;
- MOVEUNDODATA undoData;
-
- for (testIndex = 0; testIndex < bestMoves.nMoves; testIndex++)
- {
- // engage in castlephilia
- if (bestMoves.move[testIndex].type != NORMALMOVE)
- return(testIndex);
-
- board.doMove
- (
- bestMoves.move[testIndex].start,
- bestMoves.move[testIndex].end,
- undoData
- );
-
- if (bestMoves.move[testIndex].promoteType != TYPENOPIECE)
- board.promote(bestMoves.move[testIndex].end,
- bestMoves.move[testIndex].promoteType);
-
- testMetric = undoData.capturedPiece ?
- undoData.capturedPiece->whatValue() * 16 : 0;
- testMetric += coverage(board, moveColor, whereEnemyKing) +
- threatChange
- (
- bestMoves.move[testIndex].start,
- bestMoves.move[testIndex].end,
- whereEnemyKing,
- board.whatPiece(bestMoves.move[testIndex].end)
- ) * 4;
-
- if (testMetric > bestMetric)
- {
- bestIndex = testIndex;
- bestMetric = testMetric;
- }
-
- if (bestMoves.move[testIndex].promoteType != TYPENOPIECE)
- board.restorePawn(bestMoves.move[testIndex].end);
-
- board.undoMove
- (
- bestMoves.move[testIndex].end,
- bestMoves.move[testIndex].start,
- undoData
- );
- }
-
- return(bestIndex);
- }
-
- GAMESTATUS COMPUTERPLAYER::play(BOARD &board) const
- {
- BOARDMETRIC metric;
- BESTMOVES bestMoves;
- int best;
-
- ChessUI.thinkingMessage(whatColor());
- board.findBestMoves(lookAhead, whatColor(), metric, &bestMoves);
- if (metric.kingSituation[whatColor()] != KINGOK)
- {
- // see if checkmate/stalemate current or predicted
- if (lookAhead > 2)
- board.findBestMoves(2, whatColor(), metric, &bestMoves);
-
- if (metric.kingSituation[whatColor()] == KINGLOST)
- {
- ChessUI.clearMessage();
- ChessUI.mated(whatColor());
- return(GAMEOVER);
- }
- else if (metric.kingSituation[whatColor()] == STALEMATE)
- {
- ChessUI.clearMessage();
- ChessUI.staleMated(whatColor());
- return(GAMEOVER);
- }
- }
-
- best = bestDevelopMove(board, whatColor(), bestMoves);
-
- if (!ChessUI.computerMove(board, whatColor(),
- bestMoves.move[best]))
- return(GAMEOVER);
- return(GAMECONTINUE);
- }
-