Generalize FEN e.p. field to handle diagonal and triple pushes
authorH.G.Muller <hgm@hgm-xboard.(none)>
Tue, 6 Dec 2016 16:19:00 +0000 (17:19 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Fri, 13 Jan 2017 15:39:25 +0000 (16:39 +0100)
In Berolina Chess a single square canot unambiguously indicate which
e.p. capture ispossible, as two initial double-pushes could cross over
the same square (and a 4th-rank Pawn could have come from two 2nd-rank
locations). So both the skipped square and the location of the corresponding
e.p.victim have to be mentioned in the e.p. field of a FEN. This is now
supported (in variant Berolina) on both reading and writing.
  In addition, the test for when an e.p. field has to be added is improved.
It was still using hard-coded rank numbers, only acting on 2->4 and 7->5
Pawn moves that stayed on the same file. Now it works on any advance of
more than one rank. For pushes of more than one rank the e.p. square is
biased towards the from-square. This makes it possible to distinguish
between a triple and a double-push that end on the same rank.

backend.c

index 57c06b9..baead2f 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -18445,13 +18445,15 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts)
         fromY = moveList[move - 1][1] - ONE;
         toX = moveList[move - 1][2] - AAA;
         toY = moveList[move - 1][3] - ONE;
-       if (fromY == (whiteToPlay ? BOARD_HEIGHT-2 : 1) &&
-           toY == (whiteToPlay ? BOARD_HEIGHT-4 : 3) &&
-           boards[move][toY][toX] == (whiteToPlay ? BlackPawn : WhitePawn) &&
-           fromX == toX) {
+       if ((whiteToPlay ? toY < fromY - 1 : toY > fromY + 1) &&
+           boards[move][toY][toX] == (whiteToPlay ? BlackPawn : WhitePawn) ) {
            /* 2-square pawn move just happened */
-            *p++ = toX + AAA;
-           *p++ = whiteToPlay ? '6'+BOARD_HEIGHT-8 : '3';
+            *p++ = (3*toX + 5*fromX + 4)/8 + AAA;
+           *p++ = (3*toY + 5*fromY + 4)/8 + ONE;
+           if(gameInfo.variant == VariantBerolina) {
+               *p++ = toX + AAA;
+               *p++ = toY + ONE;
+           }
        } else {
            *p++ = '-';
        }
@@ -18828,11 +18830,22 @@ ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
       if(*p=='-') {
         p++; board[EP_STATUS] = EP_NONE;
       } else {
-         char c = *p++ - AAA;
-
-         if(c < BOARD_LEFT || c >= BOARD_RGHT) return TRUE;
-         if(*p >= '0' && *p <='9') p++;
-         board[EP_STATUS] = c;
+         int d, r, c = *p - AAA;
+
+         if(c >= BOARD_LEFT && c < BOARD_RGHT) {
+             p++;
+             board[EP_STATUS] = board[EP_FILE] = c; r = 0;
+             if(*p >= '0' && *p <='9') r = board[EP_RANK] = *p++ - ONE;
+             d = (r < BOARD_HEIGHT << 1 ? 1 : -1); // assume double-push (P next to e.p. square nearer center)
+             if(board[r+d][c] == EmptySquare) d *= 2; // but if no Pawn there, triple push
+             board[LAST_TO] = 256*(r + d) + c;
+             c = *p++ - AAA;
+             if(c >= BOARD_LEFT && c < BOARD_RGHT) { // mover explicitly mentioned
+                 if(*p >= '0' && *p <='9') r = board[EP_RANK] = *p++ - ONE;
+                 board[LAST_TO] = 256*r + c;
+                 if(!(board[EP_RANK]-r & 1)) board[EP_RANK] |= 128;
+             }
+         }
       }
     }