hachu.c 123 KB
Newer Older
1 2 3 4 5 6
/**************************************************************************/
/*                               HaChu                                    */
/* A WinBoard engine for Chu Shogi (and some related games) by H.G.Muller */
/**************************************************************************/
/* This source code is released in the public domain                      */
/**************************************************************************/
7 8 9 10 11 12

// TODO:
// in GenCapts we do not generate jumps of more than two squares yet
// promotions by pieces with Lion power stepping in & out the zone in same turn
// promotion on capture

H.G.Muller's avatar
H.G.Muller committed
13
#define VERSION "0.21"
14

15
//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))*/)))
16
#define PATH 0
17

18
#define HASH
19
#define KILLERS
20
#define NULLMOVE
21
#define CHECKEXT
22
#define LMR 4
23
#define LIONTRAP
24
#define XWINGS
25
#define KINGSAFETY
26
#define KSHIELD
27
#define FORTRESS
28
#define PAWNBLOCK
29
#define TANDEM 100 /* bonus for pairs of attacking light steppers */
30 31
#define KYLIN 100 /* extra end-game value of Kylin for promotability */
#define PROMO 0 /* extra bonus for 'vertical' piece when it actually promotes (diagonal pieces get half) */
H.G. Muller's avatar
H.G. Muller committed
32

33
#include <stdio.h>
H.G. Muller's avatar
H.G. Muller committed
34 35 36 37
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>
H.G. Muller's avatar
H.G. Muller committed
38
#include <stdint.h>
H.G. Muller's avatar
H.G. Muller committed
39 40 41

#ifdef WIN32 
#    include <windows.h>
42 43 44 45 46 47 48 49 50 51
     int InputWaiting()
     {  // checks for waiting input in pipe
	static int pipe, init;
	static HANDLE inp;
	DWORD cnt;

	if(!init) inp = GetStdHandle(STD_INPUT_HANDLE);
	if(!PeekNamedPipe(inp, NULL, 0, NULL, &cnt, NULL)) return 1;
	return cnt;
    }
H.G. Muller's avatar
H.G. Muller committed
52 53
#else
#    include <sys/time.h>
54 55 56 57 58 59 60
#    include <sys/ioctl.h>
     int InputWaiting()
     {
	int cnt;
	if(ioctl(0, FIONREAD, &cnt)) return 1;
	return cnt;
     }
H.G. Muller's avatar
H.G. Muller committed
61 62 63 64 65 66
     int GetTickCount() // with thanks to Tord
     {	struct timeval t;
	gettimeofday(&t, NULL);
	return t.tv_sec*1000 + t.tv_usec/1000;
     }
#endif
67

H.G. Muller's avatar
H.G. Muller committed
68 69
#define BW bWidth
#define BH bHeight
70
#define BHMAX 16
H.G. Muller's avatar
H.G. Muller committed
71 72 73
#define BWMAX (2*BHMAX)
#define BSIZE BWMAX*BHMAX
#define ZONE  zone
74

75
#define ONE 1 /* currently no variants with 10-deep board */
76 77 78 79 80 81

#define BLACK      0
#define WHITE      1
#define EMPTY      0
#define EDGE   (1<<11)
#define TYPE   (WHITE|BLACK|EDGE)
H.G. Muller's avatar
H.G. Muller committed
82
#define ABSENT  2047
83
#define INF     8000
84
#define NPIECES EDGE+1               /* length of piece list    */
85 86 87 88 89

#define SQLEN    11                /* bits in square number   */
#define SQUARE  ((1<<SQLEN) - 1)   /* mask for square in move */
#define DEFER   (1<<2*SQLEN)       /* deferral on zone entry  */
#define PROMOTE (1<<2*SQLEN+1)     /* promotion bit in move   */
90 91
#define SPECIAL  1400              /* start of special moves  */
#define BURN    (SPECIAL + 96)     /* start of burn encodings */
92
#define CASTLE  (SPECIAL + 100)    /* castling encodings      */
93 94 95 96 97 98 99 100 101 102 103 104 105 106
#define STEP(X,Y) (BW*(X)+ (Y))
#define SORTKEY(X) 0

#define UPDATE_MOBILITY(X,Y)
#define ADDMOVE(X,Y)

// promotion codes
#define CAN_PROMOTE 0x11
#define DONT_DEFER  0x22
#define CANT_DEFER  0x44
#define LAST_RANK   0x88
#define P_WHITE     0x0F
#define P_BLACK     0xF0

107 108 109 110 111 112 113 114 115 116 117
// Piece-Square Tables
#define PST_NEUTRAL 0
#define PST_STEPPER BH
#define PST_WJUMPER (BW*BH)
#define PST_SLIDER  (BW*BH+BH)
#define PST_TRAP    (2*BW*BH)
#define PST_CENTER  (2*BW*BH+BH)
#define PST_WPPROM  (3*BW*BH)
#define PST_BPPROM  (3*BW*BH+BH)
#define PST_BJUMPER (4*BW*BH)
#define PST_ZONDIST (4*BW*BH+BH)
118 119 120 121
#define PST_ADVANCE (5*BW*BH)
#define PST_RETRACT (5*BW*BH+BH)
#define PST_WFLYER  (6*BW*BH)
#define PST_BFLYER  (6*BW*BH+BH)
122 123
#define PST_LANCE   (7*BW*BH)
#define PST_END     (8*BW*BH)
124

125 126 127
typedef unsigned int Move;

char *MoveToText(Move move, int m);     // from WB driver
128 129 130
void pmap(int *m, int col);
void pboard(int *b);
void pbytes(unsigned char *b);
H.G.Muller's avatar
H.G.Muller committed
131
int myRandom();
132

H.G. Muller's avatar
H.G. Muller committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
typedef struct {
  int lock[5];
  int move[5];
  short int score[5];
  char depth[5];
  char flag[5];
  char age[4];
} HashBucket;

HashBucket *hashTable;
int hashMask;

#define H_UPPER 2
#define H_LOWER 1

148 149 150 151
typedef struct {
  char *name, *promoted;
  int value;
  signed char range[8];
152
  char bulk;
153
  char ranking;
154
  int whiteKey, blackKey;
155 156 157
} PieceDesc;

typedef struct {
H.G.Muller's avatar
H.G.Muller committed
158
  int from, to, piece, victim, new, booty, epSquare, epVictim[9], ep2Square, revMoveCount;
159
  int savKeyL, savKeyH, gain, loss, filling, saveDelta;
160
  char fireMask;
161 162
} UndoInfo;

163
char *array, fenArray[4000], startPos[4000], *reason, checkStack[300];
164 165
int bWidth, bHeight, bsize, zone, currentVariant, chuFlag, tenFlag, chessFlag, repDraws, stalemate;
int tsume, pvCuts, allowRep, entryProm, okazaki, pVal;
166 167
int stm, xstm, hashKeyH=1, hashKeyL=1, framePtr, msp, nonCapts, rootEval, filling, promoDelta;
int retMSP, retFirst, retDep, pvPtr, level, cnt50, mobilityScore;
168
int ll, lr, ul, ur; // corner squares
169
int nodes, startTime, lastRootMove, lastRootIter, tlim1, tlim2, tlim3, repCnt, comp, abortFlag;
170
Move ponderMove;
H.G.Muller's avatar
H.G.Muller committed
171
Move retMove, moveStack[20000], path[100], repStack[300], pv[1000], repeatMove[300], killer[100][2];
172

H.G. Muller's avatar
H.G. Muller committed
173 174
      int maxDepth;                            // used by search

175
#define X 36 /* slider              */
176
#define R 37 /* jump capture        */
H.G. Muller's avatar
H.G. Muller committed
177 178
#define N -1 /* Knight              */
#define J -2 /* jump                */
H.G.Muller's avatar
H.G.Muller committed
179 180 181 182
#define I -3 /* jump + step         */
#define D -4 /* linear double move  */
#define T -5 /* linear triple move  */
#define L -6 /* true Lion move      */
H.G.Muller's avatar
H.G.Muller committed
183 184 185 186 187 188
#define W -7 /* Werewolf move       */
#define F -8 /* Lion + 3-step       */
#define S -9 /* Lion + range        */
#define H -10 /* hook move           */
#define C -11 /* capture only       */
#define M -12 /* non-capture only   */
189

190 191
#define LVAL 1000 /* piece value of Lion. Used in chu for recognizing it to implement Lion-trade rules  */
#define FVAL 5000 /* piece value of Fire Demon. Used in code for recognizing moves with it and do burns */
192 193

