// promotions by pieces with Lion power stepping in & out the zone in same turn\r
// promotion on capture\r
\r
-#define VERSION "0.18"\r
+#define VERSION "0.20"\r
\r
-//define PATH level==0 || path[0] == 0x1103a && (level==1 || path[1] == 0x6f0f6 && (level == 2 /*|| path[2] == 0x8710f && (level == 3 /*|| path[3] == 0x3e865 && (level == 4 || path[4] == 0x4b865 && (level == 5)))*/))\r
+//define PATH level==0 || path[0] == 0x590cb && (level==1 || path[1] == 0x4c0c9 && (level == 2 || path[2] == 0x8598ca && (level == 3 /*|| path[3] == 0x3e865 && (level == 4 || path[4] == 0x4b865 && (level == 5))*/)))\r
#define PATH 0\r
\r
#define HASH\r
#define XWINGS\r
#define KINGSAFETY\r
#define KSHIELD\r
-#define XFORTRESS\r
+#define FORTRESS\r
#define PAWNBLOCK\r
+#define TANDEM 100 /* bonus for pairs of attacking light steppers */\r
#define KYLIN 100 /* extra end-game value of Kylin for promotability */\r
#define PROMO 0 /* extra bonus for 'vertical' piece when it actually promotes (diagonal pieces get half) */\r
\r
#define PROMOTE (1<<2*SQLEN+1) /* promotion bit in move */\r
#define SPECIAL 1400 /* start of special moves */\r
#define BURN (SPECIAL + 96) /* start of burn encodings */\r
+#define CASTLE (SPECIAL + 100) /* castling encodings */\r
#define STEP(X,Y) (BW*(X)+ (Y))\r
#define SORTKEY(X) 0\r
\r
#define PST_RETRACT (5*BW*BH+BH)\r
#define PST_WFLYER (6*BW*BH)\r
#define PST_BFLYER (6*BW*BH+BH)\r
-#define PST_END (7*BW*BH)\r
+#define PST_LANCE (7*BW*BH)\r
+#define PST_END (8*BW*BH)\r
\r
typedef unsigned int Move;\r
\r
void pmap(int *m, int col);\r
void pboard(int *b);\r
void pbytes(unsigned char *b);\r
+int myRandom();\r
\r
typedef struct {\r
int lock[5];\r
} PieceDesc;\r
\r
typedef struct {\r
- int from, to, piece, victim, new, booty, epSquare, epVictim[8], ep2Square, revMoveCount;\r
+ int from, to, piece, victim, new, booty, epSquare, epVictim[9], ep2Square, revMoveCount;\r
int savKeyL, savKeyH, gain, loss, filling, saveDelta;\r
char fireMask;\r
} UndoInfo;\r
int ll, lr, ul, ur; // corner squares\r
int nodes, startTime, lastRootMove, lastRootIter, tlim1, tlim2, tlim3, repCnt, comp, abortFlag;\r
Move ponderMove;\r
-Move retMove, moveStack[10000], path[100], repStack[300], pv[1000], repeatMove[300], killer[100][2];\r
+Move retMove, moveStack[20000], path[100], repStack[300], pv[1000], repeatMove[300], killer[100][2];\r
\r
int maxDepth; // used by search\r
\r
{ 2,-1}\r
};\r
\r
-int epList[96], ep2List[96], toList[96], reverse[96]; // decoding tables for double and triple moves\r
+int epList[104], ep2List[104], toList[104], reverse[104]; // decoding tables for double and triple moves\r
int kingStep[10], knightStep[10]; // raw tables for step vectors (indexed as -1 .. 8)\r
int neighbors[9]; // similar to kingStep, but starts with null-step\r
char fireFlags[10]; // flags for Fire-Demon presence (last two are dummies, which stay 0, for compactify)\r
int attackMaps[200*BSIZE], *attacks = attackMaps;\r
char distance[2*BSIZE]; // distance table\r
char promoBoard[BSIZE]; // flags to indicate promotion zones\r
-char rawFire[BSIZE+2*BWMAX]; // flags to indicate squares controlled by Fire Demons\r
+unsigned char rawFire[BSIZE+2*BWMAX]; // flags to indicate squares controlled by Fire Demons\r
signed char PST[7*BSIZE];\r
\r
#define board (rawBoard + 6*BHMAX + 3)\r
int\r
EasyProm (signed char *r)\r
{\r
- int i;\r
if(r[0] == X) return 30 + PROMO*((unsigned int)(r[1] | r[2] | r[3] | r[5] | r[6] | r[7]) <= 1);\r
if(r[1] == X || r[7] == X) return 30 + PROMO/2;\r
return 0;\r
int i, m=0;\r
for(i=0; i<8; i++) {\r
int d = r[i];\r
- if(r[i] < 0) d == r[i] >= L ? 2 : 36;\r
+ if(r[i] < 0) d = r[i] >= L ? 2 : 36;\r
if(d > m) m = d;\r
}\r
return m;\r
void\r
Compactify (int stm)\r
{ // remove pieces that are permanently gone (captured or promoted) from one side's piece list\r
- int i, j, k;\r
+ int i, k;\r
for(i=stm+2; i<=last[stm]; i+=2) { // first pass: unpromoted pieces\r
if((k = p[i].promo) >= 0 && p[i].pos == ABSENT) { // unpromoted piece no longer there\r
p[k].promo = -2; // orphan promoted version\r
p[i].bulk = list->bulk;\r
p[i].mobWeight = v > 600 ? 0 : v >= 400 ? 1 : v >= 300 ? 2 : v > 150 ? 3 : v >= 100 ? 2 : 0;\r
if(Lance(list->range))\r
- p[i].mobWeight = 5 + 3*(list->range[4]==X), p[i].pst = 0; // clear path but don't move forward\r
+ p[i].mobWeight = 0, p[i].pst = list->range[4] ? PST_NEUTRAL : PST_LANCE; // keep back\r
for(j=stm+2; j<= last[stm]; j+=2) {\r
if(p[j].promo >= i) p[j].promo += 2;\r
}\r
}\r
\r
void\r
-SetUp(char *array, int var)\r
+SetUp (char *array, int var)\r
{\r
- int i, j, n, m, nr, color;\r
- char c, *q, name[3], prince = 0;\r
+ int i, j, n, m, color;\r
+ char c, name[3], prince = 0;\r
PieceDesc *p1, *p2;\r
last[WHITE] = 1; last[BLACK] = 0;\r
+ royal[WHITE] = royal[BLACK] = 0;\r
for(i=0; ; i++) {\r
//printf("next rank: %s\n", array);\r
for(j = BW*i; ; j++) {\r
}\r
}\r
eos:\r
+ // add dummy Kings if not yet added (needed to set royal[] to valid value!)\r
+ if(!royal[WHITE]) p[AddPiece(WHITE, LookUp("K", V_CHU))].pos = ABSENT;\r
+ if(!royal[BLACK]) p[AddPiece(BLACK, LookUp("K", V_CHU))].pos = ABSENT;\r
// add dummy Crown Princes if not yet added\r
if(!(prince & WHITE+1)) p[AddPiece(WHITE, LookUp("CP", V_CHU))].pos = ABSENT;\r
if(!(prince & BLACK+1)) p[AddPiece(BLACK, LookUp("CP", V_CHU))].pos = ABSENT;\r
if(i == kylin[WHITE]) p[i].promoGain = 1.25*KYLIN, p[i].value += KYLIN;\r
// if(j > 0 && p[i].pst == PST_STEPPER) p[i].pst = PST_WPPROM; // use white pre-prom bonus\r
if(j > 0 && p[i].pst == PST_STEPPER && p[i].value >= 100)\r
- p[i].pst = p[i].value <= 150 ? PST_ADVANCE : PST_NEUTRAL; // light steppers advance\r
+ p[i].pst = p[i].value <= 150 ? PST_ADVANCE : PST_WPPROM; // light steppers advance\r
if(j > 0 && p[i].bulk == 6) p[i].pst = PST_WFLYER, p[i].mobWeight = 4; // SM defends zone\r
if((j = p[i].promo) > 0 && g)\r
- p[i].promoGain = (p[j].value - p[i].value - g)*1.25, p[i].value = p[j].value - g;\r
+ p[i].promoGain = (p[j].value - p[i].value - g)*0.9, p[i].value = p[j].value - g;\r
else p[i].promoGain = 0;\r
board[p[i].pos] = i;\r
rootEval += p[i].value + PST[p[i].pst + p[i].pos];\r
int g = p[i].promoGain;\r
// if(j > 0 && p[i].pst == PST_STEPPER) p[i].pst = PST_BPPROM; // use black pre-prom bonus\r
if(j > 0 && p[i].pst == PST_STEPPER && p[i].value >= 100)\r
- p[i].pst = p[i].value <= 150 ? PST_RETRACT : PST_NEUTRAL; // light steppers advance\r
+ p[i].pst = p[i].value <= 150 ? PST_RETRACT : PST_BPPROM; // light steppers advance\r
if(j > 0 && p[i].pst == PST_WJUMPER) p[i].pst = PST_BJUMPER; // use black pre-prom bonus\r
if(j > 0 && p[i].bulk == 6) p[i].pst = PST_BFLYER, p[i].mobWeight = 4; // SM defends zone\r
if((j = p[i].promo) > 0 && g)\r
- p[i].promoGain = (p[j].value - p[i].value - g)*1.25, p[i].value = p[j].value - g;\r
+ p[i].promoGain = (p[j].value - p[i].value - g)*0.9, p[i].value = p[j].value - g;\r
else p[i].promoGain = 0;\r
if(i == kylin[BLACK]) p[i].promoGain = 1.25*KYLIN, p[i].value += KYLIN;\r
board[p[i].pos] = i;\r
toList[88+i] = kStep[i]; epList[88+i] = 2*kStep[i];\r
}\r
\r
+ toList[100] = BH - 2; epList[100] = BH - 1; ep2List[100] = BH - 3;\r
+ toList[100+1] = 2; epList[100+1] = 0; ep2List[100+1] = 3;\r
+ toList[100+2] = bsize - BH - 2; epList[100+2] = bsize - BH - 1; ep2List[100+2] = bsize - BH - 3;\r
+ toList[100+3] = bsize - BW + 2; epList[100+3] = bsize - BW; ep2List[100+3] = bsize - BW + 3;\r
+\r
// fill distance table\r
for(i=0; i<2*BSIZE; i++) {\r
distance[i] = 0;\r
PST[PST_STEPPER+s] = d/4 - (i < 2 || i > BH-3 ? 3 : 0) - (j == 0 || j == BH-1 ? 5 : 0)\r
+ 3*(i==zone || i==BH-zone-1); // stepper centralization\r
PST[PST_WJUMPER+s] = d/6; // double-stepper centralization\r
- PST[PST_SLIDER +s] = d/12 - 5*(i==BH/2 || i==(BH-1)/2); // slider centralization\r
+ PST[PST_SLIDER +s] = d/12 - 15*(i==BH/2 || i==(BH-1)/2);// slider centralization\r
PST[PST_TRAP +s] = j < 3 || j > BH-4 ? (i < 3 ? 7 : i == 3 ? 4 : i == 4 ? 2 : 0) : 0;\r
PST[PST_CENTER+s] = ((BH-1)*(BH-1) - (2*i - BH + 1)*(2*i - BH + 1) - (2*j - BH + 1)*(2*j - BH + 1))/6;\r
PST[PST_WPPROM+s] = PST[PST_BPPROM+s] = PST[PST_STEPPER+s]; // as stepper, but with pre-promotion bonus W/B\r
PST[PST_BJUMPER+s] = PST[PST_WJUMPER+s]; // as jumper, but with pre-promotion bonus B\r
PST[PST_ZONDIST+s] = BW*(zone - 1 - i); // board step to enter promo zone black\r
- PST[PST_ADVANCE+s] = PST[PST_WFLYER-s-1] = 2*(5*i+i*i) - (i >= zone)*8*(i-zone+1)*(i-zone+1)\r
- - 50 - 10*(j==0 || j == BH-1); // advance-encouraging table\r
- PST[PST_WFLYER +s] = PST[PST_END-s-1] = (i == zone-1)*40 + (i == zone-2)*20 - 20;\r
+ PST[PST_ADVANCE+s] = PST[PST_WFLYER-s-1] = 2*(5*i+i*i) - (i >= zone)*6*(i-zone+1)*(i-zone+1)\r
+ - (2*j - BH + 1)*(2*j - BH + 1)/BH + BH/2\r
+ - 50 - 35*(j==0 || j == BH-1) - 15*(j == 1 || BH-2); // advance-encouraging table\r
+ PST[PST_WFLYER +s] = PST[PST_LANCE-s-1] = (i == zone-1)*40 + (i == zone-2)*20 - 20;\r
+ PST[PST_LANCE +s] = (PST[PST_STEPPER+j] - PST[PST_STEPPER+s])/2; \r
}\r
if(zone > 0) PST[PST_WPPROM+BW*(BH-1-zone) + j] += 10, PST[PST_BPPROM + BW*zone + j] += 10;\r
+ if(j > (BH-1)/2 - 3 && j < BH/2 + 3)\r
+ PST[PST_WPPROM + j] += 4, PST[PST_BPPROM + BW*(BH-1) + j] += 4; // fortress\r
+ if(j > (BH-1)/2 - 2 && j < BH/2 + 2)\r
+ PST[PST_WPPROM + BW + j] += 2, PST[PST_BPPROM + BW*(BH-2) + j] += 2; // fortress\r
#if KYLIN\r
// pre-promotion bonuses for jumpers\r
if(zone > 0) PST[PST_WJUMPER + BW*(BH-2-zone) + j] = PST[PST_BJUMPER + BW*(zone+1) + j] = 100,\r
{\r
if(board[y] != EMPTY) return 1; // edge, capture or own piece\r
//if(flag) printf("# add %c%d%c%d, pf=%d\n", x%BW+'a',x/BW,y%BW+'a',y/BW, promoFlags);\r
- if( (promoBoard[x] | promoBoard[y]) & promoFlags &&\r
- (!entryProm || promoBoard[y] & ~promoBoard[x] & CAN_PROMOTE )){ // piece can promote with this move\r
+ if( (entryProm ? promoBoard[y] & ~promoBoard[x] & CAN_PROMOTE\r
+ : promoBoard[y] | promoBoard[x] ) & promoFlags ){ // piece can promote with this move\r
moveStack[msp++] = moveStack[nonCapts]; // create space for promotion\r
moveStack[nonCapts++] = x<<SQLEN | y | PROMOTE; // push promotion\r
if((promoFlags & promoBoard[y] & (CANT_DEFER | DONT_DEFER | LAST_RANK)) == 0) { // deferral could be a better alternative\r
char rowMask[] = { 0100, 0140, 0160, 070, 034, 016, 07, 03, 01 };\r
char rows[9];\r
\r
-int\r
+void\r
AreaStep (int from, int x, int flags, int n, int d)\r
{\r
int i;\r
}\r
}\r
\r
-int\r
+void\r
AreaMoves (int from, int piece, int range)\r
{\r
int i;\r
for(r=b; r<=t-2; r++) rows[r] |= rows[r+1] | rows[r+2]; // smear vertically\r
}\r
\r
+void\r
+GenCastlings ()\r
+{ // castings for Lion Chess. Assumes board width = 8 and Kings on e-file, and K/R value = 280/300!\r
+ int f = BH>>1, t = CASTLE;\r
+ if(stm != WHITE) f += bsize - BW, t += 2;\r
+ if(p[board[f]].value = 280) {\r
+ if(p[board[f-4]].value == 300 && board[f-3] == EMPTY && board[f-2] == EMPTY && board[f-1] == EMPTY) moveStack[msp++] = f<<SQLEN | t+1;\r
+ if(p[board[f+3]].value == 300 && board[f+1] == EMPTY && board[f+2] == EMPTY) moveStack[msp++] = f<<SQLEN | t;\r
+ }\r
+}\r
+\r
int\r
GenNonCapts (int promoSuppress)\r
{\r
int\r
MapOneColor (int start, int last, int *map)\r
{\r
- int i, j, k, totMob = 0;\r
+ int i, j, totMob = 0;\r
for(i=start+2; i<=last; i+=2) {\r
int mob = 0;\r
if(p[i].pos == ABSENT) continue;\r
} else u->new = u->piece;\r
\r
if(u->to >= SPECIAL) { // two-step Lion move\r
+ if(u->to >= CASTLE) { // move Rook, faking it was an e.p. victim so that UnMake works automatically\r
+ u->epSquare = epList[u->to - SPECIAL];\r
+ u->ep2Square = ep2List[u->to - SPECIAL];\r
+ u->epVictim[0] = board[u->epSquare]; // kludgy: fake that King e.p. captured the Rook!\r
+ u->epVictim[1] = board[u->ep2Square]; // should be EMPTY (but you never know, so save as well).\r
+ board[u->ep2Square] = u->epVictim[0]; // but put Rook back\r
+ board[u->epSquare] = EMPTY;\r
+ p[u->epVictim[0]].pos = u->ep2Square;\r
+ p[u->epVictim[1]].pos = ABSENT;\r
+ u->to = toList[u->to - SPECIAL];\r
+ hashKeyL ^= p[u->epVictim[0]].pieceKey * squareKey[u->epSquare];\r
+ hashKeyH ^= p[u->epVictim[0]].pieceKey * squareKey[u->epSquare+BH];\r
+ hashKeyL ^= p[u->epVictim[0]].pieceKey * squareKey[u->ep2Square];\r
+ hashKeyH ^= p[u->epVictim[0]].pieceKey * squareKey[u->ep2Square+BH];\r
+ } else {\r
// take care of first e.p. victim\r
u->epSquare = u->from + epList[u->to - SPECIAL]; // decode\r
u->epVictim[0] = board[u->epSquare]; // remember for takeback\r
hashKeyH ^= p[u->epVictim[1]].pieceKey * squareKey[u->ep2Square+BH];\r
if(p[u->piece].value != LVAL && p[u->epVictim[0]].value == LVAL) deferred |= PROMOTE; // flag non-Lion x Lion\r
cnt50 = 0; // double capture irreversible\r
+ }\r
}\r
\r
if(u->fireMask & fireBoard[u->to]) { // we moved next to enemy Fire Demon (must be done after SPECIAL, to decode to-sqr)\r
}\r
\r
void\r
-GenCapts(int sqr, int victimValue)\r
+GenCapts (int sqr, int victimValue)\r
{ // generate all moves that capture the piece on the given square\r
- int i, range, att = attacks[2*sqr + stm];\r
+ int i, att = attacks[2*sqr + stm];\r
//printf("GenCapts(%c%d,%d) %08x\n",sqr%BW+'a',sqr/BW,victimValue,att);\r
if(!att) return; // no attackers at all!\r
for(i=0; i<8; i++) { // try all rays\r
- int x, v, jumper, jcapt=0;\r
+ int x, v, jcapt=0;\r
if(att & attackMask[i]) { // attacked by move in this direction\r
v = -kStep[i]; x = sqr;\r
while( board[x+=v] == EMPTY ); // scan towards source until we encounter a 'stop'\r
int\r
Fortress (int forward, int king, int lion)\r
{ // penalty for lack of Lion-proof fortress\r
- int rank = PST[king], anchor, r, l, q;\r
- if(!rank) return -300;\r
+ int rank = PST[king], anchor, r, l, q, res = 0;\r
+ if(rank != 2) return 25*(rank-2);\r
anchor = king + forward*(rank-1);\r
\r
+ q = Guard(anchor); l = Guard(anchor-1); r = Guard(anchor+1);\r
+ if(!q) return l > 1 || r > 1 ? 0 : -25;\r
+ if(q == 1) res = 40*(l > 1 && r > 1); // TGT, EGT or TGE get 40\r
+ else { // T or E in front of King\r
+ if(l > 1) res = 30 + (r > 1)*(20 + 5*(q==2)); // TT., ET. or TE. (30), TET (50), TTE (55)\r
+ else if(r > 1) res = 30; // .TT, .ET or .TE (30)\r
+ }\r
+ q = 0;\r
+ if(filling > 32) {\r
+ if(r > 1 && Guard(king+2) == 1) q += 10;\r
+ if(l > 1 && Guard(king-2) == 1) q += 10; \r
+ q += 5*(Guard(king+1) == 1);\r
+ q += 5*(Guard(king-1) == 1);\r
+ if(filling < 96) q = q*(filling - 32)>>6;\r
+ }\r
+ return res + q;\r
+\r
if(Guard(anchor) == 3 || Guard(anchor+1) == 3 || Guard(anchor-1) == 3) return 0;\r
if(rank == 2 && Guard(king+1) == 3 || Guard(king-1) == 3) return -50;\r
if(Guard(r=anchor) == 2 || Guard(r=anchor+1) == 2 || Guard(r=anchor-1) == 2)\r
}\r
\r
int\r
-Surround (int stm, int king, int start)\r
+Surround (int stm, int king, int start, int max)\r
{\r
int i, s=0;\r
for(i=start; i<9; i++) {\r
v = p[piece].value;\r
s += -(v > 70) & v;\r
}\r
- return (s > 512 ? 512 : s);\r
+ return (s > max ? max : s);\r
}\r
\r
int\r
int\r
Evaluate (int difEval)\r
{\r
- int wLion = ABSENT, bLion = ABSENT, wKing, bKing, score=mobilityScore, f, i, j;\r
+ int wLion = ABSENT, bLion = ABSENT, wKing, bKing, score=mobilityScore, f, i, j, max=512;\r
+\r
+ if(tsume) return difEval;\r
\r
if(p[WHITE+2].value == LVAL) wLion = p[WHITE+2].pos;\r
if(p[BLACK+2].value == LVAL) bLion = p[BLACK+2].pos;\r
score += (PST[PST_CENTER+wKing] - PST[PST_CENTER+bKing])*(32 - filling) >> 7;\r
if(lead > 100) score -= PST[PST_CENTER+bKing]*(32 - filling) >> 3; // white leads, drive black K to corner\r
if(lead < -100) score += PST[PST_CENTER+wKing]*(32 - filling) >> 3; // black leads, drive white K to corner\r
+ max = 16*filling;\r
}\r
\r
# ifdef FORTRESS\r
f = 0;\r
if(bLion != ABSENT) f += Fortress( BW, wKing, bLion);\r
if(wLion != ABSENT) f -= Fortress(-BW, bKing, wLion);\r
- score += (filling < 96 ? f : f*(224 - filling) >> 7); // build up slowly\r
+ score += (filling < 192 ? f : f*(224 - filling) >> 5); // build up slowly\r
# endif\r
\r
# ifdef KSHIELD\r
- score += Surround(WHITE, wKing, 1) - Surround(BLACK, bKing, 1) >> 3;\r
+ score += Surround(WHITE, wKing, 1, max) - Surround(BLACK, bKing, 1, max) >> 3;\r
# endif\r
\r
#endif\r
int sq;\r
if((wLion = kylin[WHITE]) && (sq = p[wLion].pos) != ABSENT) {\r
int anchor = sq - PST[5*BW*BH - 1 - sq]; // FIXME: PST_ZONDIST indexed backwards\r
- score += (512 - Surround(BLACK, anchor, 0))*(128 - filling)*PST[p[wLion].pst + sq] >> 15;\r
+ score += (512 - Surround(BLACK, anchor, 0, 512))*(128 - filling)*PST[p[wLion].pst + sq] >> 15;\r
}\r
if((bLion = kylin[BLACK]) && (sq = p[bLion].pos) != ABSENT) {\r
int anchor = sq + PST[PST_ZONDIST + sq];\r
- score -= (512 - Surround(WHITE, anchor, 0))*(128 - filling)*PST[p[bLion].pst + sq] >> 15;\r
+ score -= (512 - Surround(WHITE, anchor, 0, 512))*(128 - filling)*PST[p[bLion].pst + sq] >> 15;\r
}\r
}\r
#endif\r
\r
#ifdef PAWNBLOCK\r
- // penalty for blocking own P or GB: 20 by slider, 10 by other, but 50 if only retreat mode is straight back\r
+ // penalty for blocking own P or GB: 20 by slider, 10 by other, but 50 if only RETRACT mode is straight back\r
for(i=last[WHITE]; i > 1 && p[i].value<=50; i-=2) {\r
if((f = p[i].pos) != ABSENT) { // P present,\r
if((j = board[f + BW])&1) // square before it white (odd) piece\r
}\r
#endif\r
\r
- return difEval - (filling*filling*promoDelta >> 16) + (stm ? score : -score);\r
+#ifdef TANDEM\r
+ if(zone > 0) {\r
+ int rw = BW*(BH-1-zone), rb = BW*zone, h=0;\r
+ for(f=0; f<BH; f++) {\r
+ if(p[board[rw+f]].pst == PST_ADVANCE) {\r
+ h += (p[board[rw+f-BW]].pst == PST_ADVANCE);\r
+ if(f > 0) h += (p[board[rw+f-BW-1]].pst == PST_ADVANCE);\r
+ if(f+1 < BH) h += (p[board[rw+f-BW+1]].pst == PST_ADVANCE);\r
+ }\r
+ if(p[board[rb+f]].pst == PST_ADVANCE) {\r
+ h -= (p[board[rb+f+BW]].pst == PST_RETRACT);\r
+ if(f > 0) h -= (p[board[rb+f+BW-1]].pst == PST_RETRACT);\r
+ if(f+1 < BH) h -= (p[board[rb+f+BW+1]].pst == PST_RETRACT);\r
+ }\r
+ }\r
+ score += h*TANDEM;\r
+ }\r
+#endif\r
+\r
+ return difEval - (filling*promoDelta >> 8) + (stm ? score : -score);\r
}\r
\r
inline void\r
// in-check test and TSUME filter\r
{\r
k = p[king=royal[stm]].pos;\r
- if( k == ABSENT) k = p[king + 2].pos;\r
- else if(p[king + 2].pos != ABSENT) k = ABSENT; // two kings is no king...\r
+ if( k == ABSENT) {\r
+ if((k = p[king + 2].pos) == ABSENT && (!tsume || tsume & stm+1))\r
+ return -INF; // lose when no King (in tsume only for side to be mated)\r
+ } else if(p[king + 2].pos != ABSENT) {\r
+ if(tsume && tsume & stm+1) {\r
+ retDep = 60; return INF; // we win when not in check\r
+ }\r
+ k = ABSENT; // two kings is no king...\r
+ }\r
if( k != ABSENT) { // check is possible\r
if(!attacks[2*k + xstm]) {\r
if(tsume && tsume & stm+1) {\r
}\r
} else { // he has no king! Test for attacks on Crown Prince\r
k = p[king + 2].pos;\r
- if(k == ABSENT || attacks[2*k + stm]) return INF; // we have attack on Crown Prince\r
+ if(k == ABSENT ? !tsume : attacks[2*k + stm]) return INF; // we have attack on Crown Prince\r
}\r
//printf("King safe\n");fflush(stdout);\r
// EVALUATION & WINDOW SHIFT\r
if(to == ABSENT) continue; // ignore if absent\r
if(!attacks[2*to + stm]) continue; // skip if not attacked\r
group = p[nextVictim].value; // remember value of this found victim\r
- if(iterDep <= QSdepth + 1 && 2*group + curEval + 30 < alpha) { resDep = QSdepth + 1; goto cutoff; }\r
+ if(iterDep <= QSdepth + 1 && 2*group + curEval + 30 < alpha) {\r
+ resDep = QSdepth + 1; nextVictim -= 2;\r
+ if(bestScore < 2*group + curEval + 30) bestScore = 2*group + curEval + 30;\r
+ goto cutoff;\r
+ }\r
if(PATH) printf("%d:%2d:%2d group=%d, to=%c%d\n",level,depth,iterDep,group,to%BW+'a',to/BW+ONE);\r
GenCapts(to, 0);\r
if(PATH) printf("%d:%2d:%2d first=%d msp=%d\n",level,depth,iterDep,firstMove,msp);\r
case 6: // non-captures\r
nonCapts = msp;\r
nullMove = GenNonCapts(oldPromo);\r
+ if(msp == nonCapts) goto cutoff;\r
#ifdef KILLERS\r
{ // swap killers to front\r
Move h = killer[level][0]; int j = curMove;\r
\r
if(flag & depth >= 0) printf("%2d:%d made %d/%d %s\n", depth, iterDep, curMove, msp, MoveToText(moveStack[curMove], 0));\r
for(i=2; i<=cnt50; i+=2) if(repStack[level-i+200] == hashKeyH) {\r
+ retDep = iterDep;\r
if(repDraws) { score = 0; goto repetition; }\r
if(!allowRep) {\r
moveStack[curMove] = 0; // erase forbidden move\r
score = -Search(-beta, -iterAlpha, -difEval - tb.booty, iterDep-1+ext,\r
curMove >= late && iterDep > QSdepth + LMR,\r
promoSuppress & ~PROMOTE, defer, depth ? INF : tb.gain);\r
+\r
#else\r
score = 0;\r
#endif\r
#ifdef HASH\r
// hash store\r
hashTable[index].lock[hit] = hashKeyH;\r
- hashTable[index].depth[hit] = iterDep;\r
+ hashTable[index].depth[hit] = resDep;\r
hashTable[index].score[hit] = bestScore;\r
hashTable[index].flag[hit] = (bestScore < beta) * H_UPPER;\r
if(bestScore > alpha) {\r
\r
// some parameter of your engine\r
#define MAXMOVES 2000 /* maximum game length */\r
- #define MAXPLY 30 /* maximum search depth */\r
+ #define MAXPLY 60 /* maximum search depth */\r
\r
#define OFF 0\r
#define ON 1\r
*p++ = table[2* (*fen - 'A' - n)+1] + n;\r
}\r
} else *p++ = *fen;\r
+ if(!*fen) break;\r
fen++;\r
}\r
+ *p = '\0';\r
printf("# converted FEN '%s'\n", fenArray);\r
return fenArray;\r
}\r
SetUp(array, currentVariant);\r
strcpy(startPos, array);\r
sup0 = sup1 = sup2 = ABSENT;\r
- hashKeyH = hashKeyL = 87620895*currentVariant;\r
+ hashKeyH = hashKeyL = 87620895*currentVariant + !!fen;\r
return stm;\r
}\r
\r
char *promoChar = "";\r
if(f == t) { sprintf(buf, "@@@@"); return buf; } // null-move notation in WB protocol\r
buf[0] = '\0';\r
- if(t >= SPECIAL) { // kludgy! Print as side effect non-standard WB command to remove victims from double-capture (breaks hint command!)\r
+ if(t >= SPECIAL) {\r
+ if(t < CASTLE) { // castling is printed as a single move, implying its side effects\r
int e = f + epList[t - SPECIAL];\r
// printf("take %c%d\n", e%BW+'a', e/BW+ONE);\r
sprintf(buf, "%c%d%c%d,", f%BW+'a', f/BW+ONE, e%BW+'a', e/BW+ONE); f = e;\r
sprintf(buf+strlen(buf), "%c%d%c%d,", f%BW+'a', f/BW+ONE, e%BW+'a', e/BW+ONE); f = e;\r
if(multiLine) printf("move %s\n", buf), buf[0] = '\0';\r
}\r
+ }\r
t = g + toList[t - SPECIAL];\r
}\r
if(move & PROMOTE) promoChar = currentVariant == V_MAKRUK ? "m" : repDraws ? "q" : "+";\r
int\r
ReadSquare (char *p, int *sqr)\r
{\r
- int i=0, f, r;\r
+ int f, r;\r
f = p[0] - 'a';\r
r = atoi(p + 1) - ONE;\r
*sqr = r*BW + f;\r
Search(-INF-1, INF+1, 0, QSdepth+1, 0, sup1 & ~PROMOTE, sup2, INF);\r
postThinking++;\r
\r
- listStart = retFirst; listEnd = msp = retMSP;\r
+ listStart = retFirst; msp = retMSP;\r
+ if(currentVariant == V_LION) GenCastlings(); listEnd = msp;\r
}\r
\r
MOVE\r
if(t == f + BW - 1) t2 = SPECIAL + 48; else\r
if(t == f - BW + 1) t2 = SPECIAL + 20; else\r
if(t == f - BW - 1) t2 = SPECIAL + 52; // fake double-move\r
+ } else if(currentVariant == V_LION && board[f] != EMPTY && p[board[f]].value == 280 && (t-f == 2 || f-t == 2)) { // castling\r
+ if(t == f+2 && f < BW) t2 = CASTLE; else\r
+ if(t == f-2 && f < BW) t2 = CASTLE + 1; else\r
+ if(t == f+2 && f > BW) t2 = CASTLE + 2; else\r
+ if(t == f-2 && f > BW) t2 = CASTLE + 3;\r
}\r
ret = f<<SQLEN | t2;\r
if(*moveText != '\n' && *moveText != '=') ret |= PROMOTE;\r
for(i=listStart; i<listEnd; i++) {\r
if(sqr == (moveStack[i]>>SQLEN & SQUARE)) {\r
int t = moveStack[i] & SQUARE;\r
+ if(t >= CASTLE) t = toList[t - SPECIAL]; else // decode castling\r
if(t >= SPECIAL) {\r
int e = sqr + epList[t - SPECIAL]; // decode\r
b[e] = 'C';\r
int\r
SearchBestMove (MOVE *move, MOVE *ponderMove)\r
{\r
- int score, i;\r
+ int score;\r
printf("# SearchBestMove\n");\r
startTime = GetTickCount();\r
nodes = 0;\r
}\r
}\r
\r
+ int\r
main()\r
{\r
- int engineSide=NONE; // side played by engine\r
+ int engineSide=NONE; // side played by engine\r
MOVE move;\r
int i, score, curVarNr;\r
\r
- Init(V_CHU); // Chu\r
+ setvbuf(stdin, NULL, _IOLBF, 1024); // buffering more than one line flaws test for pending input!\r
+\r
+ Init(V_CHU); // Chu\r
seed = startTime = GetTickCount(); moveNr = 0; // initialize random\r
\r
while(1) { // infinite loop\r
\r
- fflush(stdout); // make sure everything is printed before we do something that might take time\r
+ fflush(stdout); // make sure everything is printed before we do something that might take time\r
*inBuf = 0; if(moveNr >= 20) randomize = OFF;\r
//if(moveNr >20) printf("resign\n");\r
\r
if(!strcmp(command, "remove")) { stm = TakeBack(2); continue; }\r
printf("Error: unknown command\n");\r
}\r
+ return 0;\r
}\r
\r