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