X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=56b4cb1eb0f633c865397c6535694a2243cd644f;hb=73b4112daf718e68b1b60db8a304c4f9a930c703;hp=e58cfa098a5ee6c99f307dd3f654ac399b877d49;hpb=a49a080da8e49d3d814116eb96205dbf77d6536b;p=xboard.git diff --git a/moves.c b/moves.c index e58cfa0..56b4cb1 100644 --- a/moves.c +++ b/moves.c @@ -2,8 +2,10 @@ * moves.c - Move generation and checking * $Id: moves.c,v 2.1 2003/10/27 19:21:00 mann Exp $ * - * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. - * Enhancements Copyright 1992-95 Free Software Foundation, Inc. + * Copyright 1991 by Digital Equipment Corporation, Maynard, + * Massachusetts. Enhancements Copyright + * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software + * Foundation, Inc. * * The following terms apply to Digital Equipment Corporation's copyright * interest in XBoard: @@ -27,24 +29,25 @@ * SOFTWARE. * ------------------------------------------------------------------------ * - * The following terms apply to the enhanced version of XBoard distributed - * by the Free Software Foundation: + * The following terms apply to the enhanced version of XBoard + * distributed by the Free Software Foundation: * ------------------------------------------------------------------------ - * This program is free software; you can redistribute it and/or modify + * + * GNU XBoard is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU XBoard is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * ------------------------------------------------------------------------ - */ + * along with this program. If not, see http://www.gnu.org/licenses/. * + * + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ #include "config.h" @@ -62,6 +65,7 @@ int WhitePiece P((ChessSquare)); int BlackPiece P((ChessSquare)); int SameColor P((ChessSquare, ChessSquare)); +int PosFlags(int index); extern char initialRights[BOARD_SIZE]; /* [HGM] all rights enabled, set in InitPosition */ @@ -644,7 +648,7 @@ void GenPseudoLegal(board, flags, epfile, callback, closure) case SHOGI BlackKing: case WhiteKing: case BlackKing: - walking: +// walking: for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) { if (i == 0 && j == 0) continue; @@ -1587,4 +1591,221 @@ ChessMove CoordsToAlgebraic(board, flags, epfile, return IllegalMove; } +// [HGM] XQ: the following code serves to detect perpetual chasing (Asian rules) + +typedef struct { + /* Input */ + int rf, ff, rt, ft; + /* Output */ + int recaptures; +} ChaseClosure; + +// I guess the following variables logically belong in the closure too, but I was too lazy and used globals + +int preyStackPointer, chaseStackPointer; + +struct { +char rf, ff, rt, ft; +} chaseStack[100]; + +struct { +char rank, file; +} preyStack[100]; + + + + +// there are three new callbacks for use with GenLegal: for adding captures, deleting them, and finding a recapture + +extern void AtacksCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void AttacksCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ // For adding captures that can lead to chase indictment to the chaseStack + if(board[rt][ft] == EmptySquare) return; // non-capture + if(board[rt][ft] == WhitePawn && rt < BOARD_HEIGHT/2) return; // Pawn before river can be chased + if(board[rt][ft] == BlackPawn && rt >= BOARD_HEIGHT/2) return; // Pawn before river can be chased + if(board[rf][ff] == WhitePawn || board[rf][ff] == BlackPawn) return; // Pawns are allowed to chase + if(board[rf][ff] == WhiteWazir || board[rf][ff] == BlackWazir) return; // King is allowed to chase + // move cannot be excluded from being a chase trivially (based on attacker and victim); save it on chaseStack + chaseStack[chaseStackPointer].rf = rf; + chaseStack[chaseStackPointer].ff = ff; + chaseStack[chaseStackPointer].rt = rt; + chaseStack[chaseStackPointer].ft = ft; + chaseStackPointer++; +} + +extern void ExistingAtacksCallback P((Board board, int flags, ChessMove kind, + int rf, int ff, int rt, int ft, + VOIDSTAR closure)); + +void ExistingAttacksCallback(board, flags, kind, rf, ff, rt, ft, closure) + Board board; + int flags; + ChessMove kind; + int rf, ff, rt, ft; + VOIDSTAR closure; +{ // for removing pre-exsting captures from the chaseStack, to be left with newly created ones + int i; + register ChaseClosure *cl = (ChaseClosure *) closure; //closure tells us the move played in the repeat loop + + if(board[rt][ft] == EmptySquare) return; // no capture + if(rf == cl->rf && ff == cl->ff) { // attacks with same piece from new position are not considered new + rf = cl->rt; ff = cl->ft; // doctor their fromSquare so they will be recognized in chaseStack + } + // search move in chaseStack, and delete it if it occurred there (as we know now it is not a new capture) + for(i=0; irt && ft == cl->ft) cl->recaptures++; // count legal recaptures to this square + if(appData.debugMode && board[rt][ft] != EmptySquare) + fprintf(debugFP, "try %c%c%c%c=%d\n", ff+AAA, rf+ONE,ft+AAA, rt+ONE, cl->recaptures); +} + +extern char moveList[MAX_MOVES][MOVE_LEN]; + +int PerpetualChase(int first, int last) +{ // this routine detects if the side to move in the 'first' position is perpetually chasing (when not checking) + int i, j, k, tail; + ChaseClosure cl; + ChessSquare captured; + + preyStackPointer = 0; // clear stack of chased pieces + for(i=first; i= (int) BlackPawn) attacker = BLACK_TO_WHITE attacker; // convert to white, as piecee type + if(victim >= (int) BlackPawn) victim = BLACK_TO_WHITE victim; + + if((attacker == WhiteKnight || attacker == WhiteCannon) && victim == WhiteRook) + continue; // C or H attack on R is always chase; leave on chaseStack + + if(attacker == victim) { + if(LegalityTest(boards[i+1], PosFlags(i+1), EP_NONE, initialRights, chaseStack[j].rt, + chaseStack[j].ft, chaseStack[j].rf, chaseStack[j].ff, NULLCHAR) == NormalMove) { + // we can capture back with equal piece, so this is no chase but a sacrifice + chaseStack[j] = chaseStack[--chaseStackPointer]; // delete the capture from the chaseStack + j--; /* ! */ continue; + } + + } + // the attack is on a lower piece, or on a pinned or blocked equal one + // test if the victim is protected by a true protector. First make the capture. + captured = boards[i+1][chaseStack[j].rt][chaseStack[j].ft]; + boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = boards[i+1][chaseStack[j].rf][chaseStack[j].ff]; + boards[i+1][chaseStack[j].rf][chaseStack[j].ff] = EmptySquare; + // Then test if the opponent can recapture + cl.recaptures = 0; // prepare closure to pass recapture square and count moves to it + cl.rt = chaseStack[j].rt; + cl.ft = chaseStack[j].ft; + if(appData.debugMode) { + fprintf(debugFP, "test if we can recapture %c%c\n", cl.ft+AAA, cl.rt+ONE); + } + GenLegal(boards[i+1], PosFlags(i+1), EP_NONE, initialRights, ProtectedCallback, &cl); // try all moves + // unmake the capture + boards[i+1][chaseStack[j].rf][chaseStack[j].ff] = boards[i+1][chaseStack[j].rt][chaseStack[j].ft]; + boards[i+1][chaseStack[j].rt][chaseStack[j].ft] = captured; + // if a recapture was found, piece is protected, and we are not chasing it. + if(cl.recaptures) { // attacked piece was defended by true protector, no chase + chaseStack[j] = chaseStack[--chaseStackPointer]; // so delete from chaseStack + j--; /* ! */ + } + } + // chaseStack now contains all moves that chased + if(appData.debugMode) { int n; + for(n=0; n