home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR2
/
CBUFF09.ZIP
/
SRC.ZIP
/
POSITION.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-16
|
21KB
|
765 lines
/* $Id: position.c,v 1.1.1.1 1993/06/21 11:12:00 anjo Exp $
*
* File position.c
* Part of ChessBase utilities file format (CBUFF)
* Author Horst Aurisch, aurisch@informatik.uni-bonn.de
* Anjo Anjewierden, anjo@swi.psy.uva.nl
* Purpose Internal board representation and move generation
* Works with GNU CC 2.4.5
*
* Notice Copyright (c) 1993 Anjo Anjewierden
*
* History 08/06/93 (Created)
* 30/06/93 (Integrated getmove.c)
* 05/08/93 (Last modified)
*/
/*------------------------------------------------------------
* Directives
*------------------------------------------------------------*/
#include "cbuff.h"
/*------------------------------------------------------------
* Definitions
*------------------------------------------------------------*/
Piece first[8] = { ROOK, KNIGHT, BISHOP, QUEEN,
KING, BISHOP, KNIGHT, ROOK
};
/*------------------------------------------------------------
* Initialisation
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node newPosition
@deftypefun Position newPosition ()
Returns a new chess position. The position is initialised to the
initial position.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Position
newPosition()
{ Square sq;
Position p;
p = alloc(sizeof(struct position));
for (sq=0; sq<8; sq++)
{ p->board[0+sq*8] = first[sq] | WHITE_MASK;
p->board[7+sq*8] = first[sq] | BLACK_MASK;
p->board[1+sq*8] = WHITE_PAWN;
p->board[6+sq*8] = BLACK_PAWN;
p->board[2+sq*8] = NO_PIECE;
p->board[3+sq*8] = NO_PIECE;
p->board[4+sq*8] = NO_PIECE;
p->board[5+sq*8] = NO_PIECE;
}
p->enPassant = 0;
p->toMove = WHITE;
p->nextMove = 1;
p->castling = (WHITE_SHORT | WHITE_LONG | BLACK_SHORT | BLACK_LONG);
return p;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node freePosition
@deftypefun void freePosition (Position @var{p})
Reclaims the memory associated with position @var{p}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
freePosition(Position p)
{ unalloc(p);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node clearPosition
@deftypefun void clearPosition (Position @var{p})
Clears position @var{p} such that it is empty (e.g. there are no pieces
on the board).
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
clearPosition(Position p)
{ Square sq;
for_squares(sq)
p->board[sq] = NO_PIECE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node copyPosition
@deftypefun void copyPosition (Position @var{p1}, Position @var{p2})
Copies position @var{p2} to @var{p1} (argument order is the same
as @code{strcpy}). Note: @var{p1} must have been allocated with @code{newPosition}
previously.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
copyPosition(Position p1, Position p2)
{ memcpy(p1, p2, sizeof(struct position));
}
/*------------------------------------------------------------
* Functions
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node doMovePosition
@deftypefun void doMovePosition (Position @var{p}, Move @var{m})
Plays move @var{m} in position @var{p}. The caller must ensure that
@var{m} is a legal move.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
doMovePosition(Position pos, Move move)
{ Square f = move->from;
Square t = move->to;
Piece p = move->piece;
int c = pos->toMove;
int ep = pos->enPassant;
int d = (c == WHITE ? 1 : -1);
Piece *board = pos->board;
pos->enPassant = 0;
/* En passant capture */
if (isPawnP(board[f]) && fileSquare(t) != fileSquare(f) && !board[t])
board[t-d] = 0;
/* Move the piece */
board[t] = board[f];
board[f] = NO_PIECE;
/* Promotion */
if (isPawnP(board[t]) && (rankSquare(t)==RANK_1 || rankSquare(t)==RANK_8))
board[t] = (p | (c == WHITE ? WHITE_MASK : BLACK_MASK));
/* Set new en passant flag */
if (isPawnP(board[t]) && abs(t-f) == 2)
pos->enPassant = 1 + (t>>3);
/* Castling */
if (isKingP(board[t]) && abs(t-f) == 16)
{ pos->enPassant = ep;
if (t>f)
{ board[t-8] = board[t+8];
board[t+8] = 0;
}
if (t<f)
{ board[t+8] = board[t-16];
board[t-16] = 0;
}
}
pos->toMove = (c ? WHITE : BLACK);
}
/*------------------------------------------------------------
* Ambiguous moves
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node ambiguousMovePositionP
@deftypefun bool ambiguousMovePositionP (Position @var{p}, Move @var{m}, Square * @var{sq})
Succeeds if move @var{m} is ambiguous in position @var{p}. The
ambiguous square is then stored in @var{sq}. The meaning of
ambiguous is that it is not possible to print @var{m} using short
algebraic notation.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
ambiguousMovePositionP(Position p, Move m, Square *from)
{ Piece *board = p->board;
Piece piece = board[m->from];
Square sq;
switch (piece)
{ case WHITE_KING:
case BLACK_KING:
case WHITE_PAWN:
case BLACK_PAWN: return FALSE;
case WHITE_ROOK:
case BLACK_ROOK:
case WHITE_KNIGHT:
case BLACK_KNIGHT:
case WHITE_BISHOP:
case BLACK_BISHOP:
case WHITE_QUEEN:
case BLACK_QUEEN: break;
default:
setError(ERR_UNKNOWN_PIECE);
return FALSE;
}
for_squares(sq)
{ if (board[sq] == piece)
{ if (m->from == sq)
continue;
if (attacksSquarePositionP(p, piece, sq, m->to))
{ *from = sq;
return TRUE;
}
}
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node enPassantMovePositionP
@deftypefun bool enPassantMovePositionP (Position @var{p}, Move @var{m})
Succeeds if move @var{m} in position @var{p} is an en passant capture.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
enPassantMovePositionP(Position p, Move m)
{ if ( isPawnP(p->board[m->from])
&& fileSquare(m->from) != fileSquare(m->to)
&& p->board[m->to] == NO_PIECE)
return TRUE;
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node castlingMovePositionP
@deftypefun bool castlingMovePositionP (Position @var{p}, Move @var{m})
Succeeds if move @var{m} in position @var{p} is a castling move.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
castlingMovePositionP(Position p, Move m)
{ if ( isKingP(p->board[m->from])
&& (m->from == E1 || m->from == E8 )
&& (rankSquare(m->from) == rankSquare(m->to))
&& (abs(fileSquare(m->from) - fileSquare(m->to)) == 2))
return TRUE;
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node checkMovePositionP
@deftypefun bool checkMovePositionP (Position @var{p}, Move @var{m})
Succeeds if playing move @var{m} in position @var{p} results in
checking the opponent's king.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
checkMovePositionP(Position p, Move m)
{ Piece piece = p->board[m->from];
Square kingSquare;
Square sq;
for_squares(sq)
{ if (isKingP(p->board[sq]))
{ if ( (p->toMove == WHITE && p->board[sq] == BLACK_KING)
|| (p->toMove == BLACK && p->board[sq] == WHITE_KING))
{ kingSquare = sq;
break;
}
}
}
if (attacksSquarePositionP(p, piece, m->to, kingSquare))
return TRUE;
p->board[m->from] = NO_PIECE;
for_squares(sq)
{ if ( (p->toMove == WHITE && isWhitePieceP(p->board[sq]))
|| (p->toMove == BLACK && isBlackPieceP(p->board[sq])))
{ if (attacksSquarePositionP(p, p->board[sq], sq, kingSquare))
{ p->board[m->from] = piece;
return TRUE;
}
}
}
p->board[m->from] = piece;
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node attacksSquarePositionP
@deftypefun bool attacksSquarePositionP (Position @var{p}, Piece @var{piece}, Square @var{from}, Square @var{to})
Succeeds if piece @var{piece} on square @var{from} attacks square @var{to}
in the given position @var{p}. The @var{piece} does not need to be on
square @var{from}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
attacksSquarePositionP(Position p, Piece piece, Square from, Square to)
{ int file;
int rank;
Piece *board = p->board;
file = fileSquare(to) - fileSquare(from);
rank = rankSquare(to) - rankSquare(from);
if (piece == WHITE_PAWN)
{ if (rank == 1 && abs(file) == 1) /* Only consider pawn captures. */
return TRUE;
return FALSE;
}
if (piece == BLACK_PAWN)
{ if (rank == -1 && abs(file) == 1)
return TRUE;
return FALSE;
}
if (isKingP(piece))
{ if (abs(file) <= 1 && abs(rank) <= 1)
return TRUE;
return FALSE;
}
if (isKnightP(piece))
{ if ( (abs(file) == 2 && abs(rank) == 1)
|| (abs(file) == 1 && abs(rank) == 2))
return TRUE;
return FALSE;
}
if (file == 0)
{ if (isQueenP(piece) || isRookP(piece))
{ int inc = (rank > 0 ? 1 : -1);
for (rank=rankSquare(from)+inc; rank!=rankSquare(to); rank+=inc)
if (board[makeSquare(fileSquare(to), rank)])
return FALSE;
return TRUE;
}
}
if (rank == 0)
{ if (isQueenP(piece) || isRookP(piece))
{ int inc = (file > 0 ? 1 : -1);
for (file=fileSquare(from)+inc; file!=fileSquare(to); file+=inc)
if (board[makeSquare(file, rankSquare(to))])
return FALSE;
return TRUE;
}
}
if (abs(file) == abs(rank))
{ if (isQueenP(piece) || isBishopP(piece))
{ int incFile = (file > 0 ? 1 : -1);
int incRank = (rank > 0 ? 1 : -1);
for (file=fileSquare(from)+incFile, rank=rankSquare(from)+incRank;
file!=fileSquare(to) && rank!=rankSquare(to);
file+=incFile, rank+=incRank)
if (board[makeSquare(file, rank)])
return FALSE;
return TRUE;
}
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node getStringMovePosition
@deftypefun {char *} getStringMovePosition (Position @var{p}, Move @var{m}, int @var{notation})
Returns the textual representation of playing move @var{m} in the
position @var{p}. The returned string is statically allocated. The
format of printing the move is determined by the current set of chess
symbols (@pxref{Chess symbols}) and by @var{notation}. If
@var{notation} is @code{LONG_ALGEBRAIC} the move is printed using long
algebraic notation, otherwise it is printed using short algebraic
notation.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
char *
getStringMovePosition(Position p, Move m, int notation)
{ static char str[100];
Square from = m->from;
Square to = m->to;
Piece piece = p->board[from];
char *s;
if (castlingMovePositionP(p, m))
{ if (to == G1 || to == G8)
{ strcpy(str, chessSymbol(CASTLING_SHORT));
return str;
}
if (to == C1 || to == C8)
{ strcpy(str, chessSymbol(CASTLING_LONG));
return str;
}
}
switch (piece)
{ case WHITE_KING:
case BLACK_KING: strcpy(str, chessSymbol(KING_SYMBOL)); break;
case WHITE_QUEEN:
case BLACK_QUEEN: strcpy(str, chessSymbol(QUEEN_SYMBOL)); break;
case WHITE_ROOK:
case BLACK_ROOK: strcpy(str, chessSymbol(ROOK_SYMBOL)); break;
case WHITE_BISHOP:
case BLACK_BISHOP: strcpy(str, chessSymbol(BISHOP_SYMBOL)); break;
case WHITE_KNIGHT:
case BLACK_KNIGHT: strcpy(str, chessSymbol(KNIGHT_SYMBOL)); break;
default: str[0] = '\0';
}
s = strrchr(str, '\0');
if (notation == LONG_ALGEBRAIC)
{ *s++ = 'a' + fileSquare(from);
*s++ = '1' + rankSquare(from);
if (p->board[to])
strcpy(s, chessSymbol(CAPTURE_SYMBOL));
else
strcpy(s, chessSymbol(MOVE_HYPHEN));
s = strrchr(s, '\0');
} else
{ Square ambiguous;
if (ambiguousMovePositionP(p, m, &ambiguous))
{ if (fileSquare(from) != fileSquare(ambiguous))
*s++ = 'a' + fileSquare(from);
else
*s++ = '1' + rankSquare(from);
}
if (isPawnP(p->board[from]) && (fileSquare(from) != fileSquare(to)))
*s++ = 'a' + fileSquare(from);
if (p->board[to])
{ strcpy(s, chessSymbol(CAPTURE_SYMBOL));
s = strrchr(s, '\0');
}
}
*s++ = 'a' + fileSquare(to);
*s++ = '1' + rankSquare(to);
if (m->piece)
{ strcpy(s, chessSymbol(PROMOTION_SYMBOL));
s = strrchr(s, '\0');
if (isQueenP(m->piece)) strcpy(s, chessSymbol(QUEEN_SYMBOL));
else if (isRookP(m->piece)) strcpy(s, chessSymbol(ROOK_SYMBOL));
else if (isKnightP(m->piece)) strcpy(s, chessSymbol(KNIGHT_SYMBOL));
else if (isBishopP(m->piece)) strcpy(s, chessSymbol(BISHOP_SYMBOL));
s = strrchr(s, '\0');
}
if (checkMovePositionP(p, m))
{ strcpy(s, chessSymbol(INCHECK_SYMBOL));
s = strrchr(s, '\0');
}
*s = '\0';
return str;
}
/*------------------------------------------------------------
* Printing diagrams part of a game
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node diagramPosition
@deftypefun void diagramPosition (Position @var{p}, TextBuffer @var{tb})
Prints position @var{p} as a diagram in text-buffer @var{tb}. This
function takes all user defined chess symbols into account and is
therefore usable to print diagrams as part of a game.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
diagramPosition(Position p, TextBuffer tb)
{ int file, rank;
stringTextBuffer(tb, chessSymbol(START_DIAGRAM));
for (rank=7; rank>=0; rank--)
{ if (rank != 7)
stringTextBuffer(tb, chessSymbol(START_DIAGRAM_RANK));
for (file=0; file<=7; file++)
{ switch (p->board[makeSquare(file,rank)])
{ case WHITE_KING: stringTextBuffer(tb,chessSymbol(DIAGRAM_WK)); break;
case WHITE_QUEEN: stringTextBuffer(tb,chessSymbol(DIAGRAM_WQ)); break;
case WHITE_ROOK: stringTextBuffer(tb,chessSymbol(DIAGRAM_WR)); break;
case WHITE_BISHOP: stringTextBuffer(tb,chessSymbol(DIAGRAM_WB)); break;
case WHITE_KNIGHT: stringTextBuffer(tb,chessSymbol(DIAGRAM_WN)); break;
case WHITE_PAWN: stringTextBuffer(tb,chessSymbol(DIAGRAM_WP)); break;
case BLACK_KING: stringTextBuffer(tb,chessSymbol(DIAGRAM_BK)); break;
case BLACK_QUEEN: stringTextBuffer(tb,chessSymbol(DIAGRAM_BQ)); break;
case BLACK_ROOK: stringTextBuffer(tb,chessSymbol(DIAGRAM_BR)); break;
case BLACK_BISHOP: stringTextBuffer(tb,chessSymbol(DIAGRAM_BB)); break;
case BLACK_KNIGHT: stringTextBuffer(tb,chessSymbol(DIAGRAM_BN)); break;
case BLACK_PAWN: stringTextBuffer(tb,chessSymbol(DIAGRAM_BP)); break;
default: if ((file+rank) & 1)
stringTextBuffer(tb, chessSymbol(DIAGRAM_WHITE_SQUARE));
else
stringTextBuffer(tb, chessSymbol(DIAGRAM_BLACK_SQUARE));
}
}
if (rank != 0)
stringTextBuffer(tb, chessSymbol(END_DIAGRAM_RANK));
}
stringTextBuffer(tb, chessSymbol(END_DIAGRAM));
}
/*------------------------------------------------------------
* Move generation
*------------------------------------------------------------*/
Square fromfield;
Square tofield;
Piece prompiece;
static jmp_buf env;
static int searchmove;
static int movnum;
/*------------------------------------------------------------
* Prototypes
*------------------------------------------------------------*/
static void PutMove(Square, Square, Piece);
static int OnBoard(int, int, int);
static void MovePiece(Position pos, Square, int, int, int, int);
static void Promote(Square, Square);
static void MakePawnMoves(Position, Square, int);
static void MakeKingMoves(Position, Square, int);
static void MakeRookMoves(Position, Square, int);
static void MakeBishopMoves(Position, Square, int);
static void MakeQueenMoves(Position, Square, int);
static void MakeKnightMoves(Position, Square, int);
/*------------------------------------------------------------
* Ordinal move generation (according to ChessBase format)
*------------------------------------------------------------*/
static void
PutMove(Square f, Square t, Piece p)
{ fromfield = f;
tofield = t;
prompiece = p;
movnum++;
if (movnum == searchmove)
longjmp(env, 1);
}
static int
OnBoard(int n, int y, int x)
{ return ((unsigned)(y+(n&7)) < 8) &&
((unsigned)(x+(n>>3)) < 8);
}
static void
MovePiece(Position pos, Square from, int c, int y, int x, int s)
{ Square to = from;
Square inc = 8*x+y;
if (!OnBoard(to,y,x))
return;
do
{ to += inc;
if (!pos->board[to])
PutMove(from,to,0);
else if ((pos->board[to]^c)>8)
{ PutMove(from,to,0);
return;
}
else return;
} while (s && OnBoard(to,y,x));
}
static void
Promote(Square from, Square to)
{ PutMove(from, to, QUEEN);
PutMove(from, to, ROOK);
PutMove(from, to, BISHOP);
PutMove(from, to, KNIGHT);
}
static void
MakePawnMoves(Position pos, Square f, int c)
{ int h;
int t;
int d;
int g;
if (c == WHITE)
{ d = 1;
g = 1;
} else
{ d = -1;
g = 6;
}
t = f+d;
if (!pos->board[t])
{ t += d;
if ((f&7) == g && !pos->board[t])
PutMove(f,t,0);
t -= d;
if ((t&7) == 7-g+d)
Promote(f,t);
else
PutMove(f,t,0);
}
t = f-8+d;
if (f&0x38 && (pos->board[t]^c)>8)
if ((t&7) == 7-g+d)
Promote(f,t);
else
PutMove(f,t,0);
t = f+8+d;
if ((f&0x38) != 0x38 && (pos->board[t]^c)>8)
if ((t&7) == 7-g+d)
Promote(f,t);
else
PutMove(f,t,0);
if ((f&7) == g+3*d)
{ h = (f>>3) - pos->enPassant;
t = f-8+d;
if (!h)
PutMove(f,t,0);
t = f+8+d;
if (h == -2)
PutMove(f,t,0);
}
}
static void
MakeKingMoves(Position pos, Square from, int c)
{ Piece *board = pos->board;
MovePiece(pos, from, c, -1, -1, 0);
MovePiece(pos, from, c, 0, -1, 0);
MovePiece(pos, from, c, 1, -1, 0);
MovePiece(pos, from, c, -1, 0, 0);
MovePiece(pos, from, c, 1, 0, 0);
MovePiece(pos, from, c, -1, 1, 0);
MovePiece(pos, from, c, 0, 1, 0);
MovePiece(pos, from, c, 1, 1, 0);
if (c == WHITE_MASK && from == E1)
{ if (board[H1] == WHITE_ROOK && !board[F1] && !board[G1])
PutMove(from,G1,0);
if (board[A1] == WHITE_ROOK && !board[D1] && !board[C1] && !board[B1])
PutMove(from,C1,0);
return;
}
if (c == BLACK_MASK && from == E8)
{ if (board[H8] == BLACK_ROOK && !board[F8] && !board[G8])
PutMove(from,G8,0);
if (board[A8] == BLACK_ROOK && !board[D8] && !board[C8] && !board[B8])
PutMove(from,C8,0);
return;
}
}
static void
MakeRookMoves(Position pos, Square from, int c)
{ MovePiece(pos, from, c, 0, -1, 1);
MovePiece(pos, from, c, -1, 0, 1);
MovePiece(pos, from, c, 0, 1, 1);
MovePiece(pos, from, c, 1, 0, 1);
}
static void
MakeBishopMoves(Position pos, Square from, int c)
{ MovePiece(pos, from, c, -1, -1, 1);
MovePiece(pos, from, c, -1, 1, 1);
MovePiece(pos, from, c, 1, 1, 1);
MovePiece(pos, from, c, 1, -1, 1);
}
static void
MakeQueenMoves(Position pos, Square from, int c)
{ MakeBishopMoves(pos, from, c);
MakeRookMoves(pos, from, c);
}
static void
MakeKnightMoves(Position pos, Square from, int c)
{ MovePiece(pos, from, c, -1, -2, 0);
MovePiece(pos, from, c, 1, -2, 0);
MovePiece(pos, from, c, -1, 2, 0);
MovePiece(pos, from, c, 1, 2, 0);
MovePiece(pos, from, c, -2, -1, 0);
MovePiece(pos, from, c, 2, -1, 0);
MovePiece(pos, from, c, -2, 1, 0);
MovePiece(pos, from, c, 2, 1, 0);
}
bool
getMovePosition(Position pos, int n, Move move)
{ Square sq;
int c;
c = (pos->toMove == WHITE ? WHITE_MASK : BLACK_MASK);
searchmove = n;
if (setjmp(env) == 0)
{ movnum = 0;
for (sq=0; sq<64; sq++)
{ switch ((pos->board[sq])^c)
{ case PAWN: MakePawnMoves(pos, sq, c); break;
case ROOK: MakeRookMoves(pos, sq, c); break;
case BISHOP: MakeBishopMoves(pos, sq, c); break;
case KNIGHT: MakeKnightMoves(pos, sq, c); break;
case QUEEN: MakeQueenMoves(pos, sq, c); break;
case KING: MakeKingMoves(pos, sq, c); break;
}
}
return FALSE;
}
move->from = fromfield;
move->to = tofield;
move->piece = prompiece;
return TRUE;
}