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