#define promoGain (rawGain + 1)
int pvStack[MAXPLY*MAXPLY/2];
-int nrRanks, nrFiles, specials, pinCodes, maxDrop, moveSP, pawn, *pvPtr = pvStack, boardEnd, searchNr;
+int nrRanks, nrFiles, specials, pinCodes, maxDrop, moveSP, pawn, lanceMask, *pvPtr = pvStack, boardEnd, perpLoses, searchNr;
int rawInts[21*22], pieceValues[96], pieceCode[96];
signed char rawChar[32*22], steps[512];
unsigned char rawByte[91*22], firstDir[64], rawBulk[98], handSlot[97], promoCode[96], aVal[64], vVal[64], rawLocation[96+23];
// promotion codes for unpromoted pieces. Will be ANDed with Z_WHITE or Z_BLACK to fill promoCode[] table
-#define Z_FIDE 1 /* piece has promotion choice */
+#define Z_LAST 1 /* first or last rank */
#define Z_2ND 0x66 /* must promote on last 2 ranks */
#define Z_MUST 0x78 /* must promote in entire zone */
#define Z_WHITE 0x2B /* bits applying to white zone */
#define Z_BLACK 0x55 /* bits applying to black zone */
-#define Z_LAST 0x80 /* ???? */
#define Z_DOUBLE 0x80 /* where Pawns have double step */
-chessProms[16] = { Z_FIDE|Z_MUST },
+chessProms[16] = { Z_MUST },
shogiProms[16] = { Z_MUST, Z_2ND, COLOR, 0, Z_MUST, Z_MUST, Z_2ND },
toriProms[16] = { Z_MUST, 0, 0, 0, 0, Z_MUST },
waProms[16] = { Z_MUST, Z_2ND, Z_MUST, Z_MUST, Z_MUST, COLOR, COLOR, Z_MUST, Z_MUST, Z_MUST, COLOR, Z_MUST, COLOR, Z_MUST };
+int lances[] = { 1, 3, 0103, 0103, 3, 1, 1 }; // bitmap indicating piece types with drop restriction (LSB = Pawn) in various variants
+
char *betza[] = { // piece defs for sending to GUI
NULL, // suppresses setup command
"",
moves = variants[v].dirs;
startPos= variants[v].fen;
codes = variants[v].proms;
+ lanceMask = lances[v];
+ perpLoses = v; // this works for now, as only zh allows perpetuals
if((p = betza[v])) { // configure GUI for this variant
printf("setup (%s) %dx%d+%d_%s %s 0 1", ptc[v], nrFiles, nrRanks, maxDrop+1, (v == 4 ? "chu" : "shogi"), startPos);
}
if(promote & stm) { // promotion is (also?) possible
moveStack[--m->firstMove] = (move | from << 8 | to + 11) + (vVal[victim-WHITE] + 20 << 24); // put it amongst captures
- if(promoCode[piece-WHITE] & Z_FIDE) { // only for FIDE Pawns
- moveStack[--m->firstMove] = move | from << 8 | to - 11 + (stm >> 6)*44; // under-promotion
+ if(!perpLoses) { // only for FIDE Pawns
+ moveStack[--m->firstMove] = move | from << 8 | to - 11 + (stm >> 6)*44; // turn previously-generated deferral into under-promotion
// other under-promotions could go here (Capahouse?)
}
}
void
CheckDrops (int stm, int king)
{
- int i;
- stm ^= COLOR;
- for(i=maxDrop; i>=0; i--) {
- int piece = stm + i, from = handSlot[piece];
+ int i, lowest = 0;
+ if(perpLoses) lowest = !!(pawnCount[sqr2file[king]] & maxBulk[stm]); // in Shogi no Pawn if file already crowded with those
+ else lowest = (stm == WHITE ? king < 2*22 : king >= 6*22); // in zh no Pawn from back rank
+ for(i=maxDrop; i>=lowest; i--) {
+ int piece = stm + i, from = handSlot[piece^COLOR];
if((signed char)board[from] < -1) { // piece type is in hand
int step, dir = 2*firstDir[piece-WHITE];
while((step = steps[dir++])) {
int to = king, range = steps[dir++];
- if((range & 3) == 2) break; // non-capture direction
+ if((range & 3) == 2) continue; // non-capture direction
while(board[to-=step] == 0) {
moveStack[moveSP++] = to | from << 8;
- if((range -= 8) <= 0) break;
+ if((range -= 8) <= 0) { if(i == 0 && (to < 22 || to >= boardEnd-22)) moveSP--; break; }
}
}
}
void
EvasionDrops (int stm, StackFrame *f)
{
- int i, x = f->checker, v = f->checkDir;
- stm ^= COLOR;
+ int i, x = f->checker, v = f->checkDir, s = stm ^ COLOR;
while(board[x+=v] == 0) { // all squares on check ray
- i = (x < 22 || x >= 7*22); // not on last rang. *** WRONG FOR SHOGI ***
- for(i=0; i<=maxDrop; i++) { // all droppable types
- int piece = stm + i, from = handSlot[piece];
+ int last = maxDrop;
+ i = zoneTab[x] & Z_LAST; // Pawn not on first & last rank (OK for zh)
+ if(perpLoses) { // but it is Shogi!
+ if(!(zoneTab[x] & stm)) i = 0; // outside zone, so dropping is always allowed
+ else if(perpLoses < 5) { // Shogi variant with Lance
+ i *= 2; // no Pawn, then also no Lance!
+ last += 1 - (zoneTab[x] & (Z_2ND & ~COLOR)) + (perpLoses & 4) >> 3; // on last 2 ranks trim off Knight (not in Wa)
+ }
+ if(pawnCount[sqr2file[x]] & maxBulk[stm]) i += !i; // no Pawn in pawn-crowded file
+ }
+ for(; i<=last; i++) { // all droppable types
+ int piece = s + i, from = handSlot[piece];
if((signed char)board[from] < -1) // piece type is in hand
moveStack[moveSP++] = from << 8 | x;
}
void
AllDrops (int stm)
{
- int i, start = 22, end = boardEnd-22;
- stm ^= COLOR;
+ int i, mask = lanceMask;
for(i=0; i<=maxDrop; i++) {
- int piece = stm + i, from = handSlot[piece];
+ int piece = stm + i, from = handSlot[piece^COLOR];
if((signed char)board[from] < -1) { // piece type is in hand
- int r, f;
- for(r=start; r<end; r+=22) for(f=0; f<nrFiles; f++)
- if(board[r+f] == 0) moveStack[moveSP++] = from << 8 | f + r;
+ int r, f, start = 0, end = boardEnd;
+ if(mask & 1) { // piece with drop limitation
+ int badZone = (i == 6 ? 44 : 22); // 6 is the Knight in (Judkins) Shogi
+ if(stm == BLACK || !perpLoses) start = badZone;
+ if(stm == WHITE || !perpLoses) end -= badZone;
+ }
+ for(f=0; f<nrFiles; f++) {
+ if(i == 0 && pawnCount[f] & maxBulk[stm]) continue;
+ for(r=start; r<end; r+=22)
+ if(board[r+f] == 0) moveStack[moveSP++] = from << 8 | f + r;
+ }
}
- start = 0; end = boardEnd;
+ mask >>= 1;
}
}
void
CheckTest (int stm, StackFrame *ff, StackFrame *f)
{
- if(ff->mutation == -2) f.checker = CK_NONE, f.checkDist = 0; else { // null move never checks
+ if(ff->mutation == -2) f->checker = CK_NONE, f->checkDist = 0; else { // null move never checks
int king = location[stm+31]; // own King
int vec = king - ff->toSqr;
int match = captCode[vec] & pieceCode[ff->toPiece];
to = toDecode[to];
if(inc > 0) promo = pieceID[inc - 16]; // move is promotion
else if(castle) to = 2*to - from; // move is castling, and 'to' indicates Rook; calculate King to-square
- if(promo == '+' && promoCode[WHITE] & Z_FIDE) promo = 'q';
+ if(promo == '+' && !perpLoses) promo = 'q';
if(from%22 > 10) sprintf(buf, "%c@%c%d", pieces[dropType[from]-1&~COLOR], 'a'+(to%22), 1+(to/22)); // move is drop
else sprintf(buf, "%c%d%c%d%c", 'a'+(from%22), 1+(from/22), 'a'+(to%22), 1+(to/22), promo);
return buf;
case 'n': m += in; break;
case 'b': m += 2*in; break;
case 'r': m += 3*in; break;
+ case '=': m -= 11; break; // no promotion after all
}
} else if(board[from] == stm + 31 && (f - f2 > 1 || f2 - f > 1)) { // castling
m = 22*8+10 + (f > f2 ? 0 : 11) + 22*(r2 == 7) + (from << 8);