home *** CD-ROM | disk | FTP | other *** search
- #include "misc.hpp"
- #include "brdsize.hpp"
- #include "chess.hpp"
-
- extern void OutOfMemory(void);
-
- // piece values.
- const int VALUEKING = 0,
- VALUEPAWN = 2,
- VALUEROOK = 10,
- VALUEKNIGHT = 6,
- VALUEBISHOP = 6,
- VALUEQUEEN = 18;
-
- class PAWN : public PIECE
- {
- private:
- // pointer to piece to which pawn has been promoted. null if
- // pawn has not been promoted.
- PIECE *promotePiece;
-
- public:
- PAWN(PIECECOLOR c) : PIECE(c, TYPEPAWN, VALUEPAWN), promotePiece(0) { }
- virtual ~PAWN(void) { if (promotePiece) delete promotePiece; }
-
- void promote(PIECETYPE promoteType);
- void restoreToPawn(void);
-
- virtual PIECETYPE whatType(void) const
- {
- if (promotePiece)
- return(promotePiece->whatType());
- else
- return(PIECE::whatType());
- }
-
- virtual int whatValue(void) const
- {
- if (promotePiece)
- return(promotePiece->whatValue());
- else
- return(PIECE::whatValue());
- }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- class ROOK : public PIECE
- {
- public:
- ROOK(PIECECOLOR c) : PIECE(c, TYPEROOK, VALUEROOK) { }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- class KNIGHT : public PIECE
- {
- public:
- KNIGHT(PIECECOLOR c) : PIECE(c, TYPEKNIGHT, VALUEKNIGHT) { }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- class BISHOP : public PIECE
- {
- public:
- BISHOP(PIECECOLOR c) : PIECE(c, TYPEBISHOP, VALUEBISHOP) { }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- class QUEEN : public PIECE
- {
- public:
- QUEEN(PIECECOLOR c) : PIECE(c, TYPEQUEEN, VALUEQUEEN) { }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- class KING : public PIECE
- {
- public:
- KING(PIECECOLOR c) : PIECE(c, TYPEKING, VALUEKING) { }
-
- virtual void legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const;
-
- };
-
- // put all the pieces for one color at their starting positions on
- // the board
- LOCAL void setupPieces
- (
- PIECE *board[][NUMCOLS],
- PIECECOLOR color,
- // column in which the non-pawn pieces go
- int backCol,
- // column in which the pawns go
- int pawnCol
- )
- {
- BOOL f = TRUE;
- int row;
-
- #define NEWPIECE(P, ROWOFFSET, COLOFFSET) \
- f = f && \
- ((board[ROWOFFSET][COLOFFSET] = new P) != (PIECE *) 0);
-
- NEWPIECE(ROOK(color), 0, backCol);
- NEWPIECE(KNIGHT(color), 1, backCol);
- NEWPIECE(BISHOP(color), 2, backCol);
- NEWPIECE(QUEEN(color), 3, backCol);
- NEWPIECE(KING(color), 4, backCol);
- NEWPIECE(BISHOP(color), 5, backCol);
- NEWPIECE(KNIGHT(color), 6, backCol);
- NEWPIECE(ROOK(color), 7, backCol);
-
- for (row = 0; row < NUMROWS; row++)
- NEWPIECE(PAWN(color), row, pawnCol);
-
- if (!f)
- OutOfMemory();
-
- return;
-
- #undef NEWPIECE
- }
-
- BOARD::BOARD(void)
- {
- int row, col;
-
- for (row = 0; row < NUMROWS; row++)
- for (col = 0; col < NUMCOLS; col++)
- brd[row][col] = (PIECE *) 0;
-
- setupPieces(brd, WHITE, 0, 1);
- setupPieces(brd, BLACK, 7, 6);
-
- wasLastMoveDoublePawn = FALSE;
-
- return;
- }
-
- BOARD::~BOARD(void)
- {
- int r, c;
-
- for (r = 0; r < NUMROWS; r++)
- for (c = 0; c < NUMROWS; c++)
- {
- if (brd[r][c])
- delete brd[r][c];
- }
-
- return;
- }
-
- void BOARD::doMove
- (
- POSITION start,
- POSITION end,
- MOVEUNDODATA &undoData
- )
- {
- undoData.capturedPiece = brd[end.row][end.col];
- undoData.enPassantEffect = OTHERMOVE;
-
- brd[end.row][end.col] = brd[start.row][start.col];
-
- brd[start.row][start.col] = (PIECE *) 0;
- brd[end.row][end.col]->moveDone();
-
- if (brd[end.row][end.col]->whatType() == TYPEPAWN)
- {
- if (wasLastMoveDoublePawn)
- if ((doubleMovedPawn.row == end.row) &&
- (doubleMovedPawn.col == start.col) &&
- (start.row != end.row) &&
- !undoData.capturedPiece)
- // these last two tests are necessary to handle situations
- // where the same color is moved twice in a row when
- // looking for check in "canCastle" and looking for
- // stalemate
- {
- // en passant capture
- undoData.capturedPiece =
- brd[doubleMovedPawn.row][doubleMovedPawn.col];
- brd[doubleMovedPawn.row][doubleMovedPawn.col] =
- (PIECE *) 0;
- undoData.saveDoubleMoved = doubleMovedPawn;
- undoData.enPassantEffect = ENPASSANTCAPTURE;
- wasLastMoveDoublePawn = FALSE;
- return;
- }
- {
- int diff = start.col - end.col;
- if (diff < 0)
- diff = -diff;
- if (diff == 2)
- {
- if (wasLastMoveDoublePawn)
- {
- undoData.saveDoubleMoved = doubleMovedPawn;
- undoData.enPassantEffect = AFTERDOUBLEMOVE;
- }
- doubleMovedPawn = end;
- wasLastMoveDoublePawn = TRUE;
- return;
- }
- }
- }
-
- if (wasLastMoveDoublePawn)
- {
- undoData.saveDoubleMoved = doubleMovedPawn;
- undoData.enPassantEffect = AFTERDOUBLEMOVE;
- }
- wasLastMoveDoublePawn = FALSE;
-
- return;
- }
-
- void BOARD::undoMove
- (
- POSITION end,
- POSITION orig,
- MOVEUNDODATA undoData
- )
- {
- brd[orig.row][orig.col] = brd[end.row][end.col];
-
- brd[orig.row][orig.col]->moveUndone();
-
- if (undoData.enPassantEffect == ENPASSANTCAPTURE)
- {
- brd[end.row][orig.col] = undoData.capturedPiece;
- brd[end.row][end.col] = (PIECE *) 0;
- }
- else
- brd[end.row][end.col] = undoData.capturedPiece;
-
- if (undoData.enPassantEffect == OTHERMOVE)
- wasLastMoveDoublePawn = FALSE;
- else
- {
- wasLastMoveDoublePawn = TRUE;
- doubleMovedPawn = undoData.saveDoubleMoved;
- }
-
- return;
- }
-
- BOOL BOARD::canCastle(MOVETYPE whichCastle, PIECECOLOR color)
- {
- int col = color == WHITE ? 0 : 7;
- int row, rowStep;
- BOARDMETRIC metric;
-
- if (whichCastle == QUEENSIDECASTLE)
- {
- row = 0;
- rowStep = 1;
- }
- else
- {
- row = 7;
- rowStep = -1;
- }
-
- // make sure king & rook in initial positions and have never been
- // moved.
- if (!brd[row][col])
- return(FALSE);
- if (brd[row][col]->hasBeenMoved())
- return(FALSE);
- if (!brd[4][col])
- return(FALSE);
- if (brd[4][col]->hasBeenMoved())
- return(FALSE);
-
- // make sure no pieces in between
- for ( ; ; )
- {
- row += rowStep;
- if (row == 4)
- break;
- if (brd[row][col])
- return(FALSE);
- }
-
- // make sure king is not in check
- findBestMoves(1, OtherColor(color), metric, (BESTMOVES *) 0);
- if (metric.kingSituation[color] == KINGLOST)
- return(FALSE);
-
- // make sure king would not be in check in intermediate position
- brd[4 - rowStep][col] = brd[4][col];
- brd[4][col] = (PIECE *) 0;
- findBestMoves(1, OtherColor(color), metric, (BESTMOVES *) 0);
- brd[4][col] = brd[4 - rowStep][col];
- brd[4 - rowStep][col] = (PIECE *) 0;
-
- return(metric.kingSituation[color] == KINGOK);
- }
-
- void BOARD::castle
- (
- MOVETYPE whichCastle,
- PIECECOLOR color,
- MOVEUNDODATA &undoData
- )
- {
- int col = color == WHITE ? 0 : 7;
-
- if (whichCastle == QUEENSIDECASTLE)
- {
- brd[3][col] = brd[0][col];
- brd[2][col] = brd[4][col];
- brd[0][col] = (PIECE *) 0;
- brd[4][col] = (PIECE *) 0;
- brd[3][col]->moveDone();
- brd[2][col]->moveDone();
- }
- else
- {
- brd[5][col] = brd[7][col];
- brd[6][col] = brd[4][col];
- brd[7][col] = (PIECE *) 0;
- brd[4][col] = (PIECE *) 0;
- brd[5][col]->moveDone();
- brd[6][col]->moveDone();
- }
-
- if (wasLastMoveDoublePawn)
- {
- undoData.enPassantEffect = AFTERDOUBLEMOVE;
- undoData.saveDoubleMoved = doubleMovedPawn;
- wasLastMoveDoublePawn = FALSE;
- }
- else
- undoData.enPassantEffect = OTHERMOVE;
-
-
- return;
- }
-
- void BOARD::undoCastle
- (
- MOVETYPE whichCastle,
- PIECECOLOR color,
- MOVEUNDODATA &undoData
- )
- {
- int col = color == WHITE ? 0 : 7;
-
- if (whichCastle == QUEENSIDECASTLE)
- {
- brd[0][col] = brd[3][col];
- brd[4][col] = brd[2][col];
- brd[3][col] = (PIECE *) 0;
- brd[2][col] = (PIECE *) 0;
- brd[0][col]->moveUndone();
- brd[4][col]->moveUndone();
- }
- else
- {
- brd[7][col] = brd[5][col];
- brd[4][col] = brd[6][col];
- brd[5][col] = (PIECE *) 0;
- brd[6][col] = (PIECE *) 0;
- brd[7][col]->moveUndone();
- brd[4][col]->moveUndone();
- }
-
- if (undoData.enPassantEffect == AFTERDOUBLEMOVE)
- {
- wasLastMoveDoublePawn = TRUE;
- doubleMovedPawn = undoData.saveDoubleMoved;
- }
- else
- wasLastMoveDoublePawn = FALSE;
-
- return;
- }
-
- BOOL BOARD::canPromote(POSITION where)
- {
- PIECE *p = whatPiece(where);
-
- if (!p)
- return(FALSE);
-
- if (where.col != (p->whatColor() == WHITE ? (NUMCOLS - 1) : 0))
- return(FALSE);
-
- return(p->whatType() == TYPEPAWN);
- }
-
- void BOARD::promote(POSITION where, PIECETYPE promoteType)
- {
- ((PAWN *) whatPiece(where))->promote(promoteType);
- return;
- }
-
- void BOARD::restorePawn(POSITION where)
- {
- ((PAWN *) whatPiece(where))->restoreToPawn();
- return;
- }
-
- MOVESTATUS BOARD::doUserMove
- (
- POSITION start,
- POSITION end
- )
- {
- PIECE *p = whatPiece(start.row, start.col), *taken;
- POSITIONLIST moves;
- BOARDMETRIC metric;
- BESTMOVES bestMoves;
- MOVEUNDODATA undoData;
- int m;
-
- if (!p)
- return(MOVESTATUS(ILLEGALMOVE));
-
- p->legalMoves(start, *this, moves);
- for (m = 0; m < moves.nMoves; m++)
- {
- if ((moves.end[m].row == end.row) &&
- (moves.end[m].col == end.col))
- break;
- }
- if (m == moves.nMoves)
- return(MOVESTATUS(ILLEGALMOVE));
-
- doMove(start, end, undoData);
-
- findBestMoves(1, OtherColor(p->whatColor()), metric, &bestMoves);
-
- if (metric.kingSituation[p->whatColor()] == KINGLOST)
- {
- undoMove(end, start, undoData);
- return(MOVESTATUS(WOULDLOSEKING, bestMoves.move[0].start));
- }
-
- if (undoData.capturedPiece)
- delete undoData.capturedPiece;
- if (undoData.enPassantEffect == ENPASSANTCAPTURE)
- return(MOVESTATUS(MOVEENPASSANT));
- else
- return(MOVESTATUS(MOVEDONE));
- }
-
- BOOL BOARD::userCanCastle
- (
- MOVETYPE whichCastle,
- PIECECOLOR color
- )
- {
- BOARDMETRIC metric;
- MOVEUNDODATA undoData;
-
- if (!canCastle(whichCastle, color))
- return(FALSE);
-
- castle(whichCastle, color, undoData);
-
- // make sure king is not in check in final position
- findBestMoves(1, OtherColor(color), metric, (BESTMOVES *) 0);
-
- undoCastle(whichCastle, color, undoData);
-
- return(metric.kingSituation[color] == KINGOK);
- }
-
-
- // tables that help in comparing the kingSituation portions of two
- // board metrics
-
- class SITUATIONCOMPARETABLE
- {
- private:
- int t[3][3];
-
- public:
- int * operator [] (int i) { return(t[i]); }
- };
-
- class THISSITUATIONCOMPARETABLE : public SITUATIONCOMPARETABLE
- {
- public:
- THISSITUATIONCOMPARETABLE(void)
- {
- (*this)[KINGLOST][KINGLOST] = 0;
- (*this)[KINGLOST][STALEMATE] = -1;
- (*this)[KINGLOST][KINGOK] = -1;
- (*this)[STALEMATE][KINGLOST] = 1;
- (*this)[STALEMATE][STALEMATE] = 0;
- (*this)[STALEMATE][KINGOK] = -1;
- (*this)[KINGOK][KINGLOST] = 1;
- (*this)[KINGOK][STALEMATE] = 1;
- (*this)[KINGOK][KINGOK] = 0;
-
- return;
- }
- };
-
- LOCAL THISSITUATIONCOMPARETABLE thisSituationCompareTable;
-
- class OTHERSITUATIONCOMPARETABLE : public SITUATIONCOMPARETABLE
- {
- public:
- OTHERSITUATIONCOMPARETABLE(void)
- {
- (*this)[KINGLOST][KINGLOST] = 0;
- (*this)[KINGLOST][STALEMATE] = 1;
- (*this)[KINGLOST][KINGOK] = 1;
- (*this)[STALEMATE][KINGLOST] = -1;
- (*this)[STALEMATE][STALEMATE] = 0;
- (*this)[STALEMATE][KINGOK] = -1;
- (*this)[KINGOK][KINGLOST] = -1;
- (*this)[KINGOK][STALEMATE] = 1;
- (*this)[KINGOK][KINGOK] = 0;
-
- return;
- }
- };
-
- LOCAL OTHERSITUATIONCOMPARETABLE otherSituationCompareTable;
-
- // compare two board metrics. if the second metric is invalid,
- // the first metric is better. the color parameter gives the player
- // for whom the metric is supposed to be better.
- LOCAL int compareMetric
- (
- const BOARDMETRIC &a,
- const BOARDMETRIC &b,
- BOOL bValid,
- PIECECOLOR color
- )
- {
- PIECECOLOR otherColor = OtherColor(color);
- int compare;
-
- if (!bValid)
- return(1);
-
- compare = thisSituationCompareTable[a.kingSituation[color]]
- [b.kingSituation[color]];
- if (compare != 0)
- return(compare);
-
- compare = otherSituationCompareTable[a.kingSituation[otherColor]]
- [b.kingSituation[otherColor]];
- if (compare != 0)
- return(compare);
-
- compare = a.materialDiff - b.materialDiff;
-
- if (color == BLACK)
- compare = -compare;
-
- return(compare);
- }
-
- void BOARD::helpFindBestMoves
- (
- int lookAhead,
- PIECECOLOR moveColor,
- BOARDMETRIC &metric,
- BESTMOVES *bestMoves
- )
- {
- POSITION where;
- POSITIONLIST moves;
- BOARDMETRIC testMetric;
- BOOL metricSet = FALSE;
- MOVEUNDODATA undoData;
- int m, compareResult;
- int origMaterialDiff = metric.materialDiff;
- MOVETYPE castleType;
-
- testMetric.kingSituation[WHITE] = KINGOK;
- testMetric.kingSituation[BLACK] = KINGOK;
-
- // try all possible moves for the given color
-
- for (where.row = 0; where.row < NUMROWS; where.row++)
- for (where.col = 0; where.col < NUMCOLS; where.col++)
- {
- if (whatPiece(where))
- if (whatPiece(where)->whatColor() == moveColor)
- {
- whatPiece(where)->legalMoves(where, *this, moves);
- for (m = 0; m < moves.nMoves; m++)
- {
- testMetric.materialDiff = origMaterialDiff;
- doMove
- (
- where,
- moves.end[m],
- undoData
- );
-
- if (undoData.capturedPiece)
- {
- if (undoData.capturedPiece->whatType() == TYPEKING)
- {
- undoMove
- (
- moves.end[m],
- where,
- undoData
- );
-
- metric.kingSituation[OtherColor(moveColor)] =
- KINGLOST;
-
- if (bestMoves)
- {
- bestMoves->nMoves = 0;
- bestMoves->move[0] =
- PIECEMOVE
- (
- NORMALMOVE,
- where,
- moves.end[m]
- );
- }
-
- return;
- }
- testMetric.materialDiff -=
- undoData.capturedPiece->signedValue();
- }
-
- if (canPromote(moves.end[m]))
- {
- testMetric.materialDiff -=
- whatPiece(moves.end[m])->signedValue();
- promote(moves.end[m], TYPEQUEEN);
- testMetric.materialDiff +=
- whatPiece(moves.end[m])->signedValue();
- if (lookAhead > 1)
- helpFindBestMoves
- (
- lookAhead - 1,
- OtherColor(moveColor),
- testMetric,
- (BESTMOVES *) 0
- );
- compareResult = compareMetric
- (
- testMetric,
- metric,
- metricSet,
- moveColor
- );
- if (compareResult >= 0)
- {
- if (compareResult > 0)
- {
- metric = testMetric;
- metricSet = TRUE;
- if (bestMoves)
- bestMoves->nMoves = 0;
- }
- if (bestMoves)
- bestMoves->move[bestMoves->nMoves++] =
- PIECEMOVE
- (
- NORMALMOVE,
- where,
- moves.end[m],
- TYPEQUEEN
- );
- }
- testMetric.materialDiff -=
- whatPiece(moves.end[m])->signedValue();
- restorePawn(moves.end[m]);
-
- promote(moves.end[m], TYPEKNIGHT);
- testMetric.materialDiff +=
- whatPiece(moves.end[m])->signedValue();
- if (lookAhead > 1)
- helpFindBestMoves
- (
- lookAhead - 1,
- OtherColor(moveColor),
- testMetric,
- (BESTMOVES *) 0
- );
- compareResult = compareMetric
- (
- testMetric,
- metric,
- metricSet,
- moveColor
- );
- if (compareResult >= 0)
- {
- if (compareResult > 0)
- {
- metric = testMetric;
- metricSet = TRUE;
- if (bestMoves)
- bestMoves->nMoves = 0;
- }
- if (bestMoves)
- bestMoves->move[bestMoves->nMoves++] =
- PIECEMOVE
- (
- NORMALMOVE,
- where,
- moves.end[m],
- TYPEKNIGHT
- );
- }
- restorePawn(moves.end[m]);
- }
- else // no promotion
- {
- if (lookAhead > 1)
- helpFindBestMoves
- (
- lookAhead - 1,
- OtherColor(moveColor),
- testMetric,
- (BESTMOVES *) 0
- );
- compareResult = compareMetric
- (
- testMetric,
- metric,
- metricSet,
- moveColor
- );
- if (compareResult >= 0)
- {
- if (compareResult > 0)
- {
- metric = testMetric;
- metricSet = TRUE;
- if (bestMoves)
- bestMoves->nMoves = 0;
- }
- if (bestMoves)
- bestMoves->move[bestMoves->nMoves++] =
- PIECEMOVE
- (
- NORMALMOVE,
- where,
- moves.end[m]
- );
- }
- }
-
- undoMove
- (
- moves.end[m],
- where,
- undoData
- );
-
- } // end of for loop over each legal move for piece
-
- }
-
- } // end of double for loop over each board position
-
- // only try castling moves if look ahead move than one, since
- // nothing can be captured by doing a castling move
- if (lookAhead > 1)
- {
- castleType = QUEENSIDECASTLE;
- for ( ; ; )
- {
- if (canCastle(castleType, moveColor))
- {
- testMetric.materialDiff = origMaterialDiff;
- castle(castleType, moveColor, undoData);
- helpFindBestMoves
- (
- lookAhead - 1,
- OtherColor(moveColor),
- testMetric,
- (BESTMOVES *) 0
- );
- compareResult = compareMetric
- (
- testMetric,
- metric,
- metricSet,
- moveColor
- );
- if (compareResult >= 0)
- {
- if (compareResult > 0)
- {
- metric = testMetric;
- metricSet = TRUE;
- if (bestMoves)
- bestMoves->nMoves = 0;
- }
- if (bestMoves)
- bestMoves->move[bestMoves->nMoves++] =
- PIECEMOVE(castleType);
- }
- undoCastle(castleType, moveColor, undoData);
- }
- if (castleType == KINGSIDECASTLE)
- break;
- castleType = KINGSIDECASTLE;
- }
-
- // see if the loss of the king is the result of a stalemate
- // instead of check mate
- if (metric.kingSituation[moveColor] == KINGLOST)
- {
- helpFindBestMoves
- (
- 1,
- OtherColor(moveColor),
- testMetric,
- (BESTMOVES *) 0
- );
- if (testMetric.kingSituation[moveColor] != KINGLOST)
- // king will be lost on next move, but is not in check
- metric.kingSituation[moveColor] = STALEMATE;
- }
- }
-
- return;
- }
-
- // list all legal horizontal moves in one direction from a given starting
- // point
- LOCAL void horzMoves
- (
- int row,
- int col,
- int delta,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- int limit = delta == 1 ? NUMCOLS : -1;
- PIECECOLOR color = board.whatPiece(row, col)->whatColor();
-
- for ( ; ; )
- {
- col += delta;
- if (col == limit)
- return;
- if (board.whatPiece(row, col))
- if (board.whatPiece(row, col)->whatColor() == color)
- return;
- moves.end[moves.nMoves].row = row;
- moves.end[moves.nMoves++].col = col;
- if (board.whatPiece(row, col))
- return;
- }
- }
-
- // list all legal vertical moves in one direction from a given starting
- // point
- LOCAL void vertMoves
- (
- int row,
- int col,
- int delta,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- int limit = delta == 1 ? NUMROWS : -1;
- PIECECOLOR color = board.whatPiece(row, col)->whatColor();
-
- for ( ; ; )
- {
- row += delta;
- if (row == limit)
- return;
- if (board.whatPiece(row, col))
- if (board.whatPiece(row, col)->whatColor() == color)
- return;
- moves.end[moves.nMoves].row = row;
- moves.end[moves.nMoves++].col = col;
- if (board.whatPiece(row, col))
- return;
- }
- }
-
- // list all legal rook moves from a given starting point
- LOCAL void rookMoves
- (
- int row,
- int col,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- horzMoves(row, col, 1, board, moves);
- horzMoves(row, col, -1, board, moves);
- vertMoves(row, col, 1, board, moves);
- vertMoves(row, col, -1, board, moves);
-
- return;
- }
-
- // list all legal diagonal moves from a given starting point in a
- // single direction
- LOCAL void diagMoves
- (
- int row,
- int col,
- int rowDelta,
- int colDelta,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- int rowLimit = rowDelta == 1 ? NUMROWS : -1;
- int colLimit = colDelta == 1 ? NUMCOLS : -1;
- PIECECOLOR color = board.whatPiece(row, col)->whatColor();
-
- for ( ; ; )
- {
- row += rowDelta;
- col += colDelta;
- if ((row == rowLimit) || (col == colLimit))
- return;
- if (board.whatPiece(row, col))
- if (board.whatPiece(row, col)->whatColor() == color)
- return;
- moves.end[moves.nMoves].row = row;
- moves.end[moves.nMoves++].col = col;
- if (board.whatPiece(row, col))
- return;
- }
- }
-
- // list all legal bishop moves from a given starting point
- LOCAL void bishopMoves
- (
- int row,
- int col,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- diagMoves(row, col, 1, 1, board, moves);
- diagMoves(row, col, 1, -1, board, moves);
- diagMoves(row, col, -1, 1, board, moves);
- diagMoves(row, col, -1, -1, board, moves);
-
- return;
- }
-
- // check if a position is within the board
- LOCAL BOOL withinBoard
- (
- int row,
- int col
- )
- {
- return ((0 <= row) && (row < NUMROWS) &&
- (0 <= col) && (col < NUMCOLS));
- }
-
- // row and colomn offsets from a position
- class POSITIONOFFSET
- {
- public:
- int row, col;
- };
-
- // list of moves from a given starting position generated by applying
- // a table of position offsets
- LOCAL void movesFromOffsets
- (
- int row,
- int col,
- int nOffsets,
- const POSITIONOFFSET *offset,
- const BOARD &board,
- POSITIONLIST &moves
- )
- {
- PIECECOLOR color = board.whatPiece(row, col)->whatColor();
- int i;
- PIECE *p;
-
- for (i = 0; i < nOffsets; i++)
- {
- moves.end[moves.nMoves].row = row + offset[i].row;
- moves.end[moves.nMoves].col = col + offset[i].col;
- if (withinBoard(moves.end[moves.nMoves].row,
- moves.end[moves.nMoves].col))
- {
- p = board.whatPiece
- (
- moves.end[moves.nMoves].row = row + offset[i].row,
- moves.end[moves.nMoves].col = col + offset[i].col
- );
-
- if (!p)
- moves.nMoves++;
- else if (p->whatColor() != color)
- moves.nMoves++;
- }
- }
-
- return;
- }
-
- const POSITIONOFFSET kingOffset[] =
- { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1}, { 0, 1 },
- { 1, -1 }, { 1, 0 }, { 1, 1 } };
- const int nKingOffsets = ARRAY_LENGTH(kingOffset);
-
- const POSITIONOFFSET knightOffset[] =
- { { 1, 2 }, { 2, 1}, { -1, 2 }, { 2, -1 }, { 1, -2}, { -2, 1 },
- { -1, -2 }, { -2, -1 } };
- const int nKnightOffsets = ARRAY_LENGTH(knightOffset);
-
- void PAWN::promote(PIECETYPE promoteType)
- {
- switch (promoteType)
- {
- case TYPEQUEEN:
- promotePiece = new QUEEN(whatColor());
- break;
-
- case TYPEROOK:
- promotePiece = new ROOK(whatColor());
- break;
-
- case TYPEBISHOP:
- promotePiece = new BISHOP(whatColor());
- break;
-
- case TYPEKNIGHT:
- promotePiece = new KNIGHT(whatColor());
- break;
- }
-
- if (!promotePiece)
- OutOfMemory();
-
- return;
- }
-
- void PAWN::restoreToPawn(void)
- {
- delete promotePiece;
- promotePiece = (PIECE *) 0;
-
- return;
- }
-
- void PAWN::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- int delta, limit;
- POSITION doubleMovedPawn;
-
- if (promotePiece)
- {
- promotePiece->legalMoves(start, board, moves);
- return;
- }
-
- if (whatColor() == WHITE)
- {
- delta = 1;
- limit = NUMCOLS;
- }
- else
- {
- delta = -1;
- limit = -1;
- }
-
- moves.nMoves = 0;
-
- // check if en passant capture possible
- if (board.lastMoveDoublePawn(doubleMovedPawn))
- if ((start.col == doubleMovedPawn.col) &&
- (whatColor() != board.whatPiece(doubleMovedPawn)->whatColor()))
- {
- if ((start.row - 1) == doubleMovedPawn.row)
- {
- moves.end[moves.nMoves].row = start.row - 1;
- moves.end[moves.nMoves++].col = start.col + delta;
- }
- else if ((start.row + 1) == doubleMovedPawn.row)
- {
- moves.end[moves.nMoves].row = start.row + 1;
- moves.end[moves.nMoves++].col = start.col + delta;
- }
- }
-
- start.col += delta;
-
- if (start.col == limit)
- return;
-
- // check for moves ahead
- if (!board.whatPiece(start))
- {
- moves.end[moves.nMoves++] = start;
- // check if initial double move possible
- if (!hasBeenMoved())
- if (!board.whatPiece(start.row, start.col + delta))
- {
- moves.end[moves.nMoves].row = start.row;
- moves.end[moves.nMoves++].col = start.col + delta;
- }
- }
-
- // check for captures
-
- if (start.row > 0)
- if (board.whatPiece(start.row - 1, start.col))
- if (board.whatPiece(start.row - 1, start.col)->whatColor() !=
- whatColor())
- {
- moves.end[moves.nMoves].row = start.row - 1;
- moves.end[moves.nMoves++].col = start.col;
- }
-
- if (start.row < (NUMROWS - 1))
- if (board.whatPiece(start.row + 1, start.col))
- if (board.whatPiece(start.row + 1, start.col)->whatColor() !=
- whatColor())
- {
- moves.end[moves.nMoves].row = start.row + 1;
- moves.end[moves.nMoves++].col = start.col;
- }
-
- return;
- }
-
- void ROOK::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- moves.nMoves = 0;
- rookMoves(start.row, start.col, board, moves);
-
- return;
- }
-
- void KNIGHT::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- moves.nMoves = 0;
- movesFromOffsets(start.row, start.col, nKnightOffsets, knightOffset,
- board, moves);
-
- return;
- }
-
- void BISHOP::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- moves.nMoves = 0;
- bishopMoves(start.row, start.col, board, moves);
-
- return;
- }
-
- void QUEEN::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- moves.nMoves = 0;
- rookMoves(start.row, start.col, board, moves);
- bishopMoves(start.row, start.col, board, moves);
-
- return;
- }
-
- void KING::legalMoves
- (
- POSITION start,
- const BOARD &board,
- POSITIONLIST &moves
- ) const
- {
- moves.nMoves = 0;
- movesFromOffsets(start.row, start.col, nKingOffsets, kingOffset,
- board, moves);
-
- return;
- }
-