home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume4
/
chtrans
/
trmoves.c
< prev
Wrap
C/C++ Source or Header
|
1988-06-07
|
20KB
|
786 lines
/*
* Copyright (c) 1986 by Ray Balogh (rabalogh@ccng.waterloo.edu)
*
* Permission is granted to anyone to use this software for any
* purpose on any computer system, and to redistribute it freely,
* subject to the following restrictions:
*
* 1. The author is not responsible for the consequences of use of
* this software, no matter how awful, even if they arise
* from defects in it.
*
* 2. The origin of this software must not be misrepresented, either
* by explicit claim or by omission.
*
* 3. Altered versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
*/
/* The following copyright notice appears in the chess program from which
* legal move generation code was derived:
*
C source for CHESS Rev. 3-10-87
Written by John Stanback (hplabs!hpfcla!hpisla!hpltca!jhs)
Patches for BSD Unix by Rich Salz (rs@mirror.TMC.COM) - 5/3/87
*
*
****************************************************************************
*/
#include <stdio.h>
#define true 1
#define false 0
#define neutral 0
#define white 1
#define black 2
#define no_piece 0
#define pawn 1
#define knight 2
#define bishop 3
#define rook 4
#define queen 5
#define king 6
#define px " PNBRQK"
#define qx " pnbrqk"
#define rx "12345678"
#define cx "abcdefgh"
#define check 0x00000001
#define capture 0x00000002
#define draw 0x00000004
#define promote_n 0x00000010
#define promote_b 0x00000020
#define promote_r 0x00000040
#define promote_q 0x00000080
#define promote (promote_n|promote_b|promote_r|promote_q)
#define incheck 0x00000100
#define epmask 0x00000200
#define exact 0x00000400
#define pwnthrt 0x00000800
#define MAXMVSTR 12
#define DUNNO '_'
#define ETC '*'
#define BADCHAR '\004'
#define PLYSIDE(ply) (ply % 2 ? "black" : "white")
struct leaf
{
int f,t;
unsigned int flags;
};
int row[64],col[64],Index[64];
int PieceList[3][16],PieceCnt[3];
int castld[3],kingmoved[3],mtl[3],pmtl[3];
int qrookmoved[3],krookmoved[3];
int PawnCnt[3][8];
int GameCnt,epsquare = -1;
unsigned int GameList[240];
int GamePc[240],GameClr[240];
int GamePiece[240],GameColor[240],GamePromote[240];
int value[8]={0,100,330,330,500,950,999};
int otherside[3]={0,2,1};
int map[64]=
{26,27,28,29,30,31,32,33,38,39,40,41,42,43,44,45,
50,51,52,53,54,55,56,57,62,63,64,65,66,67,68,69,
74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,
98,99,100,101,102,103,104,105,110,111,112,113,114,115,116,117};
int unmap[144]=
{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,0,1,2,3,4,5,6,7,-1,-1,-1,-1,8,9,10,11,12,13,14,15,-1,-1,
-1,-1,16,17,18,19,20,21,22,23,-1,-1,-1,-1,24,25,26,27,28,29,30,31,-1,-1,
-1,-1,32,33,34,35,36,37,38,39,-1,-1,-1,-1,40,41,42,43,44,45,46,47,-1,-1,
-1,-1,48,49,50,51,52,53,54,55,-1,-1,-1,-1,56,57,58,59,60,61,62,63,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
int board[64]=
{rook,knight,bishop,queen,king,bishop,knight,rook,
pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
rook,knight,bishop,queen,king,bishop,knight,rook};
int color[64]=
{white,white,white,white,white,white,white,white,
white,white,white,white,white,white,white,white,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
black,black,black,black,black,black,black,black,
black,black,black,black,black,black,black,black};
int sweep[7]= {false,false,false,true,true,true,false};
int Dstpwn[3]={0,4,6};
int Dstart[7]={6,4,8,4,0,0,0};
int Dstop[7]={7,5,15,7,3,7,7};
int Dir[16]={1,12,-1,-12,11,13,-11,-13,10,-10,14,-14,23,-23,25,-25};
int MovePnt = 0;
struct leaf Moves[2000];
char charmap[] = " PNBRQK";
int real_ep_square = -1;
InitializeStats()
{
register int i,loc;
int l,r,c;
for (r = 0; r < 8; r++)
for (c = 0; c < 8; c++)
{
l = 8*r+c;
row[l] = r; col[l] = c;
}
for (i = 0; i < 8; i++)
PawnCnt[white][i] = PawnCnt[black][i] = 0;
/*epsquare = -1;*/
GameCnt = -1;
castld[white] = castld[black] = false;
kingmoved[white] = kingmoved[black] = 0;
krookmoved[white] = krookmoved[black] = 0;
qrookmoved[white] = qrookmoved[black] = 0;
mtl[white] = mtl[black] = pmtl[white] = pmtl[black]=0;
PieceCnt[white] = PieceCnt[black] = 0;
for (loc = 0; loc < 64; loc++)
if (color[loc] != neutral)
{
mtl[color[loc]] += value[board[loc]];
if (board[loc] == pawn)
{
pmtl[color[loc]] += value[pawn];
++PawnCnt[color[loc]][col[loc]];
}
if (board[loc] == king) Index[loc] = 0;
else Index[loc] = ++PieceCnt[color[loc]];
PieceList[color[loc]][Index[loc]] = loc;
}
}
MakeMove(side,node,tempb,tempc)
int side,*tempc,*tempb;
struct leaf *node;
/*
Update Arrays board[], color[], and Index[] to reflect the new
board position obtained after making the move pointed to by
node. Also update miscellaneous stuff that changes when a move
is made.
*/
{
register int f,t;
int ok,xside;
int prom_val;
int bf, bt;
xside = otherside[side];
epsquare = -1;
f = node->f; t = node->t;
GameList[++GameCnt] = (f<<8) + t;
if (f == 255 || t == 255)
{
GamePc[GameCnt] = no_piece; GameClr[GameCnt] = neutral;
GamePiece[GameCnt] = no_piece; GameColor[GameCnt] = neutral;
GamePromote[GameCnt] = no_piece;
castle(side,f,t,1,&ok);
}
else
{
bf = board[f]; bt = board[t];
*tempc = color[t]; *tempb = bt;
GamePc[GameCnt] = *tempb; GameClr[GameCnt] = *tempc;
GamePiece[GameCnt] = bf; GameColor[GameCnt] = color[f];
GamePromote[GameCnt] = prompiece( node->flags );
if (*tempc != neutral)
{
UpdatePieceList(*tempc,t,1);
if (*tempb == pawn) --PawnCnt[*tempc][col[t]];
if (bf == pawn)
{
--PawnCnt[side][col[f]];
++PawnCnt[side][col[t]];
}
mtl[xside] -= value[*tempb];
if (*tempb == pawn) pmtl[xside] -= value[pawn];
}
if (bf == king) ++kingmoved[side];
if (f==0 && bf==rook || t==0 && bt==rook) ++qrookmoved[white];
if (f==7 && bf==rook || t==7 && bt==rook) ++krookmoved[white];
if (f==56 && bf==rook || t==56 && bt==rook) ++qrookmoved[black];
if (f==63 && bf==rook || t==63 && bt==rook) ++krookmoved[black];
color[t] = color[f]; board[t] = bf;
Index[t] = Index[f]; PieceList[side][Index[t]] = t;
color[f] = neutral; board[f] = no_piece;
if (board[t] == pawn)
if (t-f == 16) epsquare = f+8;
else if (f-t == 16) epsquare = f-8;
if (node->flags & promote)
{
prom_val = prompiece( node->flags );
board[t] = prom_val;
mtl[side] += value[prom_val] - value[pawn];
pmtl[side] -= value[pawn];
}
if (node->flags & epmask) en_passant(side,xside,f,t,1);
}
}
UnmakeMove(side,node,tempb,tempc)
int side,*tempc,*tempb;
struct leaf *node;
/*
Take back the move pointed to by node.
*/
{
register int f,t;
int ok,xside;
int prom_val;
int bf, bt;
xside = otherside[side];
epsquare = -1;
f = node->f; t = node->t;
GameCnt--;
if (f == 255 || t == 255) castle(side,f,t,2,&ok);
else
{
if (board[t] == king) --kingmoved[side];
bf = board[f]; bt = board[t];
if (f==0 && bt==rook || t==0 && bf==rook) --qrookmoved[white];
if (f==7 && bt==rook || t==7 && bf==rook) --krookmoved[white];
if (f==56 && bt==rook || t==56 && bf==rook) --qrookmoved[black];
if (f==63 && bt==rook || t==63 && bf==rook) --krookmoved[black];
color[f] = color[t]; board[f] = board[t];
Index[f] = Index[t]; PieceList[side][Index[f]] = f;
color[t] = *tempc; board[t] = *tempb;
if (*tempc != neutral)
{
UpdatePieceList(*tempc,t,2);
if (*tempb == pawn) ++PawnCnt[*tempc][col[t]];
if (board[f] == pawn)
{
--PawnCnt[side][col[t]];
++PawnCnt[side][col[f]];
}
mtl[xside] += value[*tempb];
if (*tempb == pawn) pmtl[xside] += value[pawn];
}
if (node->flags & promote)
{
prom_val = prompiece( node->flags );
board[f] = pawn;
mtl[side] += value[pawn] - value[prom_val];
pmtl[side] += value[pawn];
}
if (node->flags & epmask) en_passant(side,xside,f,t,2);
}
}
int
prompiece( promflags )
int promflags;
{
return( (promflags & promote_q) ? queen :
(promflags & promote_r) ? rook :
(promflags & promote_b) ? bishop :
(promflags & promote_n) ? knight :
no_piece
);
}
UpdatePieceList(side,loc,iop)
int side,loc,iop;
/*
Array PieceList[side][indx] contains the location of all the pieces of
either side. Array Index[loc] contains the indx into PieceList for a
given square.
*/
{
register int i;
if (iop == 1)
{
PieceCnt[side]--;
for (i = Index[loc]; i <= PieceCnt[side]; i++)
{
PieceList[side][i] = PieceList[side][i+1];
Index[PieceList[side][i]] = i;
}
}
else
{
PieceCnt[side]++;
PieceList[side][PieceCnt[side]] = loc;
Index[loc] = PieceCnt[side];
}
}
castle(side,f,t,iop,ok)
int side,f,t,iop,*ok;
{
int i,e,k1,k2,r1,r2,c1,c2,t0,xside;
xside = otherside[side];
if (side == white) e = 0; else e = 56;
if (f == 255)
{
/* castle king's side */
k1 = e+4; k2 = e+6; r1 = e+7; r2 = e+5; c1 = k1; c2 = r1;
}
else
{
/* castle queen's side */
k1 = e+4; k2 = e+2; r1 = e; r2 = e+3; c1 = r1; c2 = k1;
}
if (iop == 0)
{
*ok = false;
if (f == 255)
{
if (castld[side] || krookmoved[side] > 0 || kingmoved[side] > 0)
return;
}
else
{
if (castld[side] || qrookmoved[side] > 0 || kingmoved[side] > 0)
return;
}
if (board[k1] == king && board[r1] == rook)
{
*ok = true;
for (i = c1; i <= c2; i++)
if (isincheck(side,i)) {*ok = false; break;}
if (*ok)
for (i = c1+1; i < c2; i++)
if (color[i] != neutral) {*ok = false; break;}
}
}
else
{
if (iop == 1) castld[side] = true; else castld[side] = false;
if (iop == 2)
{
t0 = k1; k1 = k2; k2 = t0;
t0 = r1; r1 = r2; r2 = t0;
}
board[k2] = king; color[k2] = side; Index[k2] = 0;
board[k1] = no_piece; color[k1] = neutral;
board[r2] = rook; color[r2] = side; Index[r2] = Index[r1];
board[r1] = no_piece; color[r1] = neutral;
PieceList[side][Index[k2]] = k2;
PieceList[side][Index[r2]] = r2;
}
}
en_passant(side,xside,f,t,iop)
int side,f,t,iop;
{
int l;
if (t > f) l = t-8; else l = t+8;
if (iop == 1)
{
board[l] = no_piece; color[l] = neutral;
}
else
{
board[l] = pawn; color[l] = xside;
}
InitializeStats();
}
int
isincheck(side,kingloc)
int side,kingloc;
/*
Determine if king is in check (efficiently).
*/
{
register int u, d, m, j, loc;
int co, ro;
int xside;
int stop;
int m0;
int piece;
xside = otherside[side];
/*kingloc = PieceList[side][0];*/
co = col[kingloc]; ro = row[kingloc];
/* check for pawn checks */
if ( side == white ) {
if ( ro < 6 ) {
if ( co > 0 && color[kingloc+7] == xside && board[kingloc+7] == pawn )
return( true );
if ( co < 7 && color[kingloc+9] == xside && board[kingloc+9] == pawn )
return( true );
}
} else {
if ( ro > 1 ) {
if ( co < 7 && color[kingloc-7] == xside && board[kingloc-7] == pawn )
return( true );
if ( co > 0 && color[kingloc-9] == xside && board[kingloc-9] == pawn )
return( true );
}
}
/* check for knight checks */
m0 = map[kingloc]; stop = Dstop[knight];
for ( j = Dstart[knight]; j <= stop; j++ ) {
if ( (loc = unmap[m0+Dir[j]]) < 0 ) continue;
if ( board[loc] == knight && color[loc] == xside )
return( true );
}
/* check for bishop, rook and queen checks */
for ( piece = bishop; piece <= rook; piece+=(rook-bishop) )
{
stop = Dstop[piece];
for (j = Dstart[piece]; j <= stop; j++)
{
d = Dir[j]; m = m0+d; u = unmap[m];
while (u >= 0)
{
if (color[u] == neutral)
{
m += d; u = unmap[m];
}
else
{
if ( (board[u] == piece || board[u] == queen)
&& color[u] == xside ) return( true );
u = -1;
}
}
}
}
return( false );
}
LinkMove(f,t,side,promoteto)
int f,t,side,promoteto;
{
/*
Add a move to the tree.
*/
struct leaf *node;
struct leaf tnode;
int tempb, tempc;
if ( !(f == 255 || t == 255) ) {
/* Don't bother to link the move if the king is in check afterwards;
ie. it is really illegal */
tnode.f = f; tnode.t = t;
tnode.flags = 0;
MakeMove(side,&tnode,&tempb,&tempc);
if (isincheck(side,PieceList[side][0]))
{
UnmakeMove(side,&tnode,&tempb,&tempc);
return;
}
else
UnmakeMove(side,&tnode,&tempb,&tempc);
}
node = &Moves[MovePnt];
++MovePnt;
node->flags = 0;
node->f = f; node->t = t;
if ( !(f == 255 || t == 255) )
{
if (color[t] != neutral)
{
node->flags |= capture;
}
if (board[f] == pawn)
{
if (row[t] == 0 || row[t] == 7) node->flags |= promoteto;
else if (t == real_ep_square) node->flags |= epmask;
}
}
}
GenMoves(loc,side,xside)
int loc,side,xside;
/*
Generate moves for a piece. The from square is mapped onto a 12 by
12 board and offsets (taken from array Dir[]) are added to the
mapped location. Array unmap[] maps the move back onto array
board[] (yielding a value of -1 if the to square is off the board).
This process is repeated for bishops, rooks, and queens until a
piece is encountered or the the move falls off the board. Legal
moves are then linked into the tree.
*/
{
register int m,u,d;
int i,m0,piece;
piece = board[loc]; m0 = map[loc];
if (sweep[piece])
{
for (i = Dstart[piece]; i <= Dstop[piece]; i++)
{
d = Dir[i]; m = m0+d; u = unmap[m];
while (u >= 0)
if (color[u] == neutral)
{
LinkMove(loc,u,side,no_piece);
m += d; u = unmap[m];
}
else if (color[u] == xside)
{
LinkMove(loc,u,side,no_piece);
u = -1;
}
else u = -1;
}
}
else if (piece == pawn)
{
if (side == white && color[loc+8] == neutral)
{
if (row[loc] == 6)
{
LinkMove(loc,loc+8,side,promote_q);
LinkMove(loc,loc+8,side,promote_r);
LinkMove(loc,loc+8,side,promote_b);
LinkMove(loc,loc+8,side,promote_n);
}
else
LinkMove(loc,loc+8,side,no_piece);
if (row[loc] == 1)
if (color[loc+16] == neutral)
LinkMove(loc,loc+16,side,no_piece);
}
else if (side == black && color[loc-8] == neutral)
{
if (row[loc] == 1)
{
LinkMove(loc,loc-8,side,promote_q);
LinkMove(loc,loc-8,side,promote_r);
LinkMove(loc,loc-8,side,promote_b);
LinkMove(loc,loc-8,side,promote_n);
}
else
LinkMove(loc,loc-8,side,no_piece);
if (row[loc] == 6)
if (color[loc-16] == neutral)
LinkMove(loc,loc-16,side,no_piece);
}
for (i = Dstart[piece]; i <= Dstop[piece]; i++)
if ((u = unmap[m0+Dir[i]]) >= 0)
if (color[u] == xside || u == real_ep_square)
if (side==white && row[loc]==6 || side==black && row[loc]==1)
{
LinkMove(loc,u,side,promote_q);
LinkMove(loc,u,side,promote_r);
LinkMove(loc,u,side,promote_b);
LinkMove(loc,u,side,promote_n);
}
else
LinkMove(loc,u,side,no_piece);
}
else
{
for (i = Dstart[piece]; i <= Dstop[piece]; i++)
if ((u = unmap[m0+Dir[i]]) >= 0)
if (color[u] != side)
LinkMove(loc,u,side,no_piece);
}
}
MoveList(side)
int side;
/*
Fill the array Moves[] with all available moves for side to
play. Array MovePnt contains the index into Moves[].
*/
{
register int i;
int ok,xside;
static int initted = false;
if ( !initted ) {
InitializeStats();
initted = true;
}
MovePnt = 0;
xside = otherside[side];
Dstart[pawn] = Dstpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
for (i = 0; i <= PieceCnt[side]; i++)
GenMoves(PieceList[side][i],side,xside);
castle(side,255,0,0,&ok);
if (ok) LinkMove(255,0,side,no_piece);
castle(side,0,255,0,&ok);
if (ok) LinkMove(0,255,side,no_piece);
}
ToAlgNot( form1, form2, form3, node, side )
char form1[], form2[], form3[];
struct leaf *node;
{
int f, t, fr, tr;
char ff, tf, piece, cap;
char prom;
f = node->f; t = node->t;
if ( f == 255 ) { /* castle king's side */
ff = 'e'; tf = 'g';
fr = tr = (side == white) ? 1 : 8;
cap = '-';
piece = 'K';
} else if ( t == 255 ) { /* castle queen's side */
ff = 'e'; tf = 'c';
fr = tr = (side == white) ? 1 : 8;
cap = '-';
piece = 'K';
} else {
ff = col[f] + 'a'; tf = col[t] + 'a';
fr = row[f] + 1; tr = row[t] + 1;
cap = node->flags&(capture|epmask) ? ':' : '-';
piece = charmap[board[f]];
}
switch ( node->flags & promote ) {
case promote_n: prom = 'N'; break;
case promote_b: prom = 'B'; break;
case promote_r: prom = 'R'; break;
case promote_q:
prom = 'Q';
sprintf( form2, "%c%c%d%c%c%d*", piece, ff, fr, cap, tf, tr );
break;
default: prom = '*';
}
sprintf( form1, "%c%c%d%c%c%d%c*", piece, ff, fr, cap, tf, tr, prom );
sprintf( form3, "%c%d%c%d", ff, fr, tf, tr );
if ( prom != 'Q' )
strcpy( form2, form1 );
}
int
MvComp( incomp, reference )
char *incomp, *reference;
{
for ( ; *incomp == *reference || *incomp == DUNNO; incomp++, reference++ )
if ( *incomp == '\0' || *reference == '\0' )
return( true );
if ( *incomp == ETC ||
(*reference == ETC &&
(*incomp == '\0' || index("nbrqNBRQ",*incomp) == NULL)) )
return( true );
return( false );
}
int
DoMove(side, move, ply)
int side;
char move[];
int ply;
{
int i, j, n;
int tempb, tempc;
char expandp[MAXMVSTR], expand[MAXMVSTR], compact[MAXMVSTR];
char gexpand[MAXMVSTR], gcompact[MAXMVSTR];
struct leaf *gnode;
MoveList( side );
for ( n = 0, i = 0; i < MovePnt; i++ ) {
ToAlgNot( expandp, expand, compact, &Moves[i], side );
if ( MvComp(move,expandp) || MvComp(move,expand) ) {
#ifdef DEBUG
printf( "%s,%s,%s,%s\n", move, expandp, expand, compact );
#endif
strcpy( gexpand, expand );
strcpy( gcompact, compact );
gnode = &Moves[i];
n++;
}
}
switch ( n ) {
case 0:
#ifdef VERBOSE
printf( "move %d, %s: illegal move (%s) -- legal moves are:\n",
ply/2+1, PLYSIDE(ply), move );
for ( i = 0; i < MovePnt; ) {
printf(" ");
for (j = 0; j < 8 && i < MovePnt; j++, i++) {
ToAlgNot( expandp, expand, compact, &Moves[i], side );
printf( " %s", expand );
}
printf("\n");
}
#else
printf( "illegal move\n" );
#endif
return( false );
case 1:
printf( "%s\n", gcompact ); fflush( stdout );
MakeMove( side, gnode, &tempb, &tempc );
real_ep_square = epsquare;
return( true );
default:
#ifdef VERBOSE
printf( "move %d, %s: ambiguous move (%s) matches:\n",
ply/2+1, PLYSIDE(ply), move );
for (i = 0; i < MovePnt;) {
printf(" ");
for (j = 0; j < 8 && i < MovePnt; j++, i++) {
ToAlgNot( expandp, expand, compact, &Moves[i], side );
if ( MvComp(move,expandp) || MvComp(move,expand) )
printf( " %s\n", expand );
}
printf( "\n" );
}
#else
printf( "ambiguous move\n" );
#endif
return( false );
}
}
trans(move, ply)
char move[];
int ply;
{
static int side = white;
if ( !DoMove(side,move,ply) )
return;
side = otherside[side];
}