PieceDesc chuPieces[] = {
H.G.Muller's avatar
H.G.Muller committed
194 195
  {"LN", "",  LVAL, { W,W,W,W,W,W,W,W }, 4 }, // lion
//  {"LN", "",  LVAL, { T,T,T,T,T,T,T,T }, 4 }, // lion
196
//  {"LN", "",  LVAL, { L,L,L,L,L,L,L,L }, 4 }, // lion
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
  {"FK", "",   600, { X,X,X,X,X,X,X,X }, 4 }, // free king
  {"SE", "",   550, { X,D,X,X,X,X,X,D }, 4 }, // soaring eagle
  {"HF", "",   500, { D,X,X,X,X,X,X,X }, 4 }, // horned falcon
  {"FO", "",   400, { X,X,0,X,X,X,0,X }, 4 }, // flying ox
  {"FB", "",   400, { 0,X,X,X,0,X,X,X }, 4 }, // free boar
  {"DK", "SE", 400, { X,1,X,1,X,1,X,1 }, 4 }, // dragon king
  {"DH", "HF", 350, { 1,X,1,X,1,X,1,X }, 4 }, // dragon horse
  {"WH", "",   350, { X,X,0,0,X,0,0,X }, 3 }, // white horse
  {"R",  "DK", 300, { X,0,X,0,X,0,X,0 }, 4 }, // rook
  {"FS", "",   300, { X,1,1,1,X,1,1,1 }, 3 }, // flying stag
  {"WL", "",   250, { X,0,0,X,X,X,0,0 }, 4 }, // whale
  {"K",  "",   280, { 1,1,1,1,1,1,1,1 }, 2, 4 }, // king
  {"CP", "",   270, { 1,1,1,1,1,1,1,1 }, 2, 4 }, // king
  {"B",  "DH", 250, { 0,X,0,X,0,X,0,X }, 2 }, // bishop
  {"VM", "FO", 200, { X,0,1,0,X,0,1,0 }, 2 }, // vertical mover
  {"SM", "FB", 200, { 1,0,X,0,1,0,X,0 }, 6 }, // side mover
  {"DE", "CP", 201, { 1,1,1,1,0,1,1,1 }, 2 }, // drunk elephant
  {"BT", "FS", 152, { 0,1,1,1,1,1,1,1 }, 2 }, // blind tiger
  {"G",  "R",  151, { 1,1,1,0,1,0,1,1 }, 2 }, // gold
  {"FL", "B",  150, { 1,1,0,1,1,1,0,1 }, 2 }, // ferocious leopard
  {"KN", "LN", 154, { J,1,J,1,J,1,J,1 }, 2 }, // kirin
  {"PH", "FK", 153, { 1,J,1,J,1,J,1,J }, 2 }, // phoenix
  {"RV", "WL", 150, { X,0,0,0,X,0,0,0 }, 1 }, // reverse chariot
  {"L",  "WH", 150, { X,0,0,0,0,0,0,0 }, 1 }, // lance
  {"S",  "VM", 100, { 1,1,0,1,0,1,0,1 }, 2 }, // silver
  {"C",  "SM", 100, { 1,1,0,0,1,0,0,1 }, 2 }, // copper
  {"GB", "DE",  50, { 1,0,0,0,1,0,0,0 }, 1 }, // go between
  {"P",  "G",   40, { 1,0,0,0,0,0,0,0 }, 2 }, // pawn
225 226 227
  { NULL }  // sentinel
};

228
PieceDesc shoPieces[] = {
229 230 231 232 233 234 235 236 237 238 239 240
  {"DK", "",   700, { X,1,X,1,X,1,X,1 } }, // dragon king
  {"DH", "",   520, { 1,X,1,X,1,X,1,X } }, // dragon horse
  {"R",  "DK", 500, { X,0,X,0,X,0,X,0 } }, // rook
  {"B",  "DH", 320, { 0,X,0,X,0,X,0,X } }, // bishop
  {"K",  "",   410, { 1,1,1,1,1,1,1,1 } }, // king
  {"CP", "",   400, { 1,1,1,1,1,1,1,1 } }, // king
  {"DE", "CP", 250, { 1,1,1,1,0,1,1,1 } }, // silver
  {"G",  "",   220, { 1,1,1,0,1,0,1,1 } }, // gold
  {"S",  "G",  200, { 1,1,0,1,0,1,0,1 } }, // silver
  {"L",  "G",  150, { X,0,0,0,0,0,0,0 } }, // lance
  {"N",  "G",  110, { N,0,0,0,0,0,0,N } }, // Knight
  {"P",  "G",   80, { 1,0,0,0,0,0,0,0 } }, // pawn
241 242 243
  { NULL }  // sentinel
};

244
PieceDesc daiPieces[] = {
245 246 247 248 249 250 251 252
  {"FD", "G", 150, { 0,2,0,2,0,2,0,2 }, 2 }, // Flying Dragon
  {"VO", "G", 200, { 2,0,2,0,2,0,2,0 }, 2 }, // Violent Ox
  {"EW", "G",  80, { 1,1,1,0,0,0,1,1 }, 2 }, // Evil Wolf
  {"CS", "G",  70, { 0,1,0,1,0,1,0,1 }, 1 }, // Cat Sword
  {"AB", "G",  60, { 1,0,1,0,1,0,1,0 }, 1 }, // Angry Boar
  {"I",  "G",  80, { 1,1,0,0,0,0,0,1 }, 2 }, // Iron
  {"N",  "G",  60, { N,0,0,0,0,0,0,N }, 0 }, // Knight
  {"ST", "G",  50, { 0,1,0,0,0,0,0,1 }, 0 }, // Stone
253 254 255
  { NULL }  // sentinel
};

H.G.Muller's avatar
H.G.Muller committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
PieceDesc waPieces[] = {
  {"TE", "",   720, { X,X,1,X,X,X,1,X }, 4 }, // Tenacious Falcon
  {"GS", "",   500, { X,0,X,0,X,0,X,0 }, 4 }, // Gliding Swallow (R)
  {"DE", "",   430, { X,3,1,1,X,1,1,3 }, 3 }, // Cloud Eagle
  {"K",  "",   410, { 1,1,1,1,1,1,1,1 }, 2 }, // Crane King (K)
  {"BT", "",   390, { I,I,0,I,I,I,0,I }, 4 }, // Treacherous Fox
  {"FL", "TE", 380, { 1,X,0,X,0,X,0,X }, 4 }, // Flying Falcon
  {"FS", "",   290, { X,1,1,0,X,0,1,1 }, 3 }, // Raiding Falcon
  {"S",  "GS", 260, { 1,0,X,0,1,0,X,0 }, 6 }, // Swallow's Wing (SM)
  {"PO", "",   260, { 1,1,1,1,1,1,1,1 }, 2 }, // Plodding Ox (K)
  {"R",  "BT", 260, { X,1,0,1,1,1,0,1 }, 2 }, // Running Rabit
  {"B",  "",   240, { 1,1,1,1,0,1,1,1 }, 2 }, // Roaming Boar
  {"HH", "",   220, { N,0,0,N,N,0,0,N }, 1 }, // Heavenly Horse
  {"EW", "PO", 220, { 1,1,1,0,1,0,1,1 }, 2 }, // Violent Wolf (G)
  {"VM", "B",  200, { 1,1,0,1,0,1,0,1 }, 2 }, // Violent Stag (S)
  {"G",  "S",  190, { 1,1,0,0,1,0,0,1 }, 2 }, // Flying Goose (C)
  {"SM", "VM", 175, { 1,1,0,0,1,0,0,1 }, 2 }, // Climbing Monkey (C)
  {"DH", "HH", 170, { X,0,0,0,2,0,0,0 }, 1 }, // Liberated Horse
  {"DK", "EW", 150, { 0,1,1,0,1,0,1,1 }, 2 }, // Blind Dog
  {"PH", "PO", 150, { X,0,0,0,0,0,0,0 }, 1 }, // Oxcart (L)
  {"L",  "FS", 130, { 0,1,1,0,0,0,1,1 }, 2 }, // Flying Cock
  {"KN", "DE", 115, { 1,0,0,1,0,1,0,0 }, 2 }, // Swooping Owl
  {"C",  "FL", 105, { 1,0,0,1,0,1,0,0 }, 2 }, // Strutting Crow
  {"P",  "EW",  80, { 1,0,0,0,0,0,0,0 }, 2 }, // Sparrow Pawn (P)
  { NULL }  // sentinel
};

