8fdbb0e4271e0948d720c4f1eb4ba60bdbed04d2
[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", "Q", "K"};
27 static const char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"};
28
29 static int pieceValues[7] = {0, 1, 3, 3, 5, 9, 0};
30
31 static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11);
32 #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0)
33
34 static char bstring[MAX_BOARD_STRING_LEGTH];
35
36 static int board_read_file(char *category, char *gname, struct game_state_t *gs);
37 static void wild_update(int style);
38
39 static int style1(struct game_state_t *b, struct move_t *ml);
40 static int style2(struct game_state_t *b, struct move_t *ml);
41 static int style3(struct game_state_t *b, struct move_t *ml);
42 static int style4(struct game_state_t *b, struct move_t *ml);
43 static int style5(struct game_state_t *b, struct move_t *ml);
44 static int style6(struct game_state_t *b, struct move_t *ml);
45 static int style7(struct game_state_t *b, struct move_t *ml);
46 static int style8(struct game_state_t *b, struct move_t *ml);
47 static int style9(struct game_state_t *b, struct move_t *ml);
48 static int style10(struct game_state_t *b, struct move_t *ml);
49 static int style11(struct game_state_t *b, struct move_t *ml);
50 static int style12(struct game_state_t *b, struct move_t *ml);
51 static int style13(struct game_state_t *b, struct move_t *ml);
52
53 static int (*styleFuncs[MAX_STYLES])() = {
54         style1,
55         style2,
56         style3,
57         style4,
58         style5,
59         style6,
60         style7,
61         style8,
62         style9,
63         style10,
64         style11,
65         style12,
66         style13
67 };
68
69
70 static void reset_board_vars(struct game_state_t *gs)
71 {
72  int f,r;
73
74   for (f = 0; f < 2; f++) {
75     for (r = 0; r < 8; r++)
76       gs->ep_possible[f][r] = 0;
77     for (r = PAWN; r <= QUEEN; r++)
78       gs->holding[f][r-PAWN] = 0;
79   }
80   gs->wkmoved = gs->wqrmoved = gs->wkrmoved = 0;
81   gs->bkmoved = gs->bqrmoved = gs->bkrmoved = 0;
82   gs->onMove = WHITE;
83   gs->moveNum = 1;
84   gs->lastIrreversable = -1;
85   gs->gameNum = -1;
86 }
87
88 void board_clear(struct game_state_t *gs)
89 {
90  int f,r;
91
92  for (f = 0; f < 8; f++)
93     for (r = 0; r < 8; r++)
94       gs->board[f][r] = NOPIECE;
95  reset_board_vars(gs);
96 }
97
98 void board_standard(struct game_state_t *gs)
99 {
100  int f,r;
101
102  for (f = 0; f < 8; f++)
103     for (r = 2; r < 6; r++)
104       gs->board[f][r] = NOPIECE;
105  for (f = 0; f < 8; f++)
106    gs->board[f][1] = W_PAWN;
107  for (f = 0; f < 8; f++)
108    gs->board[f][6] = B_PAWN;
109  gs->board[0][0] = W_ROOK;
110  gs->board[1][0] = W_KNIGHT;
111  gs->board[2][0] = W_BISHOP; 
112  gs->board[3][0] = W_QUEEN;
113  gs->board[4][0] = W_KING;
114  gs->board[5][0] = W_BISHOP;
115  gs->board[6][0] = W_KNIGHT;
116  gs->board[7][0] = W_ROOK;
117  gs->board[0][7] = B_ROOK;
118  gs->board[1][7] = B_KNIGHT;
119  gs->board[2][7] = B_BISHOP;
120  gs->board[3][7] = B_QUEEN;
121  gs->board[4][7] = B_KING;
122  gs->board[5][7] = B_BISHOP;
123  gs->board[6][7] = B_KNIGHT;
124  gs->board[7][7] = B_ROOK;
125  reset_board_vars(gs);
126 }
127
128 int board_init(int g,struct game_state_t *b, char *category, char *board)
129 {
130   int retval = 0;
131   int wval;
132
133   if (!category || !board || !category[0] || !board[0]) 
134                                 /* accounts for bughouse too */
135     board_standard(b);
136   else {
137     if (!strcmp(category, "wild")) {
138       if (sscanf(board, "%d", &wval) == 1 && wval >= 1 && wval <= 4)
139         wild_update(wval);
140       }
141     retval = board_read_file(category, board, b); 
142   }
143   MakeFENpos(g, game_globals.garray[g].FENstartPos);
144   return retval;
145 }
146
147 void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
148 {
149   int r, f;
150   int *p;
151
152   *ws = *bs = 0;
153   for (f = 0; f < 8; f++) {
154     for (r = 0; r < 8; r++) {
155       if (colorval(b->board[r][f]) == WHITE)
156         p = ws;
157       else
158         p = bs;
159       *p += pieceValues[piecetype(b->board[r][f])];
160     }
161   }
162   for (r = PAWN; r <= QUEEN; r++) {
163     *ws += b->holding[0][r-1] * pieceValues[r];
164     *bs += b->holding[1][r-1] * pieceValues[r];
165   }
166 }
167
168 static char *holding_str(int *holding)
169 {
170         static char tmp[30];
171         int p,i,j;
172
173         i = 0;
174         for (p = PAWN; p <= QUEEN; p++) {
175                 for (j = 0; j < holding[p-1]; j++) {
176                         tmp[i++] = wpstring[p][0];
177                 }
178         }
179         tmp[i] = '\0';
180         return tmp;
181 }
182
183 static char *append_holding_machine(char *buf, int g, int c, int p)
184 {
185   struct game_state_t *gs = &game_globals.garray[g].game_state;
186   char tmp[50];
187
188   sprintf(tmp, "<b1> game %d white [%s] black [", g+1, holding_str(gs->holding[0]));
189   strcat(tmp, holding_str(gs->holding[1]));
190   strcat(buf, tmp);
191   if (p) {
192     sprintf(tmp, "] <- %c%s\n", "WB"[c], wpstring[p]);
193     strcat(buf, tmp);
194   } else
195     strcat(buf, "]\n");
196   return buf;
197 }
198
199 static char *append_holding_display(char *buf, struct game_state_t *gs, int white)
200 {
201   if (white)
202     strcat(buf, "White holding: [");
203   else
204     strcat(buf, "Black holding: [");
205   strcat(buf, holding_str(gs->holding[white ? 0 : 1]));
206   strcat(buf, "]\n");
207   return buf;
208 }
209
210 void update_holding(int g, int pieceCaptured)
211 {
212   int p = piecetype(pieceCaptured);
213   int c = colorval(pieceCaptured);
214   struct game_state_t *gs = &game_globals.garray[g].game_state;
215   int pp, pl;
216   char tmp1[80], tmp2[80];
217
218   if (c == WHITE) {
219     c = 0;
220     pp = game_globals.garray[g].white;
221   } else {
222     c = 1;
223     pp = game_globals.garray[g].black;
224   }
225   gs->holding[c][p-1]++;
226   tmp1[0] = '\0';
227   append_holding_machine(tmp1, g, c, p);
228   sprintf(tmp2, "Game %d %s received: %s -> [%s]\n", g+1,
229           player_globals.parray[pp].name, wpstring[p], holding_str(gs->holding[c]));
230   for (pl = 0; pl < player_globals.p_num; pl++) {
231     if (player_globals.parray[pl].status == PLAYER_EMPTY)
232       continue;
233     if (player_is_observe(pl, g) || (player_globals.parray[pl].game == g)) {
234       pprintf_prompt(pl, IsMachineStyle(player_globals.parray[pl].style) ? tmp1 : tmp2);
235         }
236   }
237 }
238
239
240 /* Globals used for each board */
241 static int wTime, bTime;
242 static int orient;
243 static int forPlayer;
244 static int myTurn;              /* 1 = my turn, 0 = observe, -1 = other turn */
245  /* 2 = examiner, -2 = observing examiner */
246  /* -3 = just send position (spos/refresh) */
247
248 char *board_to_string(char *wn, char *bn,
249                       int wt, int bt,
250                       struct game_state_t *b, struct move_t *ml, int style,
251                       int orientation, int relation,
252                       int p)
253 {
254   int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0);
255   orient = orientation;
256   myTurn = relation;
257
258   wTime = 0;
259   bTime = 0;
260
261   /* when examining we calculate times based on the time left when the 
262      move happened, not current time */
263   if (game_globals.garray[b->gameNum].status == GAME_EXAMINE) {
264           unsigned nhm = game_globals.garray[b->gameNum].numHalfMoves;
265           if (nhm > 0) {
266                   wTime = ml[nhm - 1].wTime;
267                   bTime = ml[nhm - 1].bTime;
268           } else {
269                   wTime = game_globals.garray[b->gameNum].wInitTime;
270                   bTime = game_globals.garray[b->gameNum].bInitTime;
271           }
272   }
273
274   /* cope with old stored games */
275   if (wTime == 0) wTime = wt;
276   if (bTime == 0) bTime = bt;
277
278   forPlayer = p;
279   if ((style < 0) || (style >= MAX_STYLES))
280     return NULL;
281
282   if (style != 11) {            /* game header */
283     sprintf(bstring, "Game %d (%s vs. %s)\n\n",
284           b->gameNum + 1,
285           game_globals.garray[b->gameNum].white_name,
286           game_globals.garray[b->gameNum].black_name);
287   } else
288     bstring[0] = '\0';
289   if (bh && !IsMachineStyle(style))
290     append_holding_display(bstring, b, orientation==BLACK);
291   if (styleFuncs[style] (b, ml))
292     return NULL;
293   if (bh) {
294     if (IsMachineStyle(style))
295       append_holding_machine(bstring, b->gameNum, 0, 0);
296     else
297       append_holding_display(bstring, b, orientation==WHITE);
298   }
299   return bstring;
300 }
301
302 char *move_and_time(struct move_t *m)
303 {
304         static char tmp[20];
305         sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
306         return tmp;
307 }
308
309 /* The following take the game state and whole move list */
310
311 static int genstyle(struct game_state_t *b, struct move_t *ml, const char *wp[], const char *bp[],
312                     const char *wsqr, const char *bsqr,
313                     const char *top, const char *mid, const char *start, const char *end, 
314                     const char *label,const char *blabel)
315 {
316   int f, r, count;
317   char tmp[80];
318   int first, last, inc;
319   int ws, bs;
320
321   board_calc_strength(b, &ws, &bs);
322   if (orient == WHITE) {
323     first = 7;
324     last = 0;
325     inc = -1;
326   } else {
327     first = 0;
328     last = 7;
329     inc = 1;
330   }
331   strcat(bstring, top);
332   for (f = first, count = 7; f != last + inc; f += inc, count--) {
333     sprintf(tmp, "     %d  %s", f + 1, start);
334     strcat(bstring, tmp);
335     for (r = last; r != first - inc; r = r - inc) {
336       if (square_color(r, f) == WHITE)
337         strcat(bstring, wsqr);
338       else
339         strcat(bstring, bsqr);
340       if (piecetype(b->board[r][f]) == NOPIECE) {
341         if (square_color(r, f) == WHITE)
342           strcat(bstring, bp[0]);
343         else
344           strcat(bstring, wp[0]);
345       } else {
346         if (colorval(b->board[r][f]) == WHITE)
347           strcat(bstring, wp[piecetype(b->board[r][f])]);
348         else
349           strcat(bstring, bp[piecetype(b->board[r][f])]);
350       }
351     }
352     sprintf(tmp, "%s", end);
353     strcat(bstring, tmp);
354     switch (count) {
355     case 7:
356       sprintf(tmp, "     Move # : %d (%s)", b->moveNum, CString(b->onMove));
357       strcat(bstring, tmp);
358       break;
359     case 6:
360 /*    if ((b->moveNum > 1) || (b->onMove == BLACK)) {  */
361 /* The change from the above line to the one below is a kludge by hersco. */
362       if (game_globals.garray[b->gameNum].numHalfMoves > 0) {
363 /* loon: think this fixes the crashing ascii board on takeback bug */
364         sprintf(tmp, "     %s Moves : '%s'", CString(CToggle(b->onMove)),
365                 move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));
366         strcat(bstring, tmp);
367       }
368       break;
369     case 5:
370       break;
371     case 4:
372       sprintf(tmp, "     Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
373       strcat(bstring, tmp);
374       break;
375     case 3:
376       sprintf(tmp, "     White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
377       strcat(bstring, tmp);
378       break;
379     case 2:
380       sprintf(tmp, "     Black Strength : %d", bs);
381       strcat(bstring, tmp);
382       break;
383     case 1:
384       sprintf(tmp, "     White Strength : %d", ws);
385       strcat(bstring, tmp);
386       break;
387     case 0:
388       break;
389     }
390     strcat(bstring, "\n");
391     if (count != 0)
392       strcat(bstring, mid);
393     else
394       strcat(bstring, top);
395   }
396   if (orient == WHITE)
397     strcat(bstring, label);
398   else
399     strcat(bstring, blabel);
400   return 0;
401 }
402
403 /* Experimental ANSI board for colour representation */
404 static int style13(struct game_state_t *b, struct move_t *ml)
405 {
406   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 Q ", "\033[37m\033[1m K "};
407   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 Q ", "\033[21m\033[37m K "};
408   static const char *wsqr = "\033[40m";
409   static const char *bsqr = "\033[45m";
410   static const char *top = "\t+------------------------+\n";
411   static const char *mid = "";
412   static const char *start = "|";
413   static const char *end = "\033[0m|";
414   static const char *label = "\t  a  b  c  d  e  f  g  h\n";
415   static const char *blabel = "\t  h  g  f  e  d  c  b  a\n";
416
417   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
418 }
419
420 /* Standard ICS */
421 static int style1(struct game_state_t *b, struct move_t *ml)
422 {
423   static const char *wp[] = {"   |", " P |", " N |", " B |", " R |", " Q |", " K |"};
424   static const char *bp[] = {"   |", " *P|", " *N|", " *B|", " *R|", " *Q|", " *K|"};
425   static char *wsqr = "";
426   static char *bsqr = "";
427   static char *top = "\t---------------------------------\n";
428   static char *mid = "\t|---+---+---+---+---+---+---+---|\n";
429   static char *start = "|";
430   static char *end = "";
431   static char *label = "\t  a   b   c   d   e   f   g   h\n";
432   static char *blabel = "\t  h   g   f   e   d   c   b   a\n";
433
434   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
435 }
436
437 /* USA-Today Sports Center-style board */
438 static int style2(struct game_state_t *b, struct move_t *ml)
439 {
440   static const char *wp[] = {"+  ", "P  ", "N  ", "B  ", "R  ", "Q  ", "K  "};
441   static const char *bp[] = {"-  ", "p' ", "n' ", "b' ", "r' ", "q' ", "k' "};
442   static char *wsqr = "";
443   static char *bsqr = "";
444   static char *top = "";
445   static char *mid = "";
446   static char *start = "";
447   static char *end = "";
448   static char *label = "\ta  b  c  d  e  f  g  h\n";
449   static char *blabel = "\th  g  f  e  d  c  b  a\n";
450
451   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
452 }
453
454 /* Experimental vt-100 ANSI board for dark backgrounds */
455 static int style3(struct game_state_t *b, struct move_t *ml)
456 {
457   static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " Q ", " K "};
458   static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *Q", " *K"};
459   static char *wsqr = "\033[0m";
460   static char *bsqr = "\033[7m";
461   static char *top = "\t+------------------------+\n";
462   static char *mid = "";
463   static char *start = "|";
464   static char *end = "\033[0m|";
465   static char *label = "\t  a  b  c  d  e  f  g  h\n";
466   static char *blabel = "\t  h  g  f  e  d  c  b  a\n";
467
468   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
469 }
470
471 /* Experimental vt-100 ANSI board for light backgrounds */
472 static int style4(struct game_state_t *b, struct move_t *ml)
473 {
474   static const char *wp[] = {"   ", " P ", " N ", " B ", " R ", " Q ", " K "};
475   static const char *bp[] = {"   ", " *P", " *N", " *B", " *R", " *Q", " *K"};
476   static char *wsqr = "\033[7m";
477   static char *bsqr = "\033[0m";
478   static char *top = "\t+------------------------+\n";
479   static char *mid = "";
480   static char *start = "|";
481   static char *end = "\033[0m|";
482   static char *label = "\t  a  b  c  d  e  f  g  h\n";
483   static char *blabel = "\t  h  g  f  e  d  c  b  a\n";
484
485   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
486 }
487
488 /* Style suggested by ajpierce@med.unc.edu */
489 static int style5(struct game_state_t *b, struct move_t *ml)
490 {
491   static const char *wp[] = {"    ", "  o ", " :N:", " <B>", " |R|", " {Q}", " =K="};
492   static const char *bp[] = {"    ", "  p ", " :n:", " <b>", " |r|", " {q}", " =k="};
493   static char *wsqr = "";
494   static char *bsqr = "";
495   static char *top = "        .   .   .   .   .   .   .   .   .\n";
496   static char *mid = "        .   .   .   .   .   .   .   .   .\n";
497   static char *start = "";
498   static char *end = "";
499   static char *label = "\t  a   b   c   d   e   f   g   h\n";
500   static char *blabel = "\t  h   g   f   e   d   c   b   a\n";
501
502   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
503 }
504
505 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
506 static int style6(struct game_state_t *b, struct move_t *ml)
507 {
508   static const char *wp[] = {"    |", " wp |", " WN |", " WB |", " WR |", " WQ |", " WK |"};
509   static const char *bp[] = {"    |", " bp |", " BN |", " BB |", " BR |", " BQ |", " BK |"};
510   static char *wsqr = "";
511   static char *bsqr = "";
512   static char *top = "\t-----------------------------------------\n";
513   static char *mid = "\t-----------------------------------------\n";
514   static char *start = "|";
515   static char *end = "";
516   static char *label = "\t  A    B    C    D    E    F    G    H\n";
517   static char *blabel = "\t  H    G    F    E    D    C    B    A\n";
518
519   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
520 }
521
522 /* Miniature board */
523 static int style7(struct game_state_t *b, struct move_t *ml)
524 {
525   static const char *wp[] = {"  ", " P", " N", " B", " R", " Q", " K"};
526   static const char *bp[] = {" -", " p", " n", " b", " r", " q", " k"};
527   static char *wsqr = "";
528   static char *bsqr = "";
529   static char *top = "\t:::::::::::::::::::::\n";
530   static char *mid = "";
531   static char *start = "..";
532   static char *end = " ..";
533   static char *label = "\t   a b c d e f g h\n";
534   static char *blabel = "\t   h g f e d c b a\n";
535
536   return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
537 }
538
539 /* ICS interface maker board-- raw data dump */
540 static int style8(struct game_state_t *b, struct move_t *ml)
541 {
542   char tmp[80];
543   int f, r;
544   int ws, bs;
545
546   board_calc_strength(b, &ws, &bs);
547   sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,
548           game_globals.garray[b->gameNum].white_name,
549           (orient == WHITE) ? "*" : ":",
550           game_globals.garray[b->gameNum].black_name,
551           (orient == WHITE) ? ":" : "*");
552   strcat(bstring, tmp);
553   for (r = 0; r < 8; r++) {
554     for (f = 0; f < 8; f++) {
555       if (b->board[f][r] == NOPIECE) {
556         strcat(bstring, " ");
557       } else {
558         if (colorval(b->board[f][r]) == WHITE)
559           strcat(bstring, wpstring[piecetype(b->board[f][r])]);
560         else
561           strcat(bstring, bpstring[piecetype(b->board[f][r])]);
562       }
563     }
564   }
565   sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
566           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
567           (b->onMove == WHITE) ? "W" : "B",
568           ws,
569           bs,
570           (wTime + 5) / 10,
571           (bTime + 5) / 10,
572           game_globals.garray[b->gameNum].numHalfMoves ?
573           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
574           "none",
575           game_globals.garray[b->gameNum].numHalfMoves ?
576           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
577           "0:00");
578   strcat(bstring, tmp);
579   return 0;
580 }
581
582 /* last 2 moves only (previous non-verbose mode) */
583 static int style9(struct game_state_t *b, struct move_t *ml)
584 {
585   int i, count;
586   char tmp[80];
587   int startmove;
588
589   sprintf(tmp, "\nMove     %-23s%s\n",
590           game_globals.garray[b->gameNum].white_name,
591           game_globals.garray[b->gameNum].black_name);
592   strcat(bstring, tmp);
593   sprintf(tmp, "----     --------------         --------------\n");
594   strcat(bstring, tmp);
595   startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;
596   if (startmove < 0)
597     startmove = 0;
598   for (i = startmove, count = 0;
599        i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
600        i++, count++) {
601     if (!(i & 0x01)) {
602       sprintf(tmp, "  %2d     ", i / 2 + 1);
603       strcat(bstring, tmp);
604     }
605     sprintf(tmp, "%-23s", move_and_time(&ml[i]));
606     strcat(bstring, tmp);
607     if (i & 0x01)
608       strcat(bstring, "\n");
609   }
610   if (i & 0x01)
611     strcat(bstring, "\n");
612   return 0;
613 }
614
615 /* Sleator's 'new and improved' raw dump format... */
616 static int style10(struct game_state_t *b, struct move_t *ml)
617 {
618   int f, r;
619   char tmp[80];
620   int ws, bs;
621
622   board_calc_strength(b, &ws, &bs);
623   sprintf(tmp, "<10>\n");
624   strcat(bstring, tmp);
625   for (r = 7; r >= 0; r--) {
626     strcat(bstring, "|");
627     for (f = 0; f < 8; f++) {
628       if (b->board[f][r] == NOPIECE) {
629         strcat(bstring, " ");
630       } else {
631         if (colorval(b->board[f][r]) == WHITE)
632           strcat(bstring, wpstring[piecetype(b->board[f][r])]);
633         else
634           strcat(bstring, bpstring[piecetype(b->board[f][r])]);
635       }
636     }
637     strcat(bstring, "|\n");
638   }
639   strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
640   if (game_globals.garray[b->gameNum].numHalfMoves) {
641     sprintf(tmp, "%d ",
642             ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
643   } else {
644     sprintf(tmp, "-1 ");
645   }
646   strcat(bstring, tmp);
647   sprintf(tmp, "%d %d %d %d %d\n",
648           !(b->wkmoved || b->wkrmoved),
649           !(b->wkmoved || b->wqrmoved),
650           !(b->bkmoved || b->bkrmoved),
651           !(b->bkmoved || b->bqrmoved),
652        (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :
653                                            b->lastIrreversable)));
654   strcat(bstring, tmp);
655   sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",
656           b->gameNum,
657           game_globals.garray[b->gameNum].white_name,
658           game_globals.garray[b->gameNum].black_name,
659           myTurn,
660           game_globals.garray[b->gameNum].wInitTime / 600,
661           game_globals.garray[b->gameNum].wIncrement / 10,
662           ws,
663           bs,
664           (wTime + 5) / 10,
665           (bTime + 5) / 10,
666           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
667           game_globals.garray[b->gameNum].numHalfMoves ?
668           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
669           "none",
670           game_globals.garray[b->gameNum].numHalfMoves ?
671           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
672           "0:00",
673           game_globals.garray[b->gameNum].numHalfMoves ?
674           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
675           "none",
676           (orient == WHITE) ? 0 : 1);
677   strcat(bstring, tmp);
678   sprintf(tmp, ">10<\n");
679   strcat(bstring, tmp);
680   return 0;
681 }
682
683 /* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */
684 static int style11(struct game_state_t *b, struct move_t *ml)
685 {
686   char tmp[80];
687   int f, r;
688   int ws, bs;
689
690   board_calc_strength(b, &ws, &bs);
691   sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,
692           game_globals.garray[b->gameNum].white_name,
693           (orient == WHITE) ? "*" : ":",
694           game_globals.garray[b->gameNum].black_name,
695           (orient == WHITE) ? ":" : "*");
696   strcat(bstring, tmp);
697   for (r = 0; r < 8; r++) {
698     for (f = 0; f < 8; f++) {
699       if (b->board[f][r] == NOPIECE) {
700         strcat(bstring, " ");
701       } else {
702         if (colorval(b->board[f][r]) == WHITE)
703           strcat(bstring, wpstring[piecetype(b->board[f][r])]);
704         else
705           strcat(bstring, bpstring[piecetype(b->board[f][r])]);
706       }
707     }
708   }
709     sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
710             game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
711             (b->onMove == WHITE) ? "W" : "B",
712             ws,
713             bs,
714             (wTime + 5) / 10,
715             (bTime + 5) / 10,
716             game_globals.garray[b->gameNum].numHalfMoves ?
717             ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
718             "none",
719             game_globals.garray[b->gameNum].numHalfMoves ?
720             tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
721             "0:00");
722   strcat(bstring, tmp);
723   return 0;
724 }
725
726 /* Similar to style 10.  See the "style12" help file for information */
727 static int style12(struct game_state_t *b, struct move_t *ml)
728 {
729   int f, r;
730   char tmp[80];
731   int ws, bs;
732
733   board_calc_strength(b, &ws, &bs);
734   sprintf(bstring, "<12> ");
735   for (r = 7; r >= 0; r--) {
736     for (f = 0; f < 8; f++) {
737       if (b->board[f][r] == NOPIECE) {
738         strcat(bstring, "-");
739       } else {
740         if (colorval(b->board[f][r]) == WHITE)
741           strcat(bstring, wpstring[piecetype(b->board[f][r])]);
742         else
743           strcat(bstring, bpstring[piecetype(b->board[f][r])]);
744       }
745     }
746     strcat(bstring, " ");
747   }
748   strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
749   if (game_globals.garray[b->gameNum].numHalfMoves) {
750     sprintf(tmp, "%d ",
751             ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
752   } else {
753     sprintf(tmp, "-1 ");
754   }
755   strcat(bstring, tmp);
756   sprintf(tmp, "%d %d %d %d %d ",
757           !(b->wkmoved || b->wkrmoved),
758           !(b->wkmoved || b->wqrmoved),
759           !(b->bkmoved || b->bkrmoved),
760           !(b->bkmoved || b->bqrmoved),
761           (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));
762   strcat(bstring, tmp);
763   sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",
764           b->gameNum + 1,
765           game_globals.garray[b->gameNum].white_name,
766           game_globals.garray[b->gameNum].black_name,
767           myTurn,
768           game_globals.garray[b->gameNum].wInitTime / 600,
769           game_globals.garray[b->gameNum].wIncrement / 10,
770           ws,
771           bs,
772           (wTime / 10),
773           (bTime / 10),
774           game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
775           game_globals.garray[b->gameNum].numHalfMoves ?
776           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
777           "none",
778           game_globals.garray[b->gameNum].numHalfMoves ?
779           tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
780           "0:00",
781           game_globals.garray[b->gameNum].numHalfMoves ?
782           ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
783           "none", (orient == WHITE) ? 0 : 1,
784           b->moveNum > 1 ? 1 : 0); /* ticking */
785
786   strcat(bstring, tmp);
787   return 0;
788 }
789
790 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
791 {
792   FILE *fp;
793   int c;
794   int onNewLine = 1;
795   int onColor = -1;
796   int onPiece = -1;
797   int onFile = -1;
798   int onRank = -1;
799
800   fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
801   if (!fp)
802     return 1;
803
804   board_clear(gs);
805   while (!feof(fp)) {
806     c = fgetc(fp);
807     if (onNewLine) {
808       if (c == 'W') {
809         onColor = WHITE;
810         if (gs->onMove < 0)
811           gs->onMove = WHITE;
812       } else if (c == 'B') {
813         onColor = BLACK;
814         if (gs->onMove < 0)
815           gs->onMove = BLACK;
816       } else if (c == '#') {
817         while (!feof(fp) && c != '\n')
818           c = fgetc(fp);        /* Comment line */
819         continue;
820       } else {                  /* Skip any line we don't understand */
821         while (!feof(fp) && c != '\n')
822           c = fgetc(fp);
823         continue;
824       }
825       onNewLine = 0;
826     } else {
827       switch (c) {
828       case 'P':
829         onPiece = PAWN;
830         break;
831       case 'R':
832         onPiece = ROOK;
833         break;
834       case 'N':
835         onPiece = KNIGHT;
836         break;
837       case 'B':
838         onPiece = BISHOP;
839         break;
840       case 'Q':
841         onPiece = QUEEN;
842         break;
843       case 'K':
844         onPiece = KING;
845         break;
846       case 'a':
847       case 'b':
848       case 'c':
849       case 'd':
850       case 'e':
851       case 'f':
852       case 'g':
853       case 'h':
854         onFile = c - 'a';
855         onRank = -1;
856         break;
857       case '1':
858       case '2':
859       case '3':
860       case '4':
861       case '5':
862       case '6':
863       case '7':
864       case '8':
865         onRank = c - '1';
866         if (onFile >= 0 && onColor >= 0 && onPiece >= 0)
867           gs->board[onFile][onRank] = onPiece | onColor;
868         break;
869       case '#':
870         while (!feof(fp) && c != '\n')
871           c = fgetc(fp);        /* Comment line */
872       case '\n':
873         onNewLine = 1;
874         onColor = -1;
875         onPiece = -1;
876         onFile = -1;
877         onRank = -1;
878         break;
879       default:
880         break;
881       }
882     }
883   }
884   fclose(fp);
885   return 0;
886 }
887
888 #define WHITE_SQUARE 1
889 #define BLACK_SQUARE 0
890 #define ANY_SQUARE -1
891 #define SquareColor(f, r) ((f ^ r) & 1)
892
893 static void place_piece(board_t b, int piece, int squareColor)
894 {
895   int r, f;
896   int placed = 0;
897
898   if (iscolor(piece, BLACK))
899     r = 7;
900   else
901     r = 0;
902
903   while (!placed) {
904     if (squareColor == ANY_SQUARE) {
905       f = random() % 8;
906     } else {
907       f = (random() % 4) * 2;
908       if (SquareColor(f, r) != squareColor)
909         f++;
910     }
911     if ((b)[f][r] == NOPIECE) {
912       (b)[f][r] = piece;
913       placed = 1;
914     }
915   }
916 }
917
918 static void wild_update(int style)
919 {
920   int f, r, i;
921   board_t b;
922
923   for (f = 0; f < 8; f++)
924     for (r = 0; r < 8; r++)
925       b[f][r] = NOPIECE;
926   for (f = 0; f < 8; f++) {
927     b[f][1] = W_PAWN;
928     b[f][6] = B_PAWN;
929   }
930   switch (style) {
931   case 1:
932     if (random() & 0x01) {
933       b[4][0] = W_KING;
934       b[3][0] = W_QUEEN;
935     } else {
936       b[3][0] = W_KING;
937       b[4][0] = W_QUEEN;
938     }
939     if (random() & 0x01) {
940       b[4][7] = B_KING;
941       b[3][7] = B_QUEEN;
942     } else {
943       b[3][7] = B_KING;
944       b[4][7] = B_QUEEN;
945     }
946     b[0][0] = b[7][0] = W_ROOK;
947     b[0][7] = b[7][7] = B_ROOK;
948     /* Must do bishops before knights to be sure opposite colored squares are
949        available. */
950     place_piece(b, W_BISHOP, WHITE_SQUARE);
951     place_piece(b, W_BISHOP, BLACK_SQUARE);
952     place_piece(b, W_KNIGHT, ANY_SQUARE);
953     place_piece(b, W_KNIGHT, ANY_SQUARE);
954     place_piece(b, B_BISHOP, WHITE_SQUARE);
955     place_piece(b, B_BISHOP, BLACK_SQUARE);
956     place_piece(b, B_KNIGHT, ANY_SQUARE);
957     place_piece(b, B_KNIGHT, ANY_SQUARE);
958     break;
959   case 2:
960     place_piece(b, W_KING, ANY_SQUARE);
961     place_piece(b, W_QUEEN, ANY_SQUARE);
962     place_piece(b, W_ROOK, ANY_SQUARE);
963     place_piece(b, W_ROOK, ANY_SQUARE);
964     place_piece(b, W_BISHOP, ANY_SQUARE);
965     place_piece(b, W_BISHOP, ANY_SQUARE);
966     place_piece(b, W_KNIGHT, ANY_SQUARE);
967     place_piece(b, W_KNIGHT, ANY_SQUARE);
968     /* Black mirrors White */
969     for (i = 0; i < 8; i++) {
970       b[i][7] = b[i][0] | BLACK;
971     }
972     break;
973   case 3:
974     /* Generate White king on random square plus random set of pieces */
975     place_piece(b, W_KING, ANY_SQUARE);
976     for (i = 0; i < 8; i++) {
977       if (b[i][0] != W_KING) {
978         b[i][0] = (random() % 4) + 2;
979       }
980     }
981     /* Black mirrors White */
982     for (i = 0; i < 8; i++) {
983       b[i][7] = b[i][0] | BLACK;
984     }
985     break;
986   case 4:
987     /* Generate White king on random square plus random set of pieces */
988     place_piece(b, W_KING, ANY_SQUARE);
989     for (i = 0; i < 8; i++) {
990       if (b[i][0] != W_KING) {
991         b[i][0] = (random() % 4) + 2;
992       }
993     }
994     /* Black has same set of pieces, but randomly permuted, except that Black
995        must have the same number of bishops on white squares as White has on
996        black squares, and vice versa.  So we must place Black's bishops first
997        to be sure there are enough squares left of the correct color. */
998     for (i = 0; i < 8; i++) {
999       if (b[i][0] == W_BISHOP) {
1000         place_piece(b, B_BISHOP, !SquareColor(i, 0));
1001       }
1002     }
1003     for (i = 0; i < 8; i++) {
1004       if (b[i][0] != W_BISHOP) {
1005         place_piece(b, b[i][0] | BLACK, ANY_SQUARE);
1006       }
1007     }
1008     break;
1009   default:
1010     return;
1011     break;
1012   }
1013   {
1014     FILE *fp;
1015     int onPiece;
1016
1017     fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1018     if (!fp) {
1019       d_printf( "CHESSD: Can't write wild style %d\n", style);
1020       return;
1021     }
1022     fprintf(fp, "W:");
1023     onPiece = -1;
1024     for (r = 1; r >= 0; r--) {
1025       for (f = 0; f < 8; f++) {
1026         if (onPiece < 0 || b[f][r] != onPiece) {
1027           onPiece = b[f][r];
1028           fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1029         }
1030         fprintf(fp, " %c%c", f + 'a', r + '1');
1031       }
1032     }
1033     fprintf(fp, "\nB:");
1034     onPiece = -1;
1035     for (r = 6; r < 8; r++) {
1036       for (f = 0; f < 8; f++) {
1037         if (onPiece < 0 || b[f][r] != onPiece) {
1038           onPiece = b[f][r];
1039           fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1040         }
1041         fprintf(fp, " %c%c", f + 'a', r + '1');
1042       }
1043     }
1044     fprintf(fp, "\n");
1045     fclose(fp);
1046   }
1047 }
1048
1049 void wild_init(void)
1050 {
1051         wild_update(1);
1052         wild_update(2);
1053         wild_update(3);
1054         wild_update(4);
1055 }
1056