X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=moves.c;h=88bbdee9706d05cc9d2445c21cb83f78064d811e;hb=17d5e197ff197599a155a56cf2adaca266774a48;hp=bc5f4155a213ac85c77688a4dbae83d206bab3b2;hpb=2752f61000352bfaa57ff1c23045ee79e8054975;p=xboard.git diff --git a/moves.c b/moves.c index bc5f415..88bbdee 100644 --- a/moves.c +++ b/moves.c @@ -235,7 +235,8 @@ char symmetry[] = "FBNW.FFW.NKN.NW.QR....W..N"; char xStep[] = "2110.130.102.10.00....0..2"; char yStep[] = "2132.133.313.20.11....1..3"; char dirType[] = "01000104000200000260050000"; -char upgrade[] = "AKCD.QGH.JQL.NO.KK....Q..Z"; +char upgrade[] = "AFCD.BGH.JQL.NO.KW....R..Z"; +char rotate[] = "DRCA.WHG.JKL.NO.QB....F..Z"; // alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z " int dirs1[] = { 0,0x3C,0,0,0,0xC3,0,0, 0,0,0,0xF0,0,0,0,0,0,0x0F,0 ,0,0,0 ,0,0,0,0 }; @@ -263,11 +264,15 @@ OK (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VOID void MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle, char *desc, MoveCallback cb, VOIDSTAR cl) { - char buf[80], *p = desc; - int mine, his, dir, bit, occup, i; + char buf[80], *p = desc, *atom = NULL; + int mine, his, dir, bit, occup, i, ep, promoRank = -1; + ChessMove promo= NormalMove; ChessSquare pc = board[r][f]; + if(pc == DarkSquare) return; // this is not a piece, but a 'hole' in the board if(flags & F_WHITE_ON_MOVE) his = 2, mine = 1; else his = 1, mine = 2; + if(pc == WhitePawn || pc == WhiteLance) promo = WhitePromotion, promoRank = BOARD_HEIGHT-1; else + if(pc == BlackPawn || pc == BlackLance) promo = BlackPromotion, promoRank = 0; while(*p) { // more moves to go - int expo = 1, dx, dy, x, y, mode, dirSet, ds2, retry=0, initial=0, jump=1, skip = 0; + int expo = 1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0; char *cont = NULL; if(*p == 'i') initial = 1, desc = ++p; while(islower(*p)) p++; // skip prefixes @@ -277,9 +282,9 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle dirSet = 0; // build direction set based on atom symmetry switch(symmetry[*p-'A']) { case 'B': expo = 0; // bishop, slide - case 'F': // diagonal atom (degenerate 4-fold) - if(tx < 0) { // for continuation legs relative directions are orthogonal! - while(islower(*desc) && (i = dirType[*desc-'a']) != '0') { + case 'F': all = 0xAA; // diagonal atom (degenerate 4-fold) + if(tx >= 0) goto king; // continuation legs specified in K/Q system! + while(islower(*desc) && (i = dirType[*desc-'a']) != '0') { int b = dirs1[*desc-'a']; // use wide version if( islower(desc[1]) && ((i | dirType[desc[1]-'a']) & 3) == 3) { // combinable (perpendicular dim) @@ -287,19 +292,22 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle desc += 2; } else desc++; dirSet |= b; - } - dirSet &= 0xAA; if(!dirSet) dirSet = 0xAA; - break; } + dirSet &= 0xAA; if(!dirSet) dirSet = 0xAA; + break; case 'R': expo = 0; // rook, slide - case 'W': // orthogonal atom (non-deg 4-fold) + case 'W': all = 0x55; // orthogonal atom (non-deg 4-fold) + if(tx >= 0) goto king; // continuation legs specified in K/Q system! while(islower(*desc) && (dirType[*desc-'a'] & ~4) != '0') dirSet |= dirs2[*desc++-'a']; dirSet &= 0x55; if(!dirSet) dirSet = 0x55; dirSet = (dirSet << angle | dirSet >> 8-angle) & 255; // re-orient direction system break; - case 'N': // oblique atom (degenerate 8-fold) - if(tx < 0) { // for continuation legs relative directions are non-degenerate! - while(islower(*desc) && (i = dirType[*desc-'a']) != '0') { + case 'N': all = 0xFF; // oblique atom (degenerate 8-fold) + if(tx >= 0) goto king; // continuation legs specified in K/Q system! + if(*desc == 'h') { // chiral direction sets 'hr' and 'hl' + dirSet = (desc[1] == 'r' ? 0x55 : 0xAA); desc += 2; + } else + while(islower(*desc) && (i = dirType[*desc-'a']) != '0') { int b = dirs2[*desc-'a']; // when alone, use narrow version if(desc[1] == 'h') b = dirs1[*desc-'a'], desc += 2; // dirs1 is wide version else if(*desc == desc[1] || islower(desc[1]) && i < '4' @@ -308,12 +316,12 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle desc += 2; } else desc++; dirSet |= b; - } - if(!dirSet) dirSet = 0xFF; - break; } + if(!dirSet) dirSet = 0xFF; + break; case 'Q': expo = 0; // queen, slide - case 'K': // non-deg (pseudo) 8-fold + case 'K': all = 0xFF; // non-deg (pseudo) 8-fold + king: while(islower(*desc) && (i = dirType[*desc-'a']) != '0') { int b = dirs4[*desc-'a']; // when alone, use narrow version if(desc[1] == *desc) desc++; // doubling forces alone @@ -324,12 +332,13 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle } else desc++; dirSet |= b; } - if(!dirSet) dirSet = 0xFF; + if(!dirSet) dirSet = (tx < 0 ? 0xFF // default is all directions, but in continuation leg + : all == 0xFF ? 0xEF : 0x45); // omits backward, and for 4-fold atoms also diags dirSet = (dirSet << angle | dirSet >> 8-angle) & 255; // re-orient direction system ds2 = dirSet & 0xAA; // extract diagonal directions if(dirSet &= 0x55) // start with orthogonal moves, if present - retry = 1; // and schedule the diagonal moves for later - else dx = 1, dirSet = ds2; // if no orthogonal directions, do diagonal immediately + retry = 1, dx = 0; // and schedule the diagonal moves for later + else dx = dy, dirSet = ds2; // if no orthogonal directions, do diagonal immediately break; // should not have direction indicators default: return; // syntax error: invalid atom } @@ -357,27 +366,26 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle mode |= 1024; dy = 1; } if(!cont) { - if(!(mode & 15)) mode = his + 4; // no mode spec, use default = mc + if(!(mode & 15)) mode |= his + 4; // no mode spec, use default = mc } else { + strncpy(buf, cont, 80); cont = buf; // copy next leg(s), so we can modify + atom = buf; while(islower(*atom)) atom++; // skip to atom if(mode & 32) mode ^= 256 + 32; // in non-final legs 'p' means 'pass through' if(mode & 64 + 512) { mode |= 256; // and 'g' too, but converts leaper <-> slider if(mode & 512) mode ^= 0x304; // and 'y' is m-like 'g' - strncpy(buf, cont, 80); cont = buf; // copy next leg(s), so we can modify - while(islower(*cont)) cont++; // skip to atom - *cont = upgrade[*cont-'A']; // replace atom, BRQ <-> FWK - if(expo == 1) *++cont = '0'; // turn other leapers into riders - *++cont = '\0'; // make sure any old range is stripped off - cont = buf; // use modified string for continuation leg + *atom = upgrade[*atom-'A']; // replace atom, BRQ <-> FWK + atom[1] = atom[2] = '\0'; // make sure any old range is stripped off + if(expo == 1) atom[1] = '0'; // turn other leapers into riders } - if(!(mode & 0x30F)) mode = his + 0x104; // and default = mcp + if(!(mode & 0x30F)) mode |= 4; // and default of this leg = m } if(dy == 1) skip = jump - 1, jump = 1; // on W & F atoms 'j' = skip first square do { for(dir=0, bit=1; dir<8; dir++, bit += bit) { // loop over directions - int i = expo, j = skip, hop = mode, vx, vy; + int i = expo, j = skip, hop = mode, vx, vy, loop = 0; if(!(bit & dirSet)) continue; // does not move in this direction - if(dy != 1) j = 0; // + if(dy != 1 || mode & 1024) j = 0; // vx = dx*rot[dir][0] + dy*rot[dir][1]; // rotate step vector vy = dx*rot[dir][2] + dy*rot[dir][3]; if(tx < 0) x = f, y = r; // start square @@ -385,18 +393,21 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle do { // traverse ray x += vx; y += vy; // step to next square if(y < 0 || y >= BOARD_HEIGHT) break; // vertically off-board: always done - if(x < BOARD_LEFT) { if(mode & 128) x += BOARD_RGHT - BOARD_LEFT; else break; } - if(x >= BOARD_RGHT) { if(mode & 128) x -= BOARD_RGHT - BOARD_LEFT; else break; } + if(x < BOARD_LEFT) { if(mode & 128) x += BOARD_RGHT - BOARD_LEFT, loop++; else break; } + if(x >= BOARD_RGHT) { if(mode & 128) x -= BOARD_RGHT - BOARD_LEFT, loop++; else break; } + if(board[y][x] == DarkSquare) break; // black squares are supposed to be off board if(j) { j--; continue; } // skip irrespective of occupation if(!jump && board[y - vy + vy/2][x - vx + vx/2] != EmptySquare) break; // blocked if(jump > 1 && board[y - vy + vy/2][x - vx + vx/2] == EmptySquare) break; // no hop - if(x == f && y == r) occup = 4; else // start square counts as empty + if(x == f && y == r && !loop) occup = 4; else // start square counts as empty (if not around cylinder!) if(board[y][x] < BlackPawn) occup = 0x101; else if(board[y][x] < EmptySquare) occup = 0x102; else occup = 4; if(cont) { // non-final leg if(mode&16 && his&occup) occup &= 3;// suppress hopping foe in t-mode if(occup & mode) { // valid intermediate square, do continuation + char origAtom = *atom; + if(!(bit & all)) *atom = rotate[*atom - 'A']; // orth-diag interconversion to make direction valid if(occup & mode & 0x104) // no side effects, merge legs to one move MovesFromString(board, flags, f, r, x, y, dir, cont, cb, cl); if(occup & mode & 3 && (killX < 0 || killX == x && killY == y)) { // destructive first leg @@ -409,28 +420,43 @@ MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle legNr >>= 1; } } + *atom = origAtom; // undo any interconversion } if(occup != 4) break; // occupied squares always terminate the leg continue; } if(hop & 32+64) { if(occup != 4) { if(hop & 64 && i != 1) i = 2; hop &= 31; } continue; } // hopper - if(mode & 8 && y == board[EP_RANK] && occup == 4 && board[EP_FILE] == x) { // to e.p. square + ep = board[EP_RANK]; + if(mode & 8 && occup == 4 && board[EP_FILE] == x && (y == (ep & 127) || y - vy == ep - 128)) { // to e.p. square (or 2nd e.p. square) cb(board, flags, mine == 1 ? WhiteCapturesEnPassant : BlackCapturesEnPassant, r, f, y, x, cl); } if(mode & 1024) { // castling i = 2; // kludge to elongate move indefinitely if(occup == 4) continue; // skip empty squares - if(x == BOARD_LEFT && board[y][x] == initialPosition[y][x]) // reached initial corner piece + if((x == BOARD_LEFT + skip || x > BOARD_LEFT + skip && vx < 0 && board[y][x-1-skip] == DarkSquare) + && board[y][x] == initialPosition[y][x]) { // reached initial corner piece + if(pc != WhiteKing && pc != BlackKing) { // non-royal castling (to be entered as two-leg move via 'Rook') + if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX < f) + legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f - expo, cl), legNr >>= 1; + } else cb(board, flags, mine == 1 ? WhiteQueenSideCastle : BlackQueenSideCastle, r, f, y, f - expo, cl); - if(x == BOARD_RGHT-1 && board[y][x] == initialPosition[y][x]) + } + if((x == BOARD_RGHT-1-skip || x < BOARD_RGHT-1-skip && vx > 0 && board[y][x+1+skip] == DarkSquare) + && board[y][x] == initialPosition[y][x]) { + if(pc != WhiteKing && pc != BlackKing) { + if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX > f) + legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f + expo, cl), legNr >>= 1; + } else cb(board, flags, mine == 1 ? WhiteKingSideCastle : BlackKingSideCastle, r, f, y, f + expo, cl); + } break; } - if(occup & mode) cb(board, flags, NormalMove, r, f, y, x, cl); // allowed, generate + if(mode & 16 && (board[y][x] == WhiteKing || board[y][x] == BlackKing)) break; // tame piece, cannot capture royal + if(occup & mode) cb(board, flags, y == promoRank ? promo : NormalMove, r, f, y, x, cl); // allowed, generate if(occup != 4) break; // not valid transit square } while(--i); } - dx = dy = 1; dirSet = ds2; // prepare for diagonal moves of K,Q + dx = dy; dirSet = ds2; // prepare for diagonal moves of K,Q } while(retry-- && ds2); // and start doing them if(tx >= 0) break; // don't do other atoms in continuation legs } @@ -1602,14 +1628,16 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant CheckTestClosure cl; ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing; ChessSquare captured = EmptySquare, ep=0, trampled=0; + int saveKill = killX; /* Suppress warnings on uninitialized variables */ if(gameInfo.variant == VariantXiangqi) king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir; if(gameInfo.variant == VariantKnightmate) king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn; - if(gameInfo.variant == VariantChu) { // strictly speaking this is not needed, as Chu officially has no check + if(gameInfo.variant == VariantChu || gameInfo.variant == VariantShogi) { // strictly speaking this is not needed, as Chu officially has no check int r, f, k = king, royals=0, prince = flags & F_WHITE_ON_MOVE ? WhiteMonarch : BlackMonarch; + if(gameInfo.variant == VariantShogi) prince -= 11; // White/BlackFalcon for(r=0; r 1) return FALSE; // no check if we have two royals (ignores double captureby Lion!) @@ -1624,7 +1652,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[rf][ft] = EmptySquare; } else { captured = board[rt][ft]; - if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; } + if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; killX = -1; } } if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop board[rt][ft] = board[rf][ff]; @@ -1672,7 +1700,7 @@ CheckTest (Board board, int flags, int rf, int ff, int rt, int ft, int enPassant board[rf][ft] = captured; board[rt][ft] = EmptySquare; } else { - if(killX >= 0) board[killY][killX] = trampled; + if(saveKill >= 0) board[killY][killX = saveKill] = trampled; board[rt][ft] = captured; } board[EP_STATUS] = ep; @@ -1795,6 +1823,7 @@ LegalityTest (Board board, int flags, int rf, int ff, int rt, int ft, int promoC /* [HGM] Shogi promotions. '=' means defer */ if(rf != DROP_RANK && cl.kind == NormalMove) { ChessSquare piece = board[rf][ff]; + int zone = BOARD_HEIGHT/3 + (BOARD_HEIGHT == 8); if(promoChar == PieceToChar(BlackQueen)) promoChar = NULLCHAR; /* [HGM] Kludge */ if(promoChar == 'd' && (piece == WhiteRook || piece == BlackRook) || @@ -1806,7 +1835,7 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove; else if(flags & F_WHITE_ON_MOVE) { if( (int) piece < (int) WhiteWazir && - (rf >= BOARD_HEIGHT - BOARD_HEIGHT/3 || rt >= BOARD_HEIGHT - BOARD_HEIGHT/3) ) { + (rf >= BOARD_HEIGHT - zone || rt >= BOARD_HEIGHT - zone) ) { if( (piece == WhitePawn || piece == WhiteQueen) && rt > BOARD_HEIGHT-2 || piece == WhiteKnight && rt > BOARD_HEIGHT-3) /* promotion mandatory */ cl.kind = promoChar == '=' ? IllegalMove : WhitePromotion; @@ -1814,7 +1843,7 @@ if(appData.debugMode)fprintf(debugFP,"SHOGI promoChar = %c\n", promoChar ? promo cl.kind = promoChar == '+' ? WhitePromotion : WhiteNonPromotion; } else cl.kind = promoChar == '+' ? IllegalMove : NormalMove; } else { - if( (int) piece < (int) BlackWazir && (rf < BOARD_HEIGHT/3 || rt < BOARD_HEIGHT/3) ) { + if( (int) piece < (int) BlackWazir && (rf < zone || rt < zone) ) { if( (piece == BlackPawn || piece == BlackQueen) && rt < 1 || piece == BlackKnight && rt < 2 ) /* promotion obligatory */ cl.kind = promoChar == '=' ? IllegalMove : BlackPromotion; @@ -2051,6 +2080,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) /* [HGM] Shogi promotions. On input, '=' means defer, '+' promote. Afterwards, c is set to '+' for promotions, NULL other */ if(closure->rfIn != DROP_RANK && closure->kind == NormalMove) { ChessSquare piece = closure->piece; + int zone = BOARD_HEIGHT/3 + (BOARD_HEIGHT == 8); if (c == 'd' && (piece == WhiteRook || piece == BlackRook) || c == 'h' && (piece == WhiteBishop || piece == BlackBishop) || c == 'g' && (piece <= WhiteFerz || piece <= BlackFerz && piece >= BlackPawn) ) @@ -2058,7 +2088,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) if(c != NULLCHAR && c != '+' && c != '=') closure->kind = IllegalMove; // otherwise specifying a piece is illegal else if(flags & F_WHITE_ON_MOVE) { if( (int) piece < (int) WhiteWazir && - (closure->rf >= BOARD_HEIGHT-(BOARD_HEIGHT/3) || closure->rt >= BOARD_HEIGHT-(BOARD_HEIGHT/3)) ) { + (closure->rf >= BOARD_HEIGHT-zone || closure->rt >= BOARD_HEIGHT-zone) ) { if( (piece == WhitePawn || piece == WhiteQueen) && closure->rt > BOARD_HEIGHT-2 || piece == WhiteKnight && closure->rt > BOARD_HEIGHT-3) /* promotion mandatory */ closure->kind = c == '=' ? IllegalMove : WhitePromotion; @@ -2066,7 +2096,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure) closure->kind = c == '+' ? WhitePromotion : WhiteNonPromotion; } else closure->kind = c == '+' ? IllegalMove : NormalMove; } else { - if( (int) piece < (int) BlackWazir && (closure->rf < BOARD_HEIGHT/3 || closure->rt < BOARD_HEIGHT/3) ) { + if( (int) piece < (int) BlackWazir && (closure->rf < zone || closure->rt < zone) ) { if( (piece == BlackPawn || piece == BlackQueen) && closure->rt < 1 || piece == BlackKnight && closure->rt < 2 ) /* promotion obligatory */ closure->kind = c == '=' ? IllegalMove : BlackPromotion;