283
PieceDesc ddPieces[] = {
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  {"LO", "",   10, { 1,H,1,H,1,H,1,H } }, // Long-Nosed Goblin
  {"OK", "LO", 10, { 2,1,2,0,2,0,2,1 } }, // Old Kite
  {"PS", "HM", 10, { J,0,1,J,0,J,1,0 } }, // Poisonous Snake
  {"GE", "",   10, { 3,3,5,5,3,5,5,3 } }, // Great Elephant
  {"WS", "LD", 10, { 1,1,2,0,1,0,2,1 } }, // Western Barbarian
  {"EA", "LN", 10, { 2,1,1,0,2,0,1,1 } }, // Eastern Barbarian
  {"NO", "FE", 10, { 0,2,1,1,0,1,1,2 } }, // Northern Barbarian
  {"SO", "WE", 10, { 0,1,1,2,0,2,1,1 } }, // Southern Barbarian
  {"FE", "",   10, { 2,X,2,2,2,2,2,X } }, // Fragrant Elephant
  {"WE", "",   10, { 2,2,2,X,2,X,2,2 } }, // White Elephant
  {"FT", "",   10, { X,X,5,0,X,0,5,X } }, // Free Dream-Eater
  {"FR", "",   10, { 5,X,X,0,5,0,X,X } }, // Free Demon
  {"WB", "FT", 10, { 2,X,X,X,2,X,X,X } }, // Water Buffalo
  {"RB", "FR", 10, { X,X,X,X,0,X,X,X } }, // Rushing Bird
  {"SB", "",   10, { X,X,2,2,2,2,2,X } }, // Standard Bearer

  {"FH", "FK", 10, { 1,2,1,0,1,0,1,2 } }, // Flying Horse
  {"NK", "SB", 10, { 1,1,1,1,1,1,1,1 } }, // Neighbor King
  {"BM", "MW", 10, { 0,1,1,1,0,1,1,1 } }, // Blind Monkey
  {"DO", "",   10, { 2,X,2,X,2,X,2,X } }, // Dove
  {"EB", "DO", 10, { 2,0,2,0,0,0,2,0 } }, // Enchanted Badger
  {"EF", "SD", 10, { 0,2,0,0,2,0,0,2 } }, // Enchanted Fox
  {"RA", "",   10, { X,0,X,1,X,1,X,0 } }, // Racing Chariot
  {"SQ", "",   10, { X,1,X,0,X,0,X,1 } }, // Square Mover
  {"PR", "SQ", 10, { 1,1,2,1,0,1,2,1 } }, // Prancing Stag
  {"WT", "",   10, { X,1,2,0,X,0,2,X } }, // White Tiger
  {"BD", "",   10, { 2,X,X,0,2,0,X,1 } }, // Blue Dragon
  {"HD", "",   10, { X,0,0,0,1,0,0,0 } }, // Howling Dog
  {"VB", "",   10, { 0,2,1,0,0,0,1,2 } }, // Violent Bear
  {"SA", "",   10, { 2,1,0,0,2,0,0,1 } }, // Savage Tiger
  {"W",  "",   10, { 0,2,0,0,0,0,0,2 } }, // Wood
  {"CS", "DH",  70, { 0,1,0,1,0,1,0,1 } }, // cat sword
  {"FD", "DK", 150, { 0,2,0,2,0,2,0,2 } }, // flying dragon
  {"KN", "GD", 150, { J,1,J,1,J,1,J,1 } }, // kirin
  {"PH", "GB", 150, { 1,J,1,J,1,J,1,J } }, // phoenix
  {"LN", "FF",  1000, { L,L,L,L,L,L,L,L } }, // lion
  {"LD", "GE", 10, { T,T,T,T,T,T,T,T } }, // Lion Dog
  {"AB", "", 10, { 1,0,1,0,1,0,1,0 } }, // Angry Boar
  {"B",  "", 10, { 0,X,0,X,0,X,0,X } }, // Bishop
  {"C",  "", 10, { 1,1,0,0,1,0,0,1 } }, // Copper
  {"DH", "", 10, { 1,X,1,X,1,X,1,X } }, // Dragon Horse
  {"DK", "", 10, { X,1,X,1,X,1,X,1 } }, // Dragon King
  {"FK", "", 10, {  } }, // 
  {"EW", "", 10, { 1,1,1,0,0,0,1,1 } }, // Evil Wolf
  {"FL", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
333 334 335 336
  { NULL }  // sentinel
};

PieceDesc makaPieces[] = {
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
  {"DV", "", 10, { 0,1,0,1,0,0,1,1 } }, // Deva
  {"DS", "", 10, { 0,1,1,0,0,1,0,1 } }, // Dark Spirit
  {"T",  "", 10, { 0,1,0,0,1,0,0,1 } }, // Tile
  {"CS", "", 10, { 1,0,0,1,1,1,0,0 } }, // Coiled Serpent
  {"RD", "", 10, { 1,0,1,1,1,1,1,0 } }, // Reclining Dragon
  {"CC", "", 10, { 0,1,1,0,1,0,1,1 } }, // Chinese Cock
  {"OM", "", 10, { 0,1,0,1,1,1,0,1 } }, // Old Monkey
  {"BB", "", 10, { 0,1,0,1,X,1,0,1 } }, // Blind Bear
  {"OR", "", 10, { 0,2,0,0,2,0,0,2 } }, // Old Rat
  {"LD", "WS", 10, { T,T,T,T,T,T,T,T } }, // Lion Dog
  {"WR", "", 10, { 0,3,1,3,0,3,1,3 } }, // Wrestler
  {"GG", "", 10, { 3,1,3,0,3,0,3,1 } }, // Guardian of the Gods
  {"BD", "", 10, { 0,3,1,0,1,0,1,3 } }, // Budhist Devil
  {"SD", "", 10, { 5,2,5,2,5,2,5,2 } }, // She-Devil
  {"DY", "", 10, { J,0,1,0,J,0,1,0 } }, // Donkey
  {"CP", "", 10, { 0,H,0,2,0,2,0,H } }, // Capricorn
  {"HM", "", 10, { H,0,H,0,H,0,H,0 } }, // Hook Mover
  {"SF", "", 10, { 0,1,X,1,0,1,0,1 } }, // Side Flier
  {"LC", "", 10, { X,0,0,X,1,0,0,X } }, // Left Chariot
  {"RC", "", 10, { X,X,0,0,1,X,0,0 } }, // Right Chariot
  {"FG", "", 10, { X,X,X,0,X,0,X,X } }, // Free Gold
  {"FS", "", 10, { X,X,0,X,0,X,0,X } }, // Free Silver
  {"FC", "", 10, { X,X,0,0,X,0,0,X } }, // Free Copper
  {"FI", "", 10, { X,X,0,0,0,0,0,X } }, // Free Iron
  {"FT", "", 10, { 0,X,0,0,X,0,0,X } }, // Free Tile
  {"FN", "", 10, { 0,X,0,0,0,0,0,X } }, // Free Stone
  {"FTg", "", 10, { 0,X,X,X,X,X,X,X } }, // Free Tiger
  {"FLp", "", 10, { X,X,0,X,X,X,0,X } }, // Free Leopard (Free Boar?)
  {"FSp", "", 10, { X,0,0,X,X,X,0,0 } }, // Free Serpent (Whale?)
  {"FrD", "", 10, { X,0,X,X,X,X,X,0 } }, // Free Dragon
  {"FC", "", 10, { 0,X,0,X,0,X,0,X } }, // Free Cat (Bishop?)
  {"EM", "", 10, {  } }, // Emperor
  {"TK", "", 10, {  } }, // Teaching King
  {"BS", "", 10, {  } }, // Budhist Spirit
  {"WS", "", 10, { X,X,0,X,1,X,0,X } }, // Wizard Stork
  {"MW", "", 10, { 1,X,0,X,X,X,0,X } }, // Mountain Witch
  {"FF", "", 10, {  } }, // Furious Fiend
  {"GD", "", 10, { 2,3,X,3,2,3,X,3 } }, // Great Dragon
  {"GB", "", 10, { X,3,2,3,X,3,2,3 } }, // Golden Bird
  {"FrW", "", 10, {  } }, // Free Wolf
  {"FrB", "", 10, {  } }, // Free Bear
  {"BT", "", 10, { X,0,0,X,0,X,0,0 } }, // Bat
  {"", "", 10, {  } }, // 
380 381 382 383
  { NULL }  // sentinel
};

PieceDesc taiPieces[] = {
384 385 386 387 388 389 390 391
  {"", "", 10, {  } }, // Peacock
  {"", "", 10, {  } }, // Vermillion Sparrow
  {"", "", 10, {  } }, // Turtle Snake
  {"", "", 10, {  } }, // Silver Hare
  {"", "", 10, {  } }, // Golden Deer
  {"", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
  {"", "", 10, {  } }, // 
392 393 394
  { NULL }  // sentinel
};

395
PieceDesc tenjikuPieces[] = { // only those not in Chu, or different (because of different promotion)
396 397 398 399 400 401 402 403 404
  {"FI", "",  FVAL, { X,X,0,X,X,X,0,X } }, // Fire Demon
  {"GG", "",  1500, { R,R,R,R,R,R,R,R }, 0, 3 }, // Great General
  {"VG", "",  1400, { 0,R,0,R,0,R,0,R }, 0, 2 }, // Vice General
  {"RG", "GG",1200, { R,0,R,0,R,0,R,0 }, 0, 1 }, // Rook General
  {"BG", "VG",1100, { 0,R,0,R,0,R,0,R }, 0, 1 }, // Bishop General
  {"SE", "RG", 10, { X,D,X,X,X,X,X,D } }, // Soaring Eagle
  {"HF", "BG", 10, { D,X,X,X,X,X,X,X } }, // Horned Falcon
  {"LH", "",   10, { L,S,L,S,L,S,L,S } }, // Lion-Hawk
  {"LN", "LH",LVAL, { L,L,L,L,L,L,L,L } }, // Lion
405
  {"FE", "",   1,   { X,X,X,X,X,X,X,X } }, // Free Eagle
406 407 408 409 410 411 412 413 414 415
  {"FK", "FE", 600, { X,X,X,X,X,X,X,X } }, // Free King
  {"HT", "",   10, { X,X,2,X,X,X,2,X } }, // Heavenly Tetrarchs
  {"CS", "HT", 10, { X,X,2,X,X,X,2,X } }, // Chariot Soldier
  {"WB", "FI", 10, { 2,X,X,X,2,X,X,X } }, // Water Buffalo
  {"VS", "CS", 10, { X,0,2,0,1,0,2,0 } }, // Vertical Soldier
  {"SS", "WB", 10, { 2,0,X,0,1,0,X,0 } }, // Side Soldier
  {"I",  "VS", 10, { 1,1,0,0,0,0,0,1 } }, // Iron
  {"N",  "SS", 10, { N,0,0,0,0,0,0,N } }, // Knight
  {"MG", "",   10, { X,0,0,X,0,X,0,0 } }, // Multi-General
  {"D",  "MG", 10, { 1,0,0,1,0,1,0,0 } }, // Dog
416 417 418
  { NULL }  // sentinel
};

419
PieceDesc taikyokuPieces[] = {
420
  {"", "", 10, {  } }, // 
421 422 423
  { NULL }  // sentinel
};

H.G. Muller's avatar
H.G. Muller committed
424
PieceDesc chessPieces[] = {
425
  {"FK", "", 950, { X,X,X,X,X,X,X,X } },
426 427 428 429
  {"R", "",  500, { X,0,X,0,X,0,X,0 } },
  {"B", "",  320, { 0,X,0,X,0,X,0,X } },
  {"N", "",  300, { N,N,N,N,N,N,N,N } },
  {"K", "",  280, { 1,1,1,1,1,1,1,1 } },
430
  {"P", "FK", 80, { M,C,0,0,0,0,0,C } },
H.G. Muller's avatar
H.G. Muller committed
431 432 433
  { NULL }  // sentinel
};

434 435
PieceDesc lionPieces[] = {
  {"LN","", LVAL, { L,L,L,L,L,L,L,L } },
436
  {"FK", "", 600, { X,X,X,X,X,X,X,X } },
437 438 439 440
  {"R", "",  300, { X,0,X,0,X,0,X,0 } },
  {"K", "",  280, { 1,1,1,1,1,1,1,1 } },
  {"B", "",  190, { 0,X,0,X,0,X,0,X } },
  {"N", "",  180, { N,N,N,N,N,N,N,N } },
441
  {"P", "FK", 50, { M,C,0,0,0,0,0,C } },
442 443 444
  { NULL }  // sentinel
};

H.G. Muller's avatar
H.G. Muller committed
445
PieceDesc shatranjPieces[] = {
446 447 448 449 450 451
  {"FK", "", 150, { 0,1,0,1,0,1,0,1 } },
  {"R", "",  500, { X,0,X,0,X,0,X,0 } },
  {"B", "",   90, { 0,J,0,J,0,J,0,J } },
  {"N", "",  300, { N,N,N,N,N,N,N,N } },
  {"K", "",  280, { 1,1,1,1,1,1,1,1 } },
  {"P", "FK", 80, { M,C,0,0,0,0,0,C } },
H.G. Muller's avatar
H.G. Muller committed
452 453 454
  { NULL }  // sentinel
};

H.G. Muller's avatar
H.G. Muller committed
455
PieceDesc makrukPieces[] = {
456 457 458 459 460 461
  {"SM","",  150, { 0,1,0,1,0,1,0,1 } },
  {"R", "",  500, { X,0,X,0,X,0,X,0 } },
  {"S", "",  200, { 1,1,0,1,0,1,0,1 } }, // silver
  {"N", "",  300, { N,N,N,N,N,N,N,N } },
  {"K", "",  280, { 1,1,1,1,1,1,1,1 } },
  {"P", "SM", 80, { M,C,0,0,0,0,0,C } },
H.G. Muller's avatar
H.G. Muller committed
462 463 464
  { NULL }  // sentinel
};

H.G.Muller's avatar
H.G.Muller committed
465 466 467 468 469 470 471 472 473 474
PieceDesc wolfPieces[] = {
  {"EW","EW",1050,{ W,W,W,W,W,W,W,W }, 6, 5 }, // kludge to get extra Werewolves
  {"R", "",  500, { X,0,X,0,X,0,X,0 }, 3 },
  {"B", "",  320, { 0,X,0,X,0,X,0,X }, 1 },
  {"N", "",  300, { N,N,N,N,N,N,N,N }, 1 },
  {"K", "",  280, { 1,1,1,1,1,1,1,1 } },
  {"P", "R",  80, { M,C,0,0,0,0,0,C } },
  { NULL }  // sentinel
};

475 476 477 478 479 480
char chuArray[] = "L:FLCSGK:DEGSC:FLL/:RV.B.:BT:KN:PH:BT.B.:RV/:SM:VMR:DH:DK:LN:FK:DK:DHR:VM:SM/PPPPPPPPPPPP/...:GB....:GB..."
		  "/............/............/"
		  "...:gb....:gb.../pppppppppppp/:sm:vmr:dh:dk:fk:ln:dk:dhr:vm:sm/:rv.b.:bt:ph:kn:bt.b.:rv/l:flcsg:dekgsc:fll";
char daiArray[] = "LN:STICSGKGSCI:STNL/:RV.:CS.:FL.:BT:DE:BT.:FL.:CS.:RV/.:VO.:AB.:EW:KN:LN:PH:EW.:AB.:VO./R:FD:SM:VMB:DH:DK:FK:DK:DHB:VM:SM:FDR"
		  "/PPPPPPPPPPPPPPP/....:GB.....:GB..../.............../.............../.............../....:gb.....:gb..../ppppppppppppppp/"
		  "r:fd:sm:vmb:dh:dk:fk:dk:dhb:vm:sm:fdr/.:vo.:ab.:ew:ph:ln:kn:ew.:ab.:vo./:rv.:cs.:fl.:bt:de:bt.:fl.:cs.:rv/ln:sticsgkgsci:stnl";
481 482 483 484 485 486
char tenArray[] = "LN:FLICSGK:DEGSCI:FLNL/:RV.:CS:CS.:BT:KN:LN:FK:PH:BT.:CS:CS.:RV/:SS:VSB:DH:DK:WB:FI:LH:FE:FI:WB:DK:DHB:VS:SS/"
		  ":SM:VMR:HF:SE:BG:RG:GG:VG:RG:BG:SE:HFR:VM:SM/PPPPPPPPPPPPPPPP/....D......D..../"
		  "................/................/................/................/"
		  "....d......d..../pppppppppppppppp/:sm:vmr:hf:se:bg:rg:vg:gg:rg:bg:se:hfr:vm:sm/"
		  ":ss:vsb:dh:dk:wb:fi:fe:lh:fi:wb:dk:dhb:vs:ss/:rv.:cs:cs.:bt:ph:fk:ln:kn:bt.:cs:cs.:rv/ln:flicsg:dekgsci:flnl";
char shoArray[] = "LNSGKGSNL/.B..:DE..R./PPPPPPPPP/........./........./........./ppppppppp/.r..:de..b./lnsgkgsnl";
H.G.Muller's avatar
H.G.Muller committed
487 488 489
char waArray[] = ":PH:DKCG:EWK:VML:KN:SM:DH/.:FL...S...:DE./PPP:BTPPPRPPP/...P...P..."
		 "/.........../.........../..........."
		 "/...p...p.../ppprppp:btppp/.:de...s...:fl./:dh:sm:knl:vmk:ewgc:dk:ph";
490 491
char chessArray[] = "RNB:FKKBNR/PPPPPPPP/......../......../......../......../pppppppp/rnb:fkkbnr";
char lionArray[]  = "R:LNB:FKKBNR/PPPPPPPP/......../......../......../......../pppppppp/r:lnb:fkkbnr";
H.G. Muller's avatar
H.G. Muller committed
492
char shatArray[]= "RNBK:FKBNR/PPPPPPPP/......../......../......../......../pppppppp/rnbk:fkbnr";
H.G. Muller's avatar
H.G. Muller committed
493
char thaiArray[]= "RNSK:SMSNR/......../PPPPPPPP/......../......../pppppppp/......../rns:smksnr";
H.G.Muller's avatar
H.G.Muller committed
494
char wolfArray[]= "RNB:EWKBNR/PPPPPPPP/......../......../......../......../pppppppp/rnb:ewkbnr";
495 496

typedef struct {
497
  int boardWidth, boardFiles, boardRanks, zoneDepth, varNr; // board sizes
498 499 500 501
  char *name;  // WinBoard name
  char *array; // initial position
} VariantDesc;

H.G.Muller's avatar
H.G.Muller committed
502
typedef enum { V_CHESS, V_SHO, V_CHU, V_DAI, V_DADA, V_MAKA, V_TAI, V_KYOKU, V_TENJIKU, V_SHATRANJ, V_MAKRUK, V_LION, V_WA, V_WOLF } Variant;
H.G. Muller's avatar
H.G. Muller committed
503 504

#define SAME (-1)
505

506
VariantDesc variants[] = {
507 508
  { 24, 12, 12, 4, V_CHU,     "chu",     chuArray }, // Chu
  { 16,  8,  8, 1, V_CHESS,  "nocastle", chessArray }, // FIDE
509
  { 18,  9,  9, 3, V_SHO, "9x9+0_shogi", shoArray }, // Sho
510
  { 18,  9,  9, 3, V_SHO,     "sho",     shoArray }, // Sho duplicat
511 512
  { 30, 15, 15, 5, V_DAI,     "dai",     daiArray }, // Dai
  { 32, 16, 16, 5, V_TENJIKU, "tenjiku", tenArray }, // Tenjiku
H.G. Muller's avatar
H.G. Muller committed
513
  { 16,  8,  8, 1, V_SHATRANJ,"shatranj",shatArray}, // Shatranj
H.G. Muller's avatar
H.G. Muller committed
514
  { 16,  8,  8, 3, V_MAKRUK,  "makruk",  thaiArray}, // Makruk
515
  { 16,  8,  8, 1, V_LION,    "lion",    lionArray}, // Mighty Lion
H.G.Muller's avatar
H.G.Muller committed
516
  { 22, 11, 11, 3, V_WA,      "washogi", waArray},   // Wa
H.G.Muller's avatar
H.G.Muller committed
517
  { 16,  8,  8, 1, V_WOLF,    "werewolf",wolfArray},   // Wa
H.G. Muller's avatar
H.G. Muller committed
518

519
  { 0, 0, 0, 0, 0 }, // sentinel
520 521 522 523
  { 34, 17, 17, 0, V_DADA,    "dada",    chuArray }, // Dai Dai
  { 38, 19, 19, 0, V_MAKA,    "maka",    chuArray }, // Maka Dai Dai
  { 50, 25, 25, 0, V_TAI,     "tai",     chuArray }, // Tai
  { 40, 36, 36, 0, V_KYOKU,   "kyoku",   chuArray }  // Taikyoku
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
};

typedef struct {
  int x, y;
} Vector;

Vector direction[] = { // clockwise!
  {1,  0},
  {1,  1},
  {0,  1},
  {-1, 1},
  {-1, 0},
  {-1,-1},
  {0, -1},
  {1, -1},

  { 2, 1}, // Knight jumps
  { 1, 2},
  {-1, 2},
  {-2, 1},
  {-2,-1},
  {-1,-2},
  { 1,-2},
  { 2,-1}
};

550
int epList[104], ep2List[104], toList[104], reverse[104];  // decoding tables for double and triple moves
551
int kingStep[10], knightStep[10];         // raw tables for step vectors (indexed as -1 .. 8)
552
int neighbors[9];   // similar to kingStep, but starts with null-step
553
char fireFlags[10]; // flags for Fire-Demon presence (last two are dummies, which stay 0, for compactify)
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
#define kStep (kingStep+1)
#define nStep (knightStep+1)

int attackMask[8] = { // indicate which bits in attack-map item are used to count attacks from which direction
  000000007,
  000000070,
  000000700,
  000007000,
  000070000,
  000700000,
  007000000,
  070000000
};

int rayMask[8] = { // indicate which bits in attack-map item are used to count attacks from which direction
  000000077,
  000000077,
  000007700,
  000007700,
  000770000,
  000770000,
  077000000,
  077000000
};

int one[] = { // 1 in the bit fields for the various directions
  000000001,
  000000010,
  000000100,
  000001000,
  000010000,
  000100000,
  001000000,
  010000000,
 0100000000  // marks knight jumps
};

//                                           Main Data structures
//
// Piece List: 
//   Interleaved lists for black and white, white taking the odd slots
//   Pieces in general have two entries: one for the basic, and one for the promoted version
//   The unused one gets its position set to the invalid square number ABSENT
//   The list is sorted by piece value, most valuable pieces first
//   When a piece is captured in the search, both its versions are marked ABSENT
//   In the root the list is packed to eliminate all captured pieces
//   The list contains a table for how far the piece moves in each direction
//   Range encoding: -3 = full Lion, -2 = on-ray Lion, -1 = plain jump, 0 = none, 1 = step, >1 = (limited) range
// Attack table:
//   A table in board format, containing pairs of consecutive integers for each square (indexed as 2*sqr and 2*sqr+1)
//   The first integer contains info on black attacks to the square, the second similarly for white attacks
//   Each integer contains eight 3-bit fields, which count the number of attacks on it with moves in a particular direction
//   (If there are attacks by range-jumpers, the 3-bit count is increased by 2 over the actual value)
// Board:
//   The board has twice as many files as actually used, in 0x88 fashion
//   The used squares hold the piece numbers (for use as index in the piece list)
//   Unused squares are set to the invalid piece number EDGE
//   There are also 3 guard ranks of EDGE on each side
// Moves:
//   Moves are encoded as 11-bit from-square and to-square numbers packed in the low bits of an int
//   Special moves (like Lion double moves) are encoded by off-board to-squares above a certain value
//   Promotions are indicated by bit 22
// Hash table:
//   Entries of 16 bytes, holding a 32-bit signature, 16-bit lower- and upper-bound scores,
//   8-bit draft of each of those scores, an age counter that stores the search number of the last access.
//   The hash key is derived as the XOR of the products pieceKey[piece]*squareKey[square].
// Promotion zones
//   the promoBoard contains one byte with flags for each square, to indicate for each side whether the square
//   is in the promotion zone (twice), on the last two ranks, or on the last rank
//   the promoFlag field in the piece list can select which bits of this are tested, to see if it
//   (1) can promote (2) can defer when the to-square is on last rank, last two ranks, or anywhere.
//   Pawns normally can't defer anywhere, but if the user defers with them, their promoFlag is set to promote on last rank only

typedef struct {
  int pos;
  int pieceKey;
  int promo;
  int value;
  int pst;
  signed char range[8];
  char promoFlag;
  char qval;
  char mobility;
  char mobWeight;
638 639
  unsigned char promoGain;
  char bulk;
H.G.Muller's avatar
H.G.Muller committed
640
  char ranking;
641 642
} PieceInfo; // piece-list entry

643
int last[2], royal[2], kylin[2];
644 645 646 647 648 649 650 651 652 653 654 655 656
PieceInfo p[NPIECES]; // piece list

typedef struct {
  int lock;
  Move move;
  short int upper;
  short int lower;
  char depthU;
  char depthL;
  char flags;
  char age;
} HashEntry; // hash-table entry

657 658 659 660
    // Some global variables that control your engine's behavior
    int ponder;
    int randomize;
    int postThinking;
661
    int noCut=1;        // engine-defined option
662 663
    int resign;         // engine-defined option
    int contemptFactor; // likewise
664
    int seed;
665

666 667
int squareKey[BSIZE];

H.G. Muller's avatar
H.G. Muller committed
668
int rawBoard[BSIZE + 11*BHMAX + 6];
669 670 671
//int attacks[2*BSIZE];   // attack map
int attackMaps[200*BSIZE], *attacks = attackMaps;
char distance[2*BSIZE]; // distance table
672
char promoBoard[BSIZE]; // flags to indicate promotion zones
H.G.Muller's avatar
H.G.Muller committed
673
unsigned char rawFire[BSIZE+2*BWMAX]; // flags to indicate squares controlled by Fire Demons
674
signed char PST[7*BSIZE];
675

676 677 678
#define board     (rawBoard + 6*BHMAX + 3)
#define fireBoard (rawFire + BWMAX + 1)
#define dist      (distance + BSIZE)
679

680
PieceDesc *
H.G. Muller's avatar
H.G. Muller committed
681
ListLookUp (char *name, PieceDesc *list)
682
{ // find piece of given name in list of descriptors
683
  while(list->name && strcmp(name, list->name)) list++;
684
  return (list->name == NULL ? NULL : list);
685 686
}

H.G. Muller's avatar
H.G. Muller committed
687 688 689 690 691
PieceDesc *
LookUp (char *name, int var)
{ // search piece of given name in all lists relevant for given variant
  PieceDesc *desc;
  switch(var) {
692 693 694 695 696 697 698
    case V_TENJIKU: // Tenjiku
      desc = ListLookUp(name, tenjikuPieces);
      if(desc) return desc;
      return ListLookUp(name, chuPieces);
    case V_SHO: // Sho
      return ListLookUp(name, shoPieces);
    case V_DAI: // Dai
H.G. Muller's avatar
H.G. Muller committed
699 700
      desc = ListLookUp(name, daiPieces);
      if(desc) return desc;
701
    case V_CHU: // Chu
H.G. Muller's avatar
H.G. Muller committed
702
      return ListLookUp(name, chuPieces);
703 704
    case V_CHESS: // FIDE
      return ListLookUp(name, chessPieces);
H.G. Muller's avatar
H.G. Muller committed
705 706
    case V_SHATRANJ: // Shatranj
      return ListLookUp(name, shatranjPieces);
H.G. Muller's avatar
H.G. Muller committed
707 708
    case V_MAKRUK: // Makruk
      return ListLookUp(name, makrukPieces);
709 710
    case V_LION: // Mighty Lion
      return ListLookUp(name, lionPieces);
H.G.Muller's avatar
H.G.Muller committed
711 712
    case V_WA: // Wa
      return ListLookUp(name, waPieces);
H.G.Muller's avatar
H.G.Muller committed
713 714
    case V_WOLF: // Werewolf
      return ListLookUp(name, wolfPieces);
H.G. Muller's avatar
H.G. Muller committed
715
  }
716
  return NULL;
H.G. Muller's avatar
H.G. Muller committed
717 718
}

719 720 721 722
void
SqueezeOut (int n)
{ // remove piece number n from the mentioned side's piece list (and adapt the reference to the displaced pieces!)
  int i;
723
  for(i=stm+2; i<=last[stm]; i+=2)
724 725 726 727
    if(p[i].promo > n) p[i].promo -= 2;
  for(i=n; i<last[stm]; i+=2) {
    p[i] = p[i+2];
    if(i+2 == royal[stm]) royal[stm] -= 2; // NB: squeezing out the King moves up Crown Prince to royal[stm]
728
    if(i+2 == kylin[stm]) kylin[stm] -= 2;
729
    if(i < 10) fireFlags[i-2] = fireFlags[i];
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
  }
  last[stm] -= 2;
}

int
Worse (int a, int b)
{ // determine if range a not upward compatible with b
  if(a == b) return 0;
  if(a >= 0 && b >= 0) return a < b;
  if(a >= 0) return 1; // a (limited) range can never do the same as a special move
  switch(a) {
    case J: return b < J; // any special move is better than a plain jump
    case D: return b > 2 || b < D;
    case T: return b > 3 || b < T;
    case L: return b > 2 || b < D;
    case F: return b > 3 || b < F || b == T;
    case S: return b == H || b == T;
    case H: return b < 0;
    default: return 1; // a >= 0, so b must be < 0 and can always do something a ranging move cannot do
  }
  return 0;
}

753 754 755 756 757 758 759
int
Lance (signed char *r)
{ // File-bound forward slider
  int i;
  for(i=1; i<4; i++) if(r[i] || r[i+4]) return 0;
  return r[0] == X;
}
760

761 762 763
int
EasyProm (signed char *r)
{
764 765 766
  if(r[0] == X) return 30 + PROMO*((unsigned int)(r[1] | r[2] | r[3] | r[5] | r[6] | r[7]) <= 1);
  if(r[1] == X || r[7] == X) return 30 + PROMO/2;
  return 0;
767 768
}

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
int
IsUpwardCompatible (signed char *r, signed char *s)
{
  int i;
  for(i=0; i<8; i++) {
    if(Worse(r[i], s[i])) return 0;
  }
  return 1;
}

int
Forward (signed char *r)
{
  int i;
  for(i=2; i<7; i++) if(r[i]) return 0;
  return 1;
}

int
Range (signed char *r)
{
  int i, m=0;
  for(i=0; i<8; i++) {
    int d = r[i];
H.G.Muller's avatar
H.G.Muller committed
793
    if(r[i] < 0) d = r[i] >= L ? 2 : 36;
794 795 796 797 798
    if(d > m) m = d;
  }
  return m;
}

799 800 801 802 803 804 805
int multis[2], multiMovers[100];

void
StackMultis (int col)
{
  int i, j;
  multis[col] = col;
806 807
  for(i=col+2; i<=last[col]; i+=2) { // scan piece list for multi-capturers
    for(j=0; j<8; j++) if(p[i].range[j] < J && p[i].range[j] >= S || p[i].value == FVAL) {
808 809 810 811 812 813 814
      multiMovers[multis[col]] = i; // found one: put its piece number in list
      multis[col] += 2;
      break;
    }
  }
}

815 816 817
void
Compactify (int stm)
{ // remove pieces that are permanently gone (captured or promoted) from one side's piece list
H.G.Muller's avatar
H.G.Muller committed
818
  int i, k;
819
  for(i=stm+2; i<=last[stm]; i+=2) { // first pass: unpromoted pieces
820 821 822 823 824
    if((k = p[i].promo) >= 0 && p[i].pos == ABSENT) { // unpromoted piece no longer there
      p[k].promo = -2; // orphan promoted version
      SqueezeOut(i);
    }
  }
825
  for(i=stm+2; i<=last[stm]; i+=2) { // second pass: promoted pieces
H.G. Muller's avatar
H.G. Muller committed
826

827 828 829 830
    if((k = p[i].promo) == -2 && p[i].pos == ABSENT) { // orphaned promoted piece not present
      SqueezeOut(i);
    }
  }
831
  StackMultis(stm);
832 833 834
}

int
835
AddPiece (int stm, PieceDesc *list)
836
{
H.G. Muller's avatar
H.G. Muller committed
837
  int i, j, *key, v;
838
  for(i=stm+2; i<=last[stm]; i += 2) {
839
    if(p[i].value < list->value || p[i].value == list->value && (p[i].promo < 0)) break;
840 841 842
  }
  last[stm] += 2;
  for(j=last[stm]; j>i; j-= 2) p[j] = p[j-2];
843
  p[i].value = v = list->value;
844
  for(j=0; j<8; j++) p[i].range[j] = list->range[j^4*(WHITE-stm)];
845
  switch(Range(p[i].range)) {
846 847 848
    case 1:  p[i].pst = PST_STEPPER; break;
    case 2:  p[i].pst = PST_WJUMPER; break;
    default: p[i].pst = PST_SLIDER;  break;
849
  }
850 851
  key = (stm == WHITE ? &list->whiteKey : &list->blackKey);
  if(!*key) *key = ~(myRandom()*myRandom());
852
  p[i].promoGain = EasyProm(list->range); // flag easy promotion based on white view
853
  p[i].pieceKey = *key;
854
  p[i].promoFlag = 0;
855
  p[i].bulk = list->bulk;
H.G.Muller's avatar
H.G.Muller committed
856
  p[i].ranking = list->ranking;
H.G. Muller's avatar
H.G. Muller committed
857
  p[i].mobWeight = v > 600 ? 0 : v >= 400 ? 1 : v >= 300 ? 2 : v > 150 ? 3 : v >= 100 ? 2 : 0;
858
  if(Lance(list->range))
859
    p[i].mobWeight = 0, p[i].pst = list->range[4] ? PST_NEUTRAL : PST_LANCE; // keep back
860 861 862 863
  for(j=stm+2; j<= last[stm]; j+=2) {
    if(p[j].promo >= i) p[j].promo += 2;
  }
  if(royal[stm] >= i) royal[stm] += 2;
864
  if(kylin[stm] >= i) kylin[stm] += 2;
H.G.Muller's avatar
H.G.Muller committed
865
  if(p[i].value == (currentVariant == V_SHO || currentVariant == V_WA ? 410 : 280) ) royal[stm] = i, p[i].pst = 0;
866
  p[i].qval = (currentVariant == V_TENJIKU ? list->ranking : 0); // jump-capture hierarchy
867 868 869 870
  return i;
}

void
H.G.Muller's avatar
H.G.Muller committed
871
SetUp (char *array, int var)
872
{
H.G.Muller's avatar
H.G.Muller committed
873 874
  int i, j, n, m, color;
  char c, name[3], prince = 0;
875
  PieceDesc *p1, *p2;
876
  last[WHITE] = 1; last[BLACK] = 0;
877
  royal[WHITE] = royal[BLACK] = 0;
878 879 880
  for(i=0; ; i++) {
//printf("next rank: %s\n", array);
    for(j = BW*i; ; j++) {
H.G. Muller's avatar
H.G. Muller committed
881 882
      int pflag=0;
      if(*array == '+') pflag++, array++;
883 884 885 886 887 888 889 890 891 892 893
      c = name[0] = *array++;
      if(!c) goto eos;
      if(c == '.') continue;
      if(c == '/') break;
      name[1] = name[2] = 0;
      if(c == ':') name[0] = *array++, name[1] = *array++;
      if(name[0] >= 'a') {
	color = BLACK;
	name[0] += 'A' - 'a';
	if(name[1]) name[1] += 'A' - 'a';
      } else color = WHITE;
894
      if(!strcmp(name, "CP") || pflag && !strcmp(name, "DE")) prince |= color+1; // remember if we added Crown Prince
H.G. Muller's avatar
H.G. Muller committed
895
      p1 = LookUp(name, var);
896
      if(!p1) printf("tellusererror Unknown piece '%s' in setup\n", name), exit(-1);
H.G. Muller's avatar
H.G. Muller committed
897
      if(pflag && p1->promoted) p1 = LookUp(p1->promoted, var); // use promoted piece instead
898
      n = AddPiece(color, p1);
899
      p[n].pos = j;
H.G. Muller's avatar
H.G. Muller committed
900
      if(p1->promoted[0] && !pflag) {
901
        if(!strcmp(p1->promoted, "CP")) prince |= color+1; // remember if we added Crown Prince
H.G. Muller's avatar
H.G. Muller committed
902
	p2 = LookUp(p1->promoted, var);
903
        m = AddPiece(color, p2);
904 905
	if(m <= n) n += 2;
	p[n].promo = m;
906 907 908
	p[n].promoFlag = IsUpwardCompatible(p2->range, p1->range) * DONT_DEFER + CAN_PROMOTE;
	if(Forward(p1->range)) p[n].promoFlag |= LAST_RANK; // Pieces that only move forward can't defer on last rank
	if(!strcmp(p1->name, "N")) p[n].promoFlag |= CANT_DEFER; // Knights can't defer on last 2 ranks
909 910 911
	p[n].promoFlag &= n&1 ? P_WHITE : P_BLACK;
	p[m].promo = -1;
	p[m].pos = ABSENT;
912
	if(p[m].value == LVAL) kylin[color] = n; // remember piece that promotes to Lion
913 914 915 916 917
      } else p[n].promo = -1; // unpromotable piece
//printf("piece = %c%-2s %d(%d) %d/%d\n", color ? 'w' : 'b', name, n, m, last[color], last[!color]);
    }
  }
 eos:
918 919 920
  // add dummy Kings if not yet added (needed to set royal[] to valid value!)
  if(!royal[WHITE]) p[AddPiece(WHITE, LookUp("K", V_CHU))].pos = ABSENT;
  if(!royal[BLACK]) p[AddPiece(BLACK, LookUp("K", V_CHU))].pos = ABSENT;
921 922 923
  // add dummy Crown Princes if not yet added
  if(!(prince & WHITE+1)) p[AddPiece(WHITE, LookUp("CP", V_CHU))].pos = ABSENT;
  if(!(prince & BLACK+1)) p[AddPiece(BLACK, LookUp("CP", V_CHU))].pos = ABSENT;
924
  for(i=0; i<8; i++)  fireFlags[i] = 0;
925
  for(i=2, n=1; i<10; i++) if(p[i].value == FVAL) {
926 927 928 929 930
    int x = p[i].pos; // mark all burn zones
    fireFlags[i-2] = n;
    if(x != ABSENT) for(j=0; j<8; j++) fireBoard[x+kStep[j]] |= n;
    n <<= 1;
  }
H.G.Muller's avatar
H.G.Muller committed
931
  for(i=2; i<6; i++) if(p[i].ranking == 5) p[i].promo = -1, p[i].promoFlag = 0; // take promotability away from Werewolves
932
  for(i=0; i<BH; i++) for(j=0; j<BH; j++) board[BW*i+j] = EMPTY;
933
  for(i=WHITE+2; i<=last[WHITE]; i+=2) if(p[i].pos != ABSENT) {
934
    int g = p[i].promoGain;
935 936 937
    if(i == kylin[WHITE]) p[i].promoGain = 1.25*KYLIN, p[i].value += KYLIN;
//    if(j > 0 && p[i].pst == PST_STEPPER) p[i].pst = PST_WPPROM; // use white pre-prom bonus
    if(j > 0 && p[i].pst == PST_STEPPER && p[i].value >= 100)
938
	p[i].pst = p[i].value <= 150 ? PST_ADVANCE : PST_WPPROM;  // light steppers advance
939
    if(j > 0 && p[i].bulk == 6) p[i].pst = PST_WFLYER, p[i].mobWeight = 4; // SM defends zone
940
    if((j = p[i].promo) > 0 && g)
941
      p[i].promoGain = (p[j].value - p[i].value - g)*0.9, p[i].value = p[j].value - g;
942 943 944 945 946 947 948
    else p[i].promoGain = 0;
    board[p[i].pos] = i;
    rootEval += p[i].value + PST[p[i].pst + p[i].pos];
    promoDelta += p[i].promoGain;
    filling += p[i].bulk;
  } else p[i].promoGain = 0;
  for(i=BLACK+2; i<=last[BLACK]; i+=2) if(p[i].pos != ABSENT) {
949
    int g = p[i].promoGain;
950 951
//    if(j > 0 && p[i].pst == PST_STEPPER) p[i].pst = PST_BPPROM; // use black pre-prom bonus
    if(j > 0 && p[i].pst == PST_STEPPER && p[i].value >= 100)
952
	p[i].pst = p[i].value <= 150 ? PST_RETRACT : PST_BPPROM;  // light steppers advance
953 954
    if(j > 0 && p[i].pst == PST_WJUMPER) p[i].pst = PST_BJUMPER;  // use black pre-prom bonus
    if(j > 0 && p[i].bulk == 6) p[i].pst = PST_BFLYER, p[i].mobWeight = 4; // SM defends zone
955
    if((j = p[i].promo) > 0 && g)
956
      p[i].promoGain = (p[j].value - p[i].value - g)*0.9, p[i].value = p[j].value - g;
957
    else p[i].promoGain = 0;
958
    if(i == kylin[BLACK]) p[i].promoGain = 1.25*KYLIN, p[i].value += KYLIN;
959 960 961 962 963
    board[p[i].pos] = i;
    rootEval -= p[i].value + PST[p[i].pst + p[i].pos];
    promoDelta -= p[i].promoGain;
    filling += p[i].bulk;
  } else p[i].promoGain = 0;
964 965
  StackMultis(WHITE);
  StackMultis(BLACK);
966 967 968 969 970 971 972 973 974
  stm = WHITE; xstm = BLACK;
}

int myRandom()
{
  return rand() ^ rand()>>10 ^ rand() << 10 ^ rand() << 20;
}

void
H.G. Muller's avatar
H.G. Muller committed
975
Init (int var)
976 977
{
  int i, j, k;
978
  PieceDesc *pawn;
979

H.G. Muller's avatar
H.G. Muller committed
980
  if(var != SAME) { // the following should be already set if we stay in same variant (for TakeBack)
981
  currentVariant = variants[var].varNr;
H.G. Muller's avatar
H.G. Muller committed
982 983 984
  bWidth  = variants[var].boardWidth;
  bHeight = variants[var].boardRanks;
  zone    = variants[var].zoneDepth;
985
  array   = variants[var].array;
H.G. Muller's avatar
H.G. Muller committed
986
  }
H.G. Muller's avatar
H.G. Muller committed
987
  bsize = bWidth*bHeight;
988
  chuFlag = (currentVariant == V_CHU || currentVariant == V_LION);
989
  tenFlag = (currentVariant == V_TENJIKU);
H.G.Muller's avatar
H.G.Muller committed
990 991
  chessFlag = (currentVariant == V_CHESS || currentVariant == V_LION || currentVariant == V_WOLF);
  stalemate = (currentVariant == V_CHESS || currentVariant == V_MAKRUK || currentVariant == V_LION || currentVariant == V_WOLF);
H.G. Muller's avatar
H.G. Muller committed
992
  repDraws  = (stalemate || currentVariant == V_SHATRANJ);
993
  ll = 0; lr = bHeight - 1; ul = (bHeight - 1)*bWidth; ur = ul + bHeight - 1;
994
  pawn = LookUp("P", currentVariant); pVal = pawn ? pawn->value : 0; // get Pawn value
H.G. Muller's avatar
H.G. Muller committed
995

996 997 998 999
  for(i= -1; i<9; i++) { // board steps in linear coordinates
    kStep[i] = STEP(direction[i&7].x,   direction[i&7].y);       // King
    nStep[i] = STEP(direction[(i&7)+8].x, direction[(i&7)+8].y); // Knight
  }
1000
  for(i=0; i<8; i++) neighbors[i+1] = kStep[i];
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

  for(i=0; i<8; i++) { // Lion double-move decoding tables
    for(j=0; j<8; j++) {
      epList[8*i+j] = kStep[i];
      toList[8*i+j] = kStep[j] + kStep[i];
      for(k=0; k<8*i+j; k++)
	if(epList[k] == toList[8*i+j] && toList[k] == epList[8*i+j])
	  reverse[k] = 8*i+j, reverse[8*i+j] = k;
    }
    // Lion-Dog triple moves
    toList[64+i] = 3*kStep[i]; epList[64+i] =   kStep[i];
    toList[72+i] = 3*kStep[i]; epList[72+i] = 2*kStep[i];
1013
    toList[80+i] = 3*kStep[i]; epList[80+i] = 2*kStep[i]; ep2List[80+i] = kStep[i];
1014 1015 1016
    toList[88+i] =   kStep[i]; epList[88+i] = 2*kStep[i];
  }

1017 1018 1019 1020 1021
  toList[100]   = BH - 2; epList[100]   = BH - 1; ep2List[100]   = BH - 3;
  toList[100+1] =      2; epList[100+1] =      0; ep2List[100+1] =      3;
  toList[100+2] = bsize - BH - 2; epList[100+2] = bsize - BH - 1; ep2List[100+2] = bsize - BH - 3;
  toList[100+3] = bsize - BW + 2; epList[100+3] = bsize - BW;     ep2List[100+3] = bsize - BW + 3;

1022
  // fill distance table
H.G. Muller's avatar
H.G. Muller committed
1023
  for(i=0; i<2*BSIZE; i++) {
1024 1025
    distance[i] = 0;
  }
1026 1027 1028 1029
//  for(i=0; i<8; i++)
//    for(j=1; j<BH; j++)
//      dist[j * kStep[i]] = j;
//  if(currentVariant == V_TENJIKU)
1030
    for(i=1-BH; i<BH; i++) for(j=1-BH; j<BH; j++) dist[BW*i+j] = abs(i) > abs(j) ? abs(i) : abs(j);
1031 1032

  // hash key tables
H.G. Muller's avatar
H.G. Muller committed
1033
  for(i=0; i<bsize; i++) squareKey[i] = ~(myRandom()*myRandom());
1034 1035

  // board edge
H.G. Muller's avatar
H.G. Muller committed
1036
  for(i=0; i<BSIZE + 11*BHMAX + 6; i++) rawBoard[i] = EDGE;
1037 1038 1039 1040 1041 1042

  // promotion zones
  for(i=0; i<BH; i++) for(j=0; j<BH; j++) {
    char v = 0;
    if(i == 0)       v |= LAST_RANK & P_BLACK;
    if(i < 2)        v |= CANT_DEFER & P_BLACK;
1043 1044
    if(i < ZONE)     v |= (CAN_PROMOTE | DONT_DEFER) & P_BLACK; else v &= ~P_BLACK;
    if(i >= BH-ZONE) v |= (CAN_PROMOTE | DONT_DEFER) & P_WHITE; else v &= ~P_WHITE;
1045 1046 1047 1048 1049 1050
    if(i >= BH-2)    v |= CANT_DEFER & P_WHITE;
    if(i == BH-1)    v |= LAST_RANK & P_WHITE;
    promoBoard[BW*i + j] = v;
  }

  // piece-square tables
1051 1052
  for(j=0; j<BH; j++) {
   for(i=0; i<BH; i++) {
1053
    int s = BW*i + j, d = BH*(BH-2) - abs(2*i - BH + 1)*(BH-1) - (2*j - BH + 1)*(2*j - BH + 1);
1054 1055 1056 1057
    PST[s] = 2*(i==0 | i==BH-1) + (i==1 | i==BH-2);         // last-rank markers in null table
    PST[PST_STEPPER+s] = d/4 - (i < 2 || i > BH-3 ? 3 : 0) - (j == 0 || j == BH-1 ? 5 : 0)
                    + 3*(i==zone || i==BH-zone-1);          // stepper centralization
    PST[PST_WJUMPER+s] = d/6;                               // double-stepper centralization
H.G.Muller's avatar
H.G.Muller committed
1058
    PST[PST_SLIDER +s] = d/12 - 15*(i==BH/2 || i==(BH-1)/2);// slider centralization
1059 1060 1061 1062 1063
    PST[PST_TRAP  +s] = j < 3 || j > BH-4 ? (i < 3 ? 7 : i == 3 ? 4 : i == 4 ? 2 : 0) : 0;
    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;
    PST[PST_WPPROM+s] = PST[PST_BPPROM+s] = PST[PST_STEPPER+s]; // as stepper, but with pre-promotion bonus W/B
    PST[PST_BJUMPER+s] = PST[PST_WJUMPER+s];                // as jumper, but with pre-promotion bonus B
    PST[PST_ZONDIST+s] = BW*(zone - 1 - i);                 // board step to enter promo zone black
1064
    PST[PST_ADVANCE+s] = PST[PST_WFLYER-s-1] = 2*(5*i+i*i) - (i >= zone)*6*(i-zone+1)*(i-zone+1)
H.G.Muller's avatar
H.G.Muller committed
1065 1066
	- (2*j - BH + 1)*(2*j - BH + 1)/BH + BH/2
	- 50 - 35*(j==0 || j == BH-1) - 15*(j == 1 || BH-2); // advance-encouraging table
1067 1068
    PST[PST_WFLYER +s] = PST[PST_LANCE-s-1] = (i == zone-1)*40 + (i == zone-2)*20 - 20;
    PST[PST_LANCE  +s] = (PST[PST_STEPPER+j] - PST[PST_STEPPER+s])/2; 
1069
   }
1070
   if(zone > 0) PST[PST_WPPROM+BW*(BH-1-zone) + j] += 10, PST[PST_BPPROM + BW*zone + j] += 10;
1071 1072 1073 1074
   if(j > (BH-1)/2 - 3 && j < BH/2 + 3)
	PST[PST_WPPROM + j] += 4, PST[PST_BPPROM + BW*(BH-1) + j] += 4; // fortress
   if(j > (BH-1)/2 - 2 && j < BH/2 + 2)
	PST[PST_WPPROM + BW + j] += 2, PST[PST_BPPROM + BW*(BH-2) + j] += 2; // fortress
1075 1076
#if KYLIN
   // pre-promotion bonuses for jumpers
1077 1078
   if(zone > 0) PST[PST_WJUMPER + BW*(BH-2-zone) + j] = PST[PST_BJUMPER + BW*(zone+1) + j] = 100,
                PST[PST_WJUMPER + BW*(BH-1-zone) + j] = PST[PST_BJUMPER + BW*zone + j] = 200;
1079
#endif
1080 1081 1082
  }

  p[EDGE].qval = 5; // tenjiku jump-capturer sentinel
1083 1084
}

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
int
PSTest ()
{
  int r, f, score, tot=0;
  for(r=0; r<BH; r++) for(f=0; f<BH; f++) {
    int s = BW*r+f;
    int piece = board[s];
    if(!piece) continue;
    score = p[piece].value + PST[p[piece].pst + s];
    if(piece & 1) tot += score; else tot -= score;
  }
  return tot;
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
int
Dtest ()
{
  int r, f, score, tot=0;
  for(r=0; r<BH; r++) for(f=0; f<BH; f++) {
    int s = BW*r+f;
    int piece = board[s];
    if(!piece) continue;
    score = p[piece].promoGain;
    if(piece & 1) tot += score; else tot -= score;
  }
  return tot;
}

H.G. Muller's avatar
H.G. Muller committed
1113 1114
int flag;

1115 1116 1117 1118
inline int
NewNonCapture (int x, int y, int promoFlags)
{
  if(board[y] != EMPTY) return 1; // edge, capture or own piece
H.G. Muller's avatar
H.G. Muller committed
1119
//if(flag) printf("# add %c%d%c%d, pf=%d\n", x%BW+'a',x/BW,y%BW+'a',y/BW, promoFlags);
H.G.Muller's avatar
H.G.Muller committed
1120 1121
  if( (entryProm ? promoBoard[y] & ~promoBoard[x] & CAN_PROMOTE
                 : promoBoard[y] |  promoBoard[x]       ) & promoFlags ){ // piece can promote with this move
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
    moveStack[msp++] = moveStack[nonCapts];           // create space for promotion
    moveStack[nonCapts++] = x<<SQLEN | y | PROMOTE;   // push promotion
    if((promoFlags & promoBoard[y] & (CANT_DEFER | DONT_DEFER | LAST_RANK)) == 0) { // deferral could be a better alternative
      moveStack[msp++] = x<<SQLEN | y;                // push deferral
      if( (promoBoard[x] & CAN_PROMOTE) == 0 ) {      // enters zone
	moveStack[msp-1] |= DEFER;                    // flag that promo-suppression takes place after this move
      }
    }
  } else
    moveStack[msp++] = x<<SQLEN | y; // push normal move
H.G. Muller's avatar
H.G. Muller committed
1132
//if(flag) printf("msp=%d nc=%d\n", msp, nonCapts);	
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
  return 0;
}

inline int
NewCapture (int x, int y, int promoFlags)
{
  if( (promoBoard[x] | promoBoard[y]) & promoFlags) { // piece can promote with this move
    moveStack[msp++] = x<<SQLEN | y | PROMOTE;        // push promotion
    if((promoFlags & promoBoard[y] & (CANT_DEFER | DONT_DEFER | LAST_RANK)) == 0) { // deferral could be a better alternative
      moveStack[msp++] = x<<SQLEN | y;                // push deferral
      if( (promoBoard[x] & CAN_PROMOTE) == 0 ) {      // enters zone
	moveStack[msp-1] |= DEFER;                    // flag that promo-suppression takes place after this move
      }
    }
  } else
    moveStack[msp++] = x<<SQLEN | y; // push normal move
  return 0;
}

1152 1153 1154 1155 1156
char map[49]; // 7x7 map for area movers
char mapStep[] = { 7, 8, 1, -6, -7, -8, -1, 6 };
char rowMask[] = { 0100, 0140, 0160, 070, 034, 016, 07, 03, 01 };
char rows[9];

H.G.Muller's avatar
H.G.Muller committed
1157
void
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
AreaStep (int from, int x, int flags, int n, int d)
{
  int i;
  for(i=0; i<8; i++) {
    int to = x + kStep[i], m = n + mapStep[i];
    if(board[to] == EDGE) continue; // off board
    if(map[m] >= d) continue;   // already done
    if(!map[m]) moveStack[msp++] = from<<SQLEN | to;
    map[m] = d;
    if(d > 1 && board[to] == EMPTY) AreaStep(from, to, flags, m, d-1);
  }
}

H.G.Muller's avatar
H.G.Muller committed
1171
void
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
AreaMoves (int from, int piece, int range)
{
  int i;
  for(i=0; i<49; i++) map[i] = 0;
  map[3*7+7] = range;
  AreaStep(from, from, p[piece].promoFlag, 3*7+3, range);
}

void
MarkBurns (int x)
{ // make bitmap of squares in FI (7x7) neighborhood where opponents can be captured or burned
  int r=x>>5, f=x&15, top=8, bottom=0, b=0, t=8, left=0, right=8; // 9x9 area; assumes 32x16 board
  if(r < 4) bottom = 4 - r, rows[b=bottom-1] = 0; else
  if(r > 11) top   = 19 - r, rows[t=top+1] = 0; // adjust area to board edges
  if(f < 4) left   = 4 - f; else if(f > 11) right = 19 - f;
  for(r=bottom; r<=top; r++) {
    int mask = 0, y = x + 16*r;
    for(f=left; f <= right; f++) {
      if(board[y + f - (4*16+4)] != EMPTY && (board[y + f - (4*16+4)] & TYPE) == xstm)
	mask |= rowMask[f]; // on-rank attacks
    }
    rows[r+2] = mask;
  }
  for(r=b; r<=t-2; r++) rows[r] |= rows[r+1] | rows[r+2]; // smear vertically
}

1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
void
GenCastlings ()
{ // castings for Lion Chess. Assumes board width = 8 and Kings on e-file, and K/R value = 280/300!
    int f = BH>>1, t = CASTLE;
    if(stm != WHITE) f += bsize - BW, t += 2;
    if(p[board[f]].value = 280) {
      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;
      if(p[board[f+3]].value == 300 && board[f+1] == EMPTY && board[f+2] == EMPTY) moveStack[msp++] = f<<SQLEN | t;
    }
}

1209 1210 1211 1212 1213 1214 1215
int
GenNonCapts (int promoSuppress)
{
  int i, j, nullMove = ABSENT;
  for(i=stm+2; i<=last[stm]; i+=2) {
    int x = p[i].pos, pFlag = p[i].promoFlag;
    if(x == ABSENT) continue;
H.G. Muller's avatar
H.G. Muller committed
1216
    if(x == promoSuppress && chuFlag) pFlag = 0;
1217 1218 1219
    for(j=0; j<8; j++) {
      int y, v = kStep[j], r = p[i].range[j];
      if(r < 0) { // jumping piece, special treatment
H.G. Muller's avatar
H.G. Muller committed
1220 1221 1222
	if(r == N) { // pure Knightm do off-ray jump
	  NewNonCapture(x, x + nStep[j], pFlag);
	} else
1223
	if(r >= S) { // in any case, do a jump of 2
1224
	  int occup = NewNonCapture(x, x + 2*v, pFlag);
H.G.Muller's avatar
H.G.Muller committed
1225
	  if(r < I) { // Lion power, also single step
H.G.Muller's avatar
H.G.Muller committed
1226
	    if(!NewNonCapture(x, x + v, pFlag)) nullMove = (r == W ? ABSENT : x); else occup = 1;
1227 1228
	    if(r <= L) { // true Lion, also Knight jump
	      if(!occup & r < L) for(y=x+2*v; !NewNonCapture(x, y+=v, pFlag) && r == S; ); // BS and FF moves
1229
	      v = nStep[j];
H.G.Muller's avatar
H.G.Muller committed
1230
	      if(r != W) NewNonCapture(x, x + v, pFlag);
H.G.Muller's avatar
H.G.Muller committed
1231
	    } else if(r == T) NewNonCapture(x, x+3*v, pFlag); // Lion Dog, also triple step
H.G.Muller's avatar
H.G.Muller committed
1232
	  } else if(r == I) NewNonCapture(x, x + v, pFlag); // also do step
1233 1234
	} else
	if(r == M) { // FIDE Pawn; check double-move
H.G. Muller's avatar
H.G. Muller committed
1235
	  if(!NewNonCapture(x, x+v, pFlag) && chessFlag && promoBoard[x-v] & LAST_RANK)
1236
	    NewNonCapture(x, x+2*v, pFlag), moveStack[msp-1] |= DEFER; // use promoSuppress flag as e.p. flag
1237 1238