Fix mamer crash on listmanagers command
[capablanca.git] / lasker-2.2.3 / src / board.c
1 /*
2    Copyright (c) 1993 Richard V. Nash.
3    Copyright (c) 2000 Dan Papasian
4    Copyright (C) Andrew Tridgell 2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22
23 #include "includes.h"
24
25
26 const char *wpstring[] = {" ", "P", "N", "B", "R", "A", "C", "M", "Q", "E", "B", "Q", "W", "H", "N", "D", "H", "L", 
27                           "C", "S", "G", "H", "A", "F", "E", "H", "M", "S", "E", "W", "O", "G", "V", "S", "E", "A", "K"};
28 const char *bpstring[] = {" ", "p", "n", "b", "r", "a", "c", "m", "q", "e", "b", "q", "w", "h", "n", "d", "h", "l", 
29                           "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a", "k"};
30
31 int pieceValues[KING+1] = {0, 1, 3, 3, 5, 8, 9, 3, 9, 1, 1, 2, 2, 2, 1, 6, 5, 2, 3, 3, 3, 1, 5, 2, 1, 7, 7, 3, 3, 3, 7, 7, 7, 8, 9, 12, 0};
32
33 static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11);
34 #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0)
35
36 static char bstring[MAX_BOARD_STRING_LENGTH];
37
38 static int board_read_file(char *category, char *gname, struct game_state_t *gs);
39 static void wild_update(board_t b, int style);
40
41 static int style1(struct game_state_t *b, struct move_t *ml);
42 static int style2(struct game_state_t *b, struct move_t *ml);
43 static int style3(struct game_state_t *b, struct move_t *ml);
44 static int style4(struct game_state_t *b, struct move_t *ml);
45 static int style5(struct game_state_t *b, struct move_t *ml);
46 static int style6(struct game_state_t *b, struct move_t *ml);
47 static int style7(struct game_state_t *b, struct move_t *ml);
48 static int style8(struct game_state_t *b, struct move_t *ml);
49 static int style9(struct game_state_t *b, struct move_t *ml);
50 static int style10(struct game_state_t *b, struct move_t *ml);
51 static int style11(struct game_state_t *b, struct move_t *ml);
52 static int style12(struct game_state_t *b, struct move_t *ml);
53 static int style13(struct game_state_t *b, struct move_t *ml);
54
55 static int (*styleFuncs[MAX_STYLES])() = {
56         style1,
57         style2,
58         style3,
59         style4,
60         style5,
61         style6,
62         style7,
63         style8,
64         style9,
65         style10,
66         style11,
67         style12,
68         style13
69 };
70
71
72 static void reset_board_vars(struct game_state_t *gs)
73 {
74  int f,r;
75
76   if(gs->files <= 0) gs->files = 8; // [HGM] for pristine board, set default size
77   if(gs->ranks <= 0) gs->ranks = 8;
78   for (f = 0; f < 2; f++) {
79     for (r = 0; r < BW; r++)
80       gs->ep_possible[f][r] = 0;
81     for (r = PAWN; r <= KING-1; r++)
82       gs->holding[f][r-PAWN] = 0;
83   }
84   gs->wkmoved = gs->wqrmoved = gs->wkrmoved = -1; // [HGM] castle: no rights
85   gs->bkmoved = gs->bqrmoved = gs->bkrmoved = -1;
86   gs->onMove = WHITE;
87   gs->moveNum = 1;
88   gs->lastIrreversable = -1;
89   gs->gameNum = -1;
90 }
91
92 void board_clear(struct game_state_t *gs)
93 {
94  int f,r;
95
96  for (f = 0; f < BW; f++)
97     for (r = 0; r < BH; r++)
98       gs->board[f][r] = NOPIECE;
99  reset_board_vars(gs);
100 }
101
102 void board_standard(struct game_state_t *gs)
103 {
104  int f,r;
105
106  for (f = 0; f < BW; f++)\r
107     for (r = 0; r < BH; r++)\r
108       gs->board[f][r] = NOPIECE;\r
109  for (f = 0; f < gs->files; f++)\r
110    gs->board[f][gs->ranks-7] = W_PAWN;\r
111  for (f = 0; f < gs->files; f++)\r
112    gs->board[f][6] = B_PAWN;\r
113  gs->board[0][0] = W_ROOK;\r
114  gs->board[1][0] = W_KNIGHT;\r
115  gs->board[2][0] = W_BISHOP; \r
116  gs->board[3][0] = W_QUEEN;\r
117  gs->board[gs->files/2][0] = W_KING;\r
118  gs->board[gs->files-3][0] = W_BISHOP;\r
119  gs->board[gs->files-2][0] = W_KNIGHT;\r
120  gs->board[gs->files-1][0] = W_ROOK;\r
121  gs->board[0][gs->ranks-1] = B_ROOK;\r
122  gs->board[1][gs->ranks-1] = B_KNIGHT;\r
123  gs->board[2][gs->ranks-1] = B_BISHOP;\r
124  gs->board[3][gs->ranks-1] = B_QUEEN;\r
125  gs->board[gs->files/2][gs->ranks-1] = B_KING;\r
126  gs->board[gs->files-3][gs->ranks-1] = B_BISHOP;\r
127  gs->board[gs->files-2][gs->ranks-1] = B_KNIGHT;\r
128  gs->board[gs->files-1][gs->ranks-1] = B_ROOK;\r
129 #if 1
130  if(gs->files == 10) {\r
131   gs->board[6][0] = W_CARDINAL;\r
132   gs->board[4][0] = W_MARSHALL;\r
133   gs->board[6][gs->ranks-1] = B_CARDINAL;\r
134   gs->board[4][gs->ranks-1] = B_MARSHALL;\r
135  }\r
136  if(gs->royalKnight) {\r
137    gs->board[1][0] = W_MAN;\r
138    gs->board[gs->files-2][0] = W_MAN;\r
139    gs->board[1][gs->ranks-1] = B_MAN;\r
140    gs->board[gs->files-2][gs->ranks-1] = B_MAN;\r
141  }\r
142 #endif
143
144  reset_board_vars(gs);
145  // [HGM] castle: standard setup has rights for corner Rooks and central King
146  gs->wkmoved = gs->files/2;
147  gs->bkmoved = gs->files/2;
148  gs->wkrmoved = gs->files-1;
149  gs->bkrmoved = gs->files-1;
150  gs->wqrmoved = 0;
151  gs->bqrmoved = 0;
152 }
153
154 int board_init(int g,struct game_state_t *b, char *category, char *board)
155 {
156   int retval = 0;
157   int wval, i, j;
158
159   b->files = b->ranks = 8;\r
160   b->pawnDblStep = (!category || strcmp(category, "shatranj")); \r
161   b->royalKnight = (category && !strcmp(category, "knightmate"));\r
162   b->capablancaPieces = 0;
163   b->holdings = 0;
164   b->drops = 0;
165   b->castlingStyle = 1;
166   b->palace = 0;
167   b->setup = 0;
168   b->bareKingLoses = 0;
169   b->stalemate = 1;
170   b->promoType = 1;
171   b->promoZone = 1;
172   b->variant[0] = 0; // [HGM] variant: default is normal, if variant name is missing\r
173   if (!category || !board || !category[0] || !board[0]) \r
174                                 /* accounts for bughouse too */\r
175     board_standard(b);\r
176   else {
177     if(category && category[0]) strcpy(b->variant, category); // [HGM] variant: remember category name\r
178     if (!strcmp(category, "wild") && sscanf(board, "%d", &wval) == 1) {
179         if(wval >= 1 && wval <= 4)\r
180             wild_update(b->board, wval);
181         sprintf(b->variant, "wild/%d", wval);\r
182     }
183
184     if (board && !strcmp(board, "0"))
185         b->setup = 0; // [HGM] variant: any board in the default file "0" is supposed to be implied by the variant\r
186
187     if (!strcmp(category, "knightmate")) {\r
188       board_standard(b);\r
189     } else if (!strcmp(category, "super")) {\r
190       board_standard(b);
191       b->holdings = 1;
192       b->promoType = 2;
193       for(i=CENTAUR; i<=AMAZON; i++) {
194         int placed = 0;
195         do { int p, newp;
196           j = random() % 8;
197           if((p = piecetype(b->board[j][0])) >= CENTAUR) continue; // includes King
198           b->holding[1][p-PAWN] = ++b->holding[0][p-PAWN]; // piece to holding
199           if(board && !strcmp(board, "1")) newp = i - CENTAUR + WOODY; else newp = i;
200           if(board && !strcmp(board, "2")) newp = WOODY + random()%7;
201           b->board[j][0] = newp | WHITE; // place replacements
202           b->board[j][7] = newp | BLACK;
203           placed = 1;
204         } while(!placed);
205       }
206       b->setup = 1;\r
207     } else if (!strcmp(category, "fischerandom")) {\r
208       wild_update(b->board, 22);
209       b->castlingStyle = 2;
210       b->setup = 1; // [HGM] FRC: even the default is a setup position, for which an initial board has to be printed\r
211     } else if (!strcmp(category, "caparandom")) {
212       b->files = 10;\r
213       wild_update(b->board, 46);
214       b->castlingStyle = 2;
215       b->setup = 1; \r
216     } else retval = board_read_file(category, board, b); \r
217   }
218   if(b->setup && game_globals.garray[g].FENstartPos[0])  // [HGM] use pre-existing start position, if one available
219     FEN_to_board(game_globals.garray[g].FENstartPos, b); //       (could be wild board, or shuffle variant)
220   if(b->castlingStyle == 1) {
221     b->wkmoved = b->files/2;
222     b->bkmoved = b->files/2;
223     b->wkrmoved = b->files-1;
224     b->bkrmoved = b->files-1;
225     b->wqrmoved = 0;
226     b->bqrmoved = 0;
227   } else if(b->castlingStyle == 2) {
228     for(i=j=0; i < b->files; i++) {
229       int p = b->board[i][0];
230       if(p == W_ROOK || p == W_KING) {
231         switch(j++) {
232           case 0: b->wqrmoved = b->bqrmoved = i; break;
233           case 1: b->wkmoved  = b->bkmoved  = i; break;
234           case 2: b->wkrmoved = b->bkrmoved = i; break;
235         }
236       }
237     }
238   }
239 \r
240   MakeFENpos(g, game_globals.garray[g].FENstartPos);
241
242   return retval;
243 }
244
245 void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
246 {
247   int r, f;
248   int *p;
249
250   *ws = *bs = 0;
251   for (f = 0; f < b->ranks; f++) {
252     for (r = 0; r < b->files; r++) {
253       if (colorval(b->board[r][f]) == WHITE)
254         p = ws;
255       else
256         p = bs;
257       *p += pieceValues[piecetype(b->board[r][f])];
258     }
259   }
260   for (r = PAWN; r < KING; r++) {
261     *ws += b->holding[0][r-1] * pieceValues[r];
262     *bs += b->holding[1][r-1] * pieceValues[r];
263   }
264 }
265
266 static char *holding_str(int *holding)
267 {
268         static char tmp[80];
269         int p,i,j;
270
271         i = 0;
272         for (p = PAWN; p < KING; p++) {
273                 for (j = 0; j < holding[p-1]; j++) {
274                         tmp[i++] = wpstring[p][0];
275                 }
276         }
277         tmp[i] = '\0';
278         return tmp;
279 }
280
281 static char *append_holding_machine(char *buf, int g, int c, int p)
282 {
283   struct game_state_t *gs = &game_globals.garray[g].game_state;
284   char tmp[160];
285
286   sprintf(tmp, "<b1> game %d white [%s] black [", g+1, holding_str(gs->holding[0]));
287   strcat(tmp, holding_str(gs->holding[1]));
288   strcat(buf, tmp);
289   if (p) {
290     sprintf(tmp, "] <- %c%s\n", "WB"[c], wpstring[p]);
291     strcat(buf, tmp);
292   } else
293     strcat(buf, "]\n");
294   return buf;
295 }
296
297 static char *append_holding_display(char *buf, struct game_state_t *gs, int white)
298 {
299   if (white)
300     strcat(buf, "White holding: [");
301   else
302     strcat(buf, "Black holding: [");
303   strcat(buf, holding_str(gs->holding[white ? 0 : 1]));
304   strcat(buf, "]\n");
305   return buf;
306 }
307
308 void update_holding(int g, int pieceCaptured)
309 {
310   int p = piecetype(pieceCaptured);
311   int c = colorval(pieceCaptured);
312   struct game_state_t *gs = &game_globals.garray[g].game_state;
313   int pp, pl;
314   char tmp1[160], tmp2[160];
315
316   if (c == WHITE) {
317     c = 0;
318     pp = game_globals.garray[g].white;
319   } else {
320     c = 1;
321     pp = game_globals.garray[g].black;
322   }
323   gs->holding[c][p-1]++;
324   tmp1[0] = '\0';
325   append_holding_machine(tmp1, g, c, p);
326   sprintf(tmp2, "Game %d %s received: %s -> [%s]\n", g+1,
327           player_globals.parray[pp].name, wpstring[p], holding_str(gs->holding[c]));
328   for (pl = 0; pl < player_globals.p_num; pl++) {
329     if (player_globals.parray[pl].status == PLAYER_EMPTY)
330       continue;
331     if (player_is_observe(pl, g) || (player_globals.parray[pl].game == g)) {
332       pprintf_prompt(pl, IsMachineStyle(player_globals.parray[pl].style) ? tmp1 : tmp2);
333         }
334   }
335 }
336
337
338 /* Globals used for each board */
339 static int wTime, bTime;
340 static int orient;
341 static int forPlayer;
342 static int myTurn;              /* 1 = my turn, 0 = observe, -1 = other turn */
343  /* 2 = examiner, -2 = observing examiner */
344  /* -3 = just send position (spos/refresh) */
345
346 char *board_to_string(char *wn, char *bn,
347                       int wt, int bt,
348                       struct game_state_t *b, struct move_t *ml, int style,
349                       int orientation, int relation,
350                       int p)
351 {
352   int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0
353              || b->holdings ); // [HGM] zh: make sure holdings are printed
354   orient = orientation;
355   myTurn = relation;
356
357   wTime = 0;
358   bTime = 0;
359
360   /* when examining we calculate times based on the time left when the 
361      move happened, not current time */
362   if (game_globals.garray[b->gameNum].status == GAME_EXAMINE) {
363           unsigned nhm = game_globals.garray[b->gameNum].numHalfMoves;
364
365           if (nhm > 0) {
366                   wTime = ml[nhm - 1].wTime;
367                   bTime = ml[nhm - 1].bTime;
368           } else {
369                   wTime = game_globals.garray[b->gameNum].wInitTime;
370                   bTime = game_globals.garray[b->gameNum].bInitTime;
371           }
372   }
373
374   /* cope with old stored games */
375   if (wTime == 0) wTime = wt;
376   if (bTime == 0) bTime = bt;
377
378   forPlayer = p;
379   if ((style < 0) || (style >= MAX_STYLES))
380     return NULL;
381
382   if (style != 11) {            /* game header */
383     sprintf(bstring, "Game %d (%s vs. %s)\n\n",
384           b->gameNum + 1,
385           game_globals.garray[b->gameNum].white_name,
386           game_globals.garray[b->gameNum].black_name);
387   } else
388     bstring[0] = '\0';
389   if (bh && !IsMachineStyle(style))
390     append_holding_display(bstring, b, orientation==BLACK);
391
392   if (styleFuncs[style] (b, ml))
393     return NULL;
394
395   if (bh) {
396     if (IsMachineStyle(style))
397       append_holding_machine(bstring, b->gameNum, 0, 0);
398     else
399       append_holding_display(bstring, b, orientation==WHITE);
400   }
401   return bstring;
402 }
403
404 char *move_and_time(struct move_t *m)
405 {
406         static char tmp[20];
407 #if 0
408         if(m->depth>0)
409              sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */
410                                         m->score>0 ? "+" : "", m->score, m->depth);
411         else 
412 #endif
413         sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
414         return tmp;
415 }
416
417 /* The following take the game state and whole move list */
418
419 void Enlarge(char *a, int ss, int w)
420 {
421   int l, i;
422   char *p, *q;
423   if(strlen(a) < ss) return;
424   for(i=8; i<w; i++) {
425     l = strlen(a);
426     p = a + l; q = p + ss;
427     while(q != a+l-ss) *q-- = *p--;
428   }
429 }
430
431 static int genstyle(struct game_state_t *b, struct move_t *ml, const char *wp[], const char *bp[],
432                     const char *wsqr, const char *bsqr,
433                     const char *top, const char *mid, const char *start, const char *end, 
434                     const char *label,const char *blabel)
435 {
436   int f, r, count, i;\r
437   char tmp[80], mylabel[80], *p, *q, myTop[80], myMid[80];\r
438   int firstR, lastR, firstF, lastF, inc;\r
439   int ws, bs, sqrSize = strlen(wp[0]);\r
440 \r
441   board_calc_strength(b, &ws, &bs);\r
442   if (orient == WHITE) {\r
443     firstR = b->ranks-1;\r
444     firstF = b->files-1;\r
445     lastR = lastF = 0;\r
446     inc = -1;\r
447   } else {\r
448     firstR = firstF = 0;\r
449     lastR = b->ranks-1;\r
450     lastF = b->files-1;\r
451     inc = 1;\r
452   }
453   strcpy(myTop, top);
454   strcpy(myMid, mid);
455   Enlarge(myTop, sqrSize, b->files);\r
456   Enlarge(myMid, sqrSize, b->files);\r
457   strcat(bstring, myTop);\r
458   for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) {\r
459     sprintf(tmp, "     %d  %s", f + (b->ranks < 10), start);\r
460     strcat(bstring, tmp);\r
461     for (r = lastF; r != firstF - inc; r = r - inc) {\r
462       if (square_color(r, f) == WHITE)\r
463         strcat(bstring, wsqr);\r
464       else\r
465         strcat(bstring, bsqr);\r
466       if (piecetype(b->board[r][f]) == NOPIECE) {\r
467         if (square_color(r, f) == WHITE)\r
468           strcat(bstring, bp[0]);\r
469         else\r
470           strcat(bstring, wp[0]);\r
471       } else {
472         int piece = piecetype(b->board[r][f]);
473 //      if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles\r
474         if (colorval(b->board[r][f]) == WHITE)\r
475           strcat(bstring, wp[piece]);\r
476         else\r
477           strcat(bstring, bp[piece]);\r
478       }\r
479     }\r
480     sprintf(tmp, "%s", end);\r
481     strcat(bstring, tmp);\r
482     switch (count) {\r
483     case 7:\r
484       sprintf(tmp, "     Move # : %d (%s)", b->moveNum, CString(b->onMove));\r
485       strcat(bstring, tmp);\r
486       break;\r
487     case 6:\r
488 /*    if ((b->moveNum > 1) || (b->onMove == BLACK)) {  */\r
489 /* The change from the above line to the one below is a kludge by hersco. */\r
490       if (game_globals.garray[b->gameNum].numHalfMoves > 0) {\r
491 /* loon: think this fixes the crashing ascii board on takeback bug */\r
492         sprintf(tmp, "     %s Moves : '%s'", CString(CToggle(b->onMove)),\r
493                 move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));\r
494         strcat(bstring, tmp);\r
495       }\r
496       break;\r
497     case 5:\r
498       break;\r
499     case 4:\r
500       sprintf(tmp, "     Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));\r
501       strcat(bstring, tmp);\r
502       break;\r
503     case 3:\r
504       sprintf(tmp, "     White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));\r
505       strcat(bstring, tmp);\r
506       break;\r
507     case 2:\r
508       sprintf(tmp, "     Black Strength : %d", bs);\r
509       strcat(bstring, tmp);\r
510       break;\r
511     case 1:\r
512       sprintf(tmp, "     White Strength : %d", ws);\r
513       strcat(bstring, tmp);\r
514       break;\r
515     case 0:\r
516       break;\r
517     }\r
518     strcat(bstring, "\n");\r
519     if (count != 0)\r
520       strcat(bstring, myMid);\r
521     else\r
522       strcat(bstring, myTop);\r
523   }\r
524   q = mylabel; i = 0;
525   if (orient == WHITE) {\r
526     p = label;
527     while(*p) {
528         switch(*p) {
529           case ' ':
530           case '\t':
531           case '\n':
532                 *q++ = *p++; break;
533           default:
534                 if(++i > b->files) { *q++ = '\n'; *q++ = 0; }
535                 *q++ = *p++;
536         }
537     }
538   } else {
539     p = blabel;
540     while(*p) {
541         switch(*p) {
542           case ' ':
543           case '\t':
544           case '\n':
545                 *q++ = *p++; break;
546           default:
547                 *q++ = *p++ + b->files - 12;
548                 if(++i >= b->files) { *q++ = '\n'; *q++ = 0; }
549         }
550     }\r
551   }\r
552   *q++ = 0;
553   strcat(bstring, mylabel);\r
554   return 0;\r
555 }
556
557 /* Experimental ANSI board for colour representation */\r
558 static int style13(struct game_state_t *b, struct move_t *ml)\r
559 {\r
560   static const char *wp[] = {"   ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m A ", "\033[37m\033[1m C ", "\033[37m\033[1m M ", "\033[37m\033[1m Q ", "\033[37m\033[1m E ", "\033[37m\033[1m K "};\r
561   static const char *bp[] = {"   ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m A ", "\033[21m\033[37m C ", "\033[21m\033[37m M ", "\033[21m\033[37m Q ", "\033[21m\033[37m E ", "\033[21m\033[37m K "};\r
562   static const char *wsqr = "\033[40m";\r
563   static const char *bsqr = "\033[45m";\r
564   static const char *top = "\t+------------------------+\n";\r
565   static const char *mid = "";\r
566   static const char *start = "|";\r
567   static const char *end = "\033[0m|";\r
568   static const char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
569   static const char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
570 return 0;\r
571   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
572 }\r
573 \r
574 /* Standard ICS */\r
575 static int style1(struct game_state_t *b, struct move_t *ml)\r
576 {\r
577   static const char *wp[] = {"   |", " P |", " N |", " B |", " R |", " A |", " C |", " M |", " Q |", " E |", " B |", " Q |", 
578                              " W |", " H |", " N |", " D |", " H |", " L |", " C |", " S |", " G |", " H |", " A |", " F |",
579                              " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", " K |"};
580   static const char *bp[] = {"   |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|", 
581                              " *W|", " *H|", " *N|", " *D|", " *H|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|",
582                              " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", " *K|"};
583   static char *wsqr = "";\r
584   static char *bsqr = "";\r
585   static char *top = "\t---------------------------------\n";\r
586   static char *mid = "\t|---+---+---+---+---+---+---+---|\n";\r
587   static char *start = "|";\r
588   static char *end = "";\r
589   static char *label = "\t  a   b   c   d   e   f   g   h   i   j   k   l\n";\r
590   static char *blabel = "\t  l   k   j   i   h   g   f   e   d   c   b   a\n";\r
591 \r
592   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
593 }\r
594 \r
595 /* USA-Today Sports Center-style board */\r
596 static int style2(struct game_state_t *b, struct move_t *ml)\r
597 {\r
598   static const char *wp[] = {"-  ", "P  ", "N  ", "B  ", "R  ", "A  ", "C  ", "M  ", "Q  ", "E  ", "B  ", "Q  ",
599                              "W  ", "H  ", "N  ", "D  ", "H  ", "L  ", "C  ", "S  ", "G  ", "H  ", "A  ", "F  ",
600                              "E  ", "H  ", "M  ", "S  ", "E  ", "W  ", "O  ", "G  ", "V  ", "S  ", "E  ", "A  ", "K  "};
601   static const char *bp[] = {"+  ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ",
602                              "w' ", "h' ", "n' ", "d' ", "h' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ",
603                              "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", "k' "};
604   static char *wsqr = "";\r
605   static char *bsqr = "";\r
606   static char *top = "";\r
607   static char *mid = "";\r
608   static char *start = "";\r
609   static char *end = "";\r
610   static char *label = "\ta  b  c  d  e  f  g  h  i  j  k  l\n";\r
611   static char *blabel = "\tl  k  j  i  h  g  f  e  d  c  b  a\n";\r
612 \r
613   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
614 }\r
615 \r
616 /* Experimental vt-100 ANSI board for dark backgrounds */\r
617 static int style3(struct game_state_t *b, struct move_t *ml)\r
618 {\r
619   static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", 
620                              " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
621                              " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "};
622   static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", 
623                              " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
624                              " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"};
625   static char *wsqr = "\033[0m";\r
626   static char *bsqr = "\033[7m";\r
627   static char *top = "\t+------------------------+\n";\r
628   static char *mid = "";\r
629   static char *start = "|";\r
630   static char *end = "\033[0m|";\r
631   static char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
632   static char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
633 \r
634   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
635 }\r
636 \r
637 /* Experimental vt-100 ANSI board for light backgrounds */\r
638 static int style4(struct game_state_t *b, struct move_t *ml)\r
639 {\r
640   static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", 
641                              " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
642                              " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "};
643   static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", 
644                              " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
645                              " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"};
646   static char *wsqr = "\033[7m";\r
647   static char *bsqr = "\033[0m";\r
648   static char *top = "\t+------------------------+\n";\r
649   static char *mid = "";\r
650   static char *start = "|";\r
651   static char *end = "\033[0m|";\r
652   static char *label = "\t  a  b  c  d  e  f  g  h  i  j  k  l\n";\r
653   static char *blabel = "\t  l  k  j  i  h  g  f  e  d  c  b  a\n";\r
654 \r
655   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
656 }\r
657 \r
658 /* Style suggested by ajpierce@med.unc.edu */\r
659 static int style5(struct game_state_t *b, struct move_t *ml)\r
660 {\r
661   static const char *wp[] = {"    ", "  o ", " :N:", " <B>", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!",
662                              " <B>", " {Q}", " .W.", " :H:", " :N:", " <H>", " |D|", " |L|", 
663                              " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:",
664                              " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", " =K="};
665   static const char *bp[] = {"    ", "  p ", " :n:", " <b>", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!",
666                              " <b>", " {q}", " .w.", " :h:", " :n:", " <h>", " |d|", " |l|", 
667                              " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:",
668                              " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", " =k="};
669   static char *wsqr = "";\r
670   static char *bsqr = "";\r
671   static char *top = "        .   .   .   .   .   .   .   .   .\n";\r
672   static char *mid = "        .   .   .   .   .   .   .   .   .\n";\r
673   static char *start = "";\r
674   static char *end = "";\r
675   static char *label = "\t  a   b   c   d   e   f   g   h   i   j   k   l\n";\r
676   static char *blabel = "\t  l   k   j   i   h   g   f   e   d   c   b   a\n";\r
677 \r
678   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
679 }\r
680 \r
681 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */\r
682 static int style6(struct game_state_t *b, struct move_t *ml)\r
683 {\r
684   static const char *wp[] = {"    |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |", 
685                              " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WD |", " WH |", " WL |", 
686                              " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |", 
687                              " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", " WK |"};
688   static const char *bp[] = {"    |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |", 
689                              " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BD |", " BH |", " BL |", 
690                              " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |", 
691                              " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", " BK |"};
692   static char *wsqr = "";\r
693   static char *bsqr = "";\r
694   static char *top = "\t-----------------------------------------\n";\r
695   static char *mid = "\t-----------------------------------------\n";\r
696   static char *start = "|";\r
697   static char *end = "";\r
698   static char *label = "\t  A    B    C    D    E    F    G    H    I    J    K    L\n";\r
699   static char *blabel = "\t  L    K    J    I    H    G    F    E    D    C    B    A\n";\r
700 \r
701   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
702 }\r
703 \r
704 /* Miniature board */\r
705 static int style7(struct game_state_t *b, struct move_t *ml)\r
706 {\r
707   static const char *wp[] = {"  ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " D", " H", " L", 
708                              " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", " K"};
709   static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " d", " h", " l", 
710                              " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k"};
711   static char *wsqr = "";\r
712   static char *bsqr = "";\r
713   static char *top = "\t:::::::::::::::::::::\n";\r
714   static char *mid = "";\r
715   static char *start = "..";\r
716   static char *end = " ..";\r
717   static char *label = "\t   a b c d e f g h i j k l\n";\r
718   static char *blabel = "\t   l k j i h g f e d c b a\n";\r
719 \r
720   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);\r
721 }\r
722
723 /* ICS interface maker board-- raw data dump */\r
724 static int style8(struct game_state_t *b, struct move_t *ml)\r
725 {\r
726   char tmp[160];\r
727   int f, r;\r
728   int ws, bs;\r
729 \r
730   board_calc_strength(b, &ws, &bs);\r
731   sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,\r
732           game_globals.garray[b->gameNum].white_name,\r
733           (orient == WHITE) ? "*" : ":",\r
734           game_globals.garray[b->gameNum].black_name,\r
735           (orient == WHITE) ? ":" : "*");\r
736   strcat(bstring, tmp);\r
737   for (r = 0; r < b->ranks; r++) {\r
738     for (f = 0; f < b->files; f++) {\r
739       if (b->board[f][r] == NOPIECE) {\r
740         strcat(bstring, " ");\r
741       } else {\r
742         if (colorval(b->board[f][r]) == WHITE)\r
743           strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
744         else\r
745           strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
746       }\r
747     }\r
748   }\r
749   sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",\r
750           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
751           (b->onMove == WHITE) ? "W" : "B",\r
752           ws,\r
753           bs,\r
754           (wTime + 5) / 10,\r
755           (bTime + 5) / 10,\r
756           game_globals.garray[b->gameNum].numHalfMoves ?\r
757           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :\r
758           "none",\r
759           game_globals.garray[b->gameNum].numHalfMoves ?\r
760           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
761           "0:00");\r
762   strcat(bstring, tmp);\r
763   return 0;\r
764 }\r
765 \r
766 /* last 2 moves only (previous non-verbose mode) */\r
767 static int style9(struct game_state_t *b, struct move_t *ml)\r
768 {\r
769   int i, count;\r
770   char tmp[160];\r
771   int startmove;\r
772 \r
773   sprintf(tmp, "\nMove     %-23s%s\n",\r
774           game_globals.garray[b->gameNum].white_name,\r
775           game_globals.garray[b->gameNum].black_name);\r
776   strcat(bstring, tmp);\r
777   sprintf(tmp, "----     --------------         --------------\n");\r
778   strcat(bstring, tmp);\r
779   startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;\r
780   if (startmove < 0)\r
781     startmove = 0;\r
782   for (i = startmove, count = 0;\r
783        i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;\r
784        i++, count++) {\r
785     if (!(i & 0x01)) {\r
786       sprintf(tmp, "  %2d     ", i / 2 + 1);\r
787       strcat(bstring, tmp);\r
788     }\r
789     sprintf(tmp, "%-23s", move_and_time(&ml[i]));\r
790     strcat(bstring, tmp);\r
791     if (i & 0x01)\r
792       strcat(bstring, "\n");\r
793   }\r
794   if (i & 0x01)\r
795     strcat(bstring, "\n");\r
796   return 0;\r
797 }\r
798 \r
799 /* Sleator's 'new and improved' raw dump format... */\r
800 static int style10(struct game_state_t *b, struct move_t *ml)\r
801 {\r
802   int f, r;\r
803   char tmp[160];\r
804   int ws, bs;\r
805 \r
806   board_calc_strength(b, &ws, &bs);\r
807   sprintf(tmp, "<10>\n");\r
808   strcat(bstring, tmp);\r
809   for (r = b->ranks-1; r >= 0; r--) {\r
810     strcat(bstring, "|");\r
811     for (f = 0; f < b->files; f++) {\r
812       if (b->board[f][r] == NOPIECE) {\r
813         strcat(bstring, " ");\r
814       } else {\r
815         if (colorval(b->board[f][r]) == WHITE)\r
816           strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
817         else\r
818           strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
819       }\r
820     }\r
821     strcat(bstring, "|\n");\r
822   }\r
823   strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");\r
824   if (game_globals.garray[b->gameNum].numHalfMoves) {\r
825     sprintf(tmp, "%d ",\r
826             ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);\r
827   } else {\r
828     sprintf(tmp, "-1 ");\r
829   }\r
830   strcat(bstring, tmp);\r
831   sprintf(tmp, "%d %d %d %d %d\n",\r
832           (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights\r
833           (b->wkmoved >= 0 && b->wqrmoved >= 0),\r
834           (b->bkmoved >= 0 && b->bkrmoved >= 0),\r
835           (b->bkmoved >= 0 && b->bqrmoved >= 0),\r
836        (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :\r
837                                            b->lastIrreversable)));\r
838   strcat(bstring, tmp);\r
839   sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",\r
840           b->gameNum,\r
841           game_globals.garray[b->gameNum].white_name,\r
842           game_globals.garray[b->gameNum].black_name,\r
843           myTurn,\r
844           game_globals.garray[b->gameNum].wInitTime / 600,\r
845           game_globals.garray[b->gameNum].wIncrement / 10,\r
846           ws,\r
847           bs,\r
848           (wTime + 5) / 10,\r
849           (bTime + 5) / 10,\r
850           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
851           game_globals.garray[b->gameNum].numHalfMoves ?\r
852           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :\r
853           "none",\r
854           game_globals.garray[b->gameNum].numHalfMoves ?\r
855           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
856           "0:00",\r
857           game_globals.garray[b->gameNum].numHalfMoves ?\r
858           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :\r
859           "none",\r
860           (orient == WHITE) ? 0 : 1);\r
861   strcat(bstring, tmp);\r
862   sprintf(tmp, ">10<\n");\r
863   strcat(bstring, tmp);\r
864   return 0;\r
865 }\r
866 \r
867 /* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */\r
868 static int style11(struct game_state_t *b, struct move_t *ml)\r
869 {\r
870   char tmp[160];\r
871   int f, r;\r
872   int ws, bs;\r
873 \r
874   board_calc_strength(b, &ws, &bs);\r
875   sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,\r
876           game_globals.garray[b->gameNum].white_name,\r
877           (orient == WHITE) ? "*" : ":",\r
878           game_globals.garray[b->gameNum].black_name,\r
879           (orient == WHITE) ? ":" : "*");\r
880   strcat(bstring, tmp);\r
881   for (r = 0; r < b->ranks; r++) {\r
882     for (f = 0; f < b->files; f++) {\r
883       if (b->board[f][r] == NOPIECE) {\r
884         strcat(bstring, " ");\r
885       } else {\r
886         if (colorval(b->board[f][r]) == WHITE)\r
887           strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
888         else\r
889           strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
890       }\r
891     }\r
892   }\r
893     sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",\r
894             game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,\r
895             (b->onMove == WHITE) ? "W" : "B",\r
896             ws,\r
897             bs,\r
898             (wTime + 5) / 10,\r
899             (bTime + 5) / 10,\r
900             game_globals.garray[b->gameNum].numHalfMoves ?\r
901             ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :\r
902             "none",\r
903             game_globals.garray[b->gameNum].numHalfMoves ?\r
904             tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :\r
905             "0:00");\r
906   strcat(bstring, tmp);\r
907   return 0;\r
908 }\r
909
910
911 int kludgeFlag = 0; \r
912 /* Similar to style 10.  See the "style12" help file for information */\r
913 static int style12(struct game_state_t *b, struct move_t *ml)\r
914 {\r
915   int f, r;\r
916   char tmp[160]; // [HGM] 80 caused problems with long login names\r
917   int ws, bs; 
918   int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves; 
919   // [HGM] setup: the number of half moves appeared in this routine an enormous number of times,
920   // and had to be dug out of the game_globals, so that this routine could only be used to print
921   // a board from a game, and not just any board given by an isolated game_state_t. This was very
922   // inconvenient for printing initial boards in move lists of shuffle variants, so I added the
923   // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0.\r
924 \r
925   board_calc_strength(b, &ws, &bs);\r
926 \r
927   sprintf(bstring, "<12> ");\r
928   for (r = b->ranks-1; r >= 0; r--) {\r
929     for (f = 0; f < b->files; f++) {
930       if (b->board[f][r] == NOPIECE) {\r
931         strcat(bstring, "-");\r
932       } else {\r
933         if (colorval(b->board[f][r]) == WHITE)\r
934           strcat(bstring, wpstring[piecetype(b->board[f][r])]);\r
935         else\r
936           strcat(bstring, bpstring[piecetype(b->board[f][r])]);\r
937       }\r
938     }\r
939     strcat(bstring, " ");\r
940   }
941 \r
942   strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");\r
943   if (nhm) {\r
944     sprintf(tmp, "%d ",\r
945             ml[nhm - 1].doublePawn);\r
946   } else {\r
947     sprintf(tmp, "-1 ");\r
948   }\r
949   strcat(bstring, tmp);\r
950   sprintf(tmp, "%d %d %d %d %d ",\r
951           (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights\r
952           (b->wkmoved >= 0 && b->wqrmoved >= 0),\r
953           (b->bkmoved >= 0 && b->bkrmoved >= 0),\r
954           (b->bkmoved >= 0 && b->bqrmoved >= 0),\r
955           (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));\r
956   strcat(bstring, tmp);
957   sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",\r
958           b->gameNum + 1,\r
959           game_globals.garray[b->gameNum].white_name,\r
960           game_globals.garray[b->gameNum].black_name,\r
961           myTurn,\r
962           game_globals.garray[b->gameNum].wInitTime / 600,\r
963           game_globals.garray[b->gameNum].wIncrement / 10,\r
964           ws,\r
965           bs,\r
966           (wTime / 10),\r
967           (bTime / 10),\r
968           nhm / 2 + 1,\r
969           nhm ?\r
970           ml[nhm - 1].moveString :\r
971           "none",\r
972           nhm ?\r
973           tenth_str(ml[nhm - 1].tookTime, 0) :\r
974           "0:00",\r
975           nhm ?\r
976           ml[nhm - 1].algString :\r
977           "none", (orient == WHITE) ? 0 : 1,\r
978           b->moveNum > 1 ? 1 : 0); /* ticking */\r
979
980   strcat(bstring, tmp);\r
981   return 0;\r
982 }\r
983
984 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
985 {
986   FILE *fp;
987   int c;
988   int onNewLine = 1;
989   int onColor = -1;
990   int onPiece = -1;
991   int onFile = -1;
992   int onRank = -1;
993
994   fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
995   if (!fp)
996     return 1;
997
998   board_clear(gs);
999   gs->setup = 1;
1000   while (!feof(fp)) {
1001     c = fgetc(fp);
1002     if (onNewLine) {
1003       if (c == 'W') {
1004         onColor = WHITE;
1005         if (gs->onMove < 0)
1006           gs->onMove = WHITE;
1007       } else if (c == 'B') {
1008         onColor = BLACK;
1009         if (gs->onMove < 0)
1010           gs->onMove = BLACK;
1011       } else if (c == 'S') { int f=8, r=8;
1012         // [HGM] rules: read rule modifiers
1013         fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r;
1014         while (!feof(fp) && c != '\n') {
1015           c = fgetc(fp);
1016           switch(c) {
1017             case 'r':
1018                 gs->royalKnight = 1;
1019                 break;
1020             case 'c':
1021                 gs->capablancaPieces = 1;
1022                 break;
1023             case 'd':
1024                 gs->drops = 1;
1025                 break;
1026             case 'h':
1027                 gs->holdings = -1;     // color-flip holdings
1028                 break;
1029             case 'p':
1030                 gs->palace = 3;
1031                 break;
1032             case 'P':
1033                 gs->promoType = 2; // only promote to captured pieces
1034                 gs->holdings = 1;  // use holdings to hold own captured pieces
1035                 break;
1036             case 'S':
1037                 gs->promoType = 3; // Shogi-type promotions
1038                 break;
1039             case 'Z':
1040                 gs->promoZone = 3; // for Grand Chess
1041                 gs->pawnDblStep = 2;
1042                 break;
1043             case 'F':
1044                 gs->castlingStyle = 2; // FRC castling
1045                 break;
1046             case 'w':
1047                 gs->castlingStyle = 1; // wild castling, from both center files
1048                 break;
1049             case 'n':
1050                 gs->castlingStyle = 0; // no castling
1051                 break;
1052             case 'f':
1053                 gs->castlingStyle = 3; // free castling
1054                 break;
1055             case 'D':
1056                 gs->pawnDblStep = 0; // suppress pawn double step
1057                 break;
1058             case 'b':
1059                 gs->bareKingLoses = 1; // apply baring rule
1060                 break;
1061             case 's':
1062                 gs->stalemate = 0; // stalemate loses
1063                 break;
1064           }
1065         }       
1066         continue;
1067       } else if (c == '#') {
1068         while (!feof(fp) && c != '\n')
1069           c = fgetc(fp);        /* Comment line */
1070         continue;
1071       } else {                  /* Skip any line we don't understand */
1072         while (!feof(fp) && c != '\n')
1073           c = fgetc(fp);
1074         continue;
1075       }
1076       onNewLine = 0;
1077     } else {
1078       switch (c) {
1079       case 'P':
1080         onPiece = PAWN;
1081         break;
1082       case 'R':
1083         onPiece = ROOK;
1084         break;
1085       case 'N':
1086         onPiece = KNIGHT;
1087         break;
1088       case 'B':
1089         onPiece = BISHOP;
1090         break;
1091       case 'A':\r
1092         onPiece = CARDINAL;\r
1093         break;\r
1094       case 'C':\r
1095         onPiece = MARSHALL;\r
1096         break;\r
1097       case 'M':\r
1098         onPiece = MAN;\r
1099         break;\r
1100       case 'Q':
1101         onPiece = QUEEN;
1102         break;
1103       case 'T':
1104         onPiece = ELEPHANT;
1105         break;
1106       case 'E':
1107         onPiece = ALFIL;
1108         break;
1109       case 't':
1110         onPiece = ALFIL2;
1111         break;
1112       case 'q':
1113         onPiece = FERZ;
1114         break;
1115       case 'F':
1116         onPiece = FERZ2;
1117         break;
1118       case 'W':
1119         onPiece = WAZIR;
1120         break;
1121       case 'w':
1122         onPiece = WOODY;
1123         break;
1124       case 'p':
1125         onPiece = PRIESTESS;
1126         break;
1127       case 'r':
1128         onPiece = MINISTER;
1129         break;
1130       case 'z':
1131         onPiece = MAN2;
1132         break;
1133       case 'u':
1134         onPiece = NIGHTRIDER;
1135         break;
1136       case 'o':
1137         onPiece = MODERNELEPHANT;
1138         break;
1139       case 's':
1140         onPiece = MASTODON;
1141         break;
1142       case 'Z':
1143         onPiece = AMAZON;
1144         break;
1145       case 'V':
1146         onPiece = CENTAUR;
1147         break;
1148       case 'H':
1149         onPiece = HORSE;
1150         break;
1151       case 'n':
1152         onPiece = HONORABLEHORSE;
1153         break;
1154       case 'J':
1155         onPiece = DRAGONKING;
1156         break;
1157       case 'I':
1158         onPiece = DRAGONHORSE;
1159         break;
1160       case 'L':
1161         onPiece = LANCE;
1162         break;
1163       case 'O':
1164         onPiece = CANNON;
1165         break;
1166       case 'S':
1167         onPiece = SILVER;
1168         break;
1169       case 'G':
1170         onPiece = GOLD;
1171         break;
1172       case 'm':
1173         onPiece = MANDARIN;
1174         break;
1175       case 'K':
1176         onPiece = KING;
1177         break;
1178       case 'a':\r
1179       case 'b':\r
1180       case 'c':\r
1181       case 'd':\r
1182       case 'e':\r
1183       case 'f':\r
1184       case 'g':\r
1185       case 'h':\r
1186       case 'i':\r
1187       case 'j':\r
1188       case 'k':\r
1189       case 'l':\r
1190         onFile = c - 'a';\r
1191         if(onFile >= gs->files) { onFile = -1; break; }\r
1192         onRank = -1;\r
1193         break;\r
1194       case '@':
1195         if (onColor >= 0 && onPiece >= 0) // allow placement in holdings\r
1196           gs->holding[onColor == BLACK][onPiece-1]++;
1197         break;\r
1198       case '1':\r
1199       case '2':\r
1200       case '3':\r
1201       case '4':\r
1202       case '5':\r
1203       case '6':\r
1204       case '7':\r
1205       case '8':\r
1206       case '9':\r
1207       case '0':\r
1208         onRank = c - '1' + (gs->ranks > 9);\r
1209         if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; }\r
1210         if (onFile >= 0 && onColor >= 0 && onPiece >= 0)\r
1211           gs->board[onFile][onRank] = onPiece | onColor;\r
1212         break;\r      case '#':
1213         while (!feof(fp) && c != '\n')
1214           c = fgetc(fp);        /* Comment line */
1215       case '\n':
1216         onNewLine = 1;
1217         onColor = -1;
1218         onPiece = -1;
1219         onFile = -1;
1220         onRank = -1;
1221         break;
1222       default:
1223         break;
1224       }
1225     }
1226   }
1227   fclose(fp);
1228   return 0;
1229 }
1230
1231 #define WHITE_SQUARE 1
1232 #define BLACK_SQUARE 0
1233 #define ANY_SQUARE -1
1234 #define SquareColor(f, r) ((f ^ r) & 1)
1235
1236 static void place_piece(board_t b, int piece, int squareColor, int width)
1237 { //[HGM] board: make width a variable
1238   int r, f;
1239   int placed = 0;
1240
1241   if (iscolor(piece, BLACK))
1242     r = 7;
1243   else
1244     r = 0;
1245
1246   while (!placed) {
1247     if (squareColor == ANY_SQUARE) {
1248       f = random() % width;
1249     } else {
1250       f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
1251       if (SquareColor(f, r) != squareColor)
1252         f++;
1253     }
1254     if ((b)[f][r] == NOPIECE) {
1255       (b)[f][r] = piece;
1256       placed = 1;
1257     }
1258   }
1259 }
1260
1261 static void wild_update(board_t b, int style)
1262 {
1263   int f, r, i, j;
1264
1265   for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
1266     for (r = 0; r < 8; r++)
1267       b[f][r] = NOPIECE;
1268   for (f = 0; f < 8; f++) {
1269     b[f][1] = W_PAWN;
1270     b[f][6] = B_PAWN;
1271   }
1272   switch (style) {
1273   case 1:
1274     if (random() & 0x01) {
1275       b[4][0] = W_KING;
1276       b[3][0] = W_QUEEN;
1277     } else {
1278       b[3][0] = W_KING;
1279       b[4][0] = W_QUEEN;
1280     }
1281     if (random() & 0x01) {
1282       b[4][7] = B_KING;
1283       b[3][7] = B_QUEEN;
1284     } else {
1285       b[3][7] = B_KING;
1286       b[4][7] = B_QUEEN;
1287     }
1288     b[0][0] = b[7][0] = W_ROOK;
1289     b[0][7] = b[7][7] = B_ROOK;
1290     /* Must do bishops before knights to be sure opposite colored squares are
1291        available. */
1292     place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1293     place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1294     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1295     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1296     place_piece(b, B_BISHOP, WHITE_SQUARE, 8);
1297     place_piece(b, B_BISHOP, BLACK_SQUARE, 8);
1298     place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1299     place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1300     break;
1301   case 2:
1302     place_piece(b, W_KING, ANY_SQUARE, 8);
1303     place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1304     place_piece(b, W_ROOK, ANY_SQUARE, 8);
1305     place_piece(b, W_ROOK, ANY_SQUARE, 8);
1306     place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1307     place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1308     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1309     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1310     /* Black mirrors White */
1311     for (i = 0; i < 8; i++) {
1312       b[i][7] = b[i][0] | BLACK;
1313     }
1314     break;
1315   case 3:
1316     /* Generate White king on random square plus random set of pieces */
1317     place_piece(b, W_KING, ANY_SQUARE, 8);
1318     for (i = 0; i < 8; i++) {
1319       if (b[i][0] != W_KING) {
1320         b[i][0] = (random() % 4) + 2;
1321       }
1322     }
1323     /* Black mirrors White */
1324     for (i = 0; i < 8; i++) {
1325       b[i][7] = b[i][0] | BLACK;
1326     }
1327     break;
1328   case 4:
1329     /* Generate White king on random square plus random set of pieces */
1330     place_piece(b, W_KING, ANY_SQUARE, 8);
1331     for (i = 0; i < 8; i++) {
1332       if (b[i][0] != W_KING) {
1333         b[i][0] = (random() % 4) + 2;
1334       }
1335     }
1336     /* Black has same set of pieces, but randomly permuted, except that Black
1337        must have the same number of bishops on white squares as White has on
1338        black squares, and vice versa.  So we must place Black's bishops first
1339        to be sure there are enough squares left of the correct color. */
1340     for (i = 0; i < 8; i++) {
1341       if (b[i][0] == W_BISHOP) {
1342         place_piece(b, B_BISHOP, !SquareColor(i, 0), 8);
1343       }
1344     }
1345     for (i = 0; i < 8; i++) {
1346       if (b[i][0] != W_BISHOP) {
1347         place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8);
1348       }
1349     }
1350     break;
1351   case 22:
1352     /* Chess960 placement: King between R */
1353     place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1354     place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1355     place_piece(b, W_QUEEN,  ANY_SQUARE, 8);
1356     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1357     place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1358     for (i = j = 0; i < 8; i++) {
1359       if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK);
1360     }
1361     /* Black mirrors White */
1362     for (i = 0; i < 8; i++) {
1363       b[i][7] = b[i][0] | BLACK;
1364     }
1365     break;
1366   case 46:
1367     /* Chess960 placement: King between R */
1368     place_piece(b, W_BISHOP, WHITE_SQUARE, 10);
1369     place_piece(b, W_BISHOP, BLACK_SQUARE, 10);
1370     place_piece(b, W_QUEEN,  ANY_SQUARE, 10);
1371     place_piece(b, W_MARSHALL, ANY_SQUARE, 10);
1372     place_piece(b, W_CARDINAL, ANY_SQUARE, 10);
1373     place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1374     place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1375     for (i = j = 0; i < 10; i++) {
1376       if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK;
1377     }
1378     /* Black mirrors White */
1379     for (i = 0; i < 10; i++) {
1380       b[i][7] = b[i][0] | BLACK;
1381     }
1382     break;
1383   default:
1384     return;
1385     break;
1386   }
1387   {
1388     FILE *fp;
1389     int onPiece;
1390
1391     fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1392     if (!fp) {
1393       d_printf( "CHESSD: Can't write wild style %d\n", style);
1394       return;
1395     }
1396     fprintf(fp, "W:");
1397     onPiece = -1;
1398     for (r = 1; r >= 0; r--) {
1399       for (f = 0; f < 8; f++) {
1400         if (onPiece < 0 || b[f][r] != onPiece) {
1401           onPiece = b[f][r];
1402           fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1403         }
1404         fprintf(fp, " %c%c", f + 'a', r + '1');
1405       }
1406     }
1407     fprintf(fp, "\nB:");
1408     onPiece = -1;
1409     for (r = 6; r < 8; r++) {
1410       for (f = 0; f < 8; f++) {
1411         if (onPiece < 0 || b[f][r] != onPiece) {
1412           onPiece = b[f][r];
1413           fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1414         }
1415         fprintf(fp, " %c%c", f + 'a', r + '1');
1416       }
1417     }
1418     fprintf(fp, "\n");
1419     fclose(fp);
1420   }
1421 }
1422
1423 void wild_init(void)
1424 {
1425         board_t b;
1426         wild_update(b, 1);
1427         wild_update(b, 2);
1428         wild_update(b, 3);
1429         wild_update(b, 4);
1430 }
1431