Implement kifu move disambiguation
[xboard.git] / moves.c
diff --git a/moves.c b/moves.c
index dbd0526..75772a4 100644 (file)
--- a/moves.c
+++ b/moves.c
@@ -1823,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)   ||
@@ -1834,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;
@@ -1842,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;
@@ -1972,6 +1973,7 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
 {
     register DisambiguateClosure *cl = (DisambiguateClosure *) closure;
     int wildCard = FALSE; ChessSquare piece = board[rf][ff];
+    extern int kifu; // in parser.c
 
     // [HGM] wild: for wild-card pieces rt and rf are dummies
     if(piece == WhiteFalcon || piece == BlackFalcon ||
@@ -1989,6 +1991,18 @@ DisambiguateCallback (Board board, int flags, ChessMove kind, int rf, int ff, in
 
        if(cl->count && rf == cl->rf && ff == cl->ff) return; // duplicate move
 
+       if(cl->count == 1 && kifu & 0x7E && cl->rfIn == -1 && cl->ffIn == -1) { // traditional Shogi disambiguation required
+           int this = 1, other = 1;
+           if(kifu & 2) this &= (flags & 1 ? rt > rf : rt < rf), other &= (flags & 1 ? cl->rt > cl->rf : cl->rt < cl->rf);
+           if(kifu & 4) this &= (flags & 1 ? rt < rf : rt > rf), other &= (flags & 1 ? cl->rt < cl->rf : cl->rt > cl->rf);
+           if(kifu & 8) this &= (rf == rt), other &= (cl->rt == cl->rf);
+           if(kifu & 0x10) this &= (flags & 1 ? ft <= ff : ft >= ff), other &= (flags & 1 ? cl->ft <= cl->ff : cl->ft >= cl->ff);
+           if(kifu & 0x20) this &= (flags & 1 ? ft >= ff : ft <= ff), other &= (flags & 1 ? cl->ft >= cl->ff : cl->ft <= cl->ff);
+           if(kifu & 0x40) this &= (ft == ff), other &= (cl->ft == cl->ff); // should never be used
+           if(!other) cl->count--; // the old move did not satisfy the requested relative position, erase it
+           if(!this) return;       // the current move does not satisfy the requested relative position, ignore it
+       }
+
        cl->count++;
        if(cl->count == 1 || board[rt][ft] != EmptySquare) {
          // [HGM] oneclick: if multiple moves, be sure we remember capture
@@ -2030,7 +2044,7 @@ Disambiguate (Board board, int flags, DisambiguateClosure *closure)
         GenLegal(board, flags|F_IGNORE_CHECK, DisambiguateCallback, (VOIDSTAR) closure, closure->pieceIn);
        if (closure->count == 0) {
            /* No, it's not even that */
-         if(!appData.testLegality && closure->pieceIn != EmptySquare) {
+         if(!appData.testLegality && !pieceDefs && closure->pieceIn != EmptySquare) {
            int f, r; // if there is only a single piece of the requested type on the board, use that
            closure->rt = closure->rtIn, closure->ft = closure->ftIn;
            for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++)
@@ -2079,6 +2093,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) )
@@ -2086,7 +2101,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;
@@ -2094,7 +2109,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;