2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
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.
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.
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.
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"};
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};
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)
36 static char bstring[MAX_BOARD_STRING_LENGTH];
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);
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);
55 static int (*styleFuncs[MAX_STYLES])() = {
72 static void reset_board_vars(struct game_state_t *gs)
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;
84 gs->wkmoved = gs->wqrmoved = gs->wkrmoved = -1; // [HGM] castle: no rights
85 gs->bkmoved = gs->bqrmoved = gs->bkrmoved = -1;
88 gs->lastIrreversable = -1;
92 void board_clear(struct game_state_t *gs)
96 for (f = 0; f < BW; f++)
97 for (r = 0; r < BH; r++)
98 gs->board[f][r] = NOPIECE;
102 void board_standard(struct game_state_t *gs)
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;
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;
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;
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;
154 int board_init(int g,struct game_state_t *b, char *category, char *board)
159 b->files = b->ranks = 8;
160 b->pawnDblStep = (!category || strcmp(category, "shatranj"));
161 b->royalKnight = (category && !strcmp(category, "knightmate"));
162 b->capablancaPieces = 0;
165 b->castlingStyle = 1;
168 b->bareKingLoses = 0;
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 */
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);
184 if (board && !strcmp(board, "0"))
185 b->setup = 0; // [HGM] variant: any board in the default file "0" is supposed to be implied by the variant
187 if (!strcmp(category, "knightmate")) {
189 } else if (!strcmp(category, "super")) {
193 for(i=CENTAUR; i<=AMAZON; i++) {
197 if((p = piecetype(b->board[j][0])) >= CENTAUR) continue; // includes King
198 b->holding[1][p-PAWN] = ++b->holding[0][p-PAWN]; // piece to holding
199 if(board && !strcmp(board, "1")) newp = i - CENTAUR + WOODY; else newp = i;
200 if(board && !strcmp(board, "2")) newp = WOODY + random()%7;
201 b->board[j][0] = newp | WHITE; // place replacements
202 b->board[j][7] = newp | BLACK;
207 } else if (!strcmp(category, "fischerandom")) {
208 wild_update(b->board, 22);
209 b->castlingStyle = 2;
210 b->setup = 1; // [HGM] FRC: even the default is a setup position, for which an initial board has to be printed
211 } else if (!strcmp(category, "caparandom")) {
213 wild_update(b->board, 46);
214 b->castlingStyle = 2;
216 } else retval = board_read_file(category, board, b);
218 if(b->setup && game_globals.garray[g].FENstartPos[0]) // [HGM] use pre-existing start position, if one available
219 FEN_to_board(game_globals.garray[g].FENstartPos, b); // (could be wild board, or shuffle variant)
220 if(b->castlingStyle == 1) {
221 b->wkmoved = b->files/2;
222 b->bkmoved = b->files/2;
223 b->wkrmoved = b->files-1;
224 b->bkrmoved = b->files-1;
227 } else if(b->castlingStyle == 2) {
228 for(i=j=0; i < b->files; i++) {
229 int p = b->board[i][0];
230 if(p == W_ROOK || p == W_KING) {
232 case 0: b->wqrmoved = b->bqrmoved = i; break;
233 case 1: b->wkmoved = b->bkmoved = i; break;
234 case 2: b->wkrmoved = b->bkrmoved = i; break;
240 MakeFENpos(g, game_globals.garray[g].FENstartPos);
245 void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
251 for (f = 0; f < b->ranks; f++) {
252 for (r = 0; r < b->files; r++) {
253 if (colorval(b->board[r][f]) == WHITE)
257 *p += pieceValues[piecetype(b->board[r][f])];
260 for (r = PAWN; r < PIECES; r++) {
261 *ws += b->holding[0][r-1] * pieceValues[r];
262 *bs += b->holding[1][r-1] * pieceValues[r];
266 static char *holding_str(int *holding)
272 for (p = PAWN; p < PIECES; p++) {
273 for (j = 0; j < holding[p-1]; j++) {
274 tmp[i++] = wpstring[p][0];
281 static char *append_holding_machine(char *buf, int g, int c, int p)
283 struct game_state_t *gs = &game_globals.garray[g].game_state;
286 sprintf(tmp, "<b1> game %d white [%s] black [", g+1, holding_str(gs->holding[0]));
287 strcat(tmp, holding_str(gs->holding[1]));
290 sprintf(tmp, "] <- %c%s\n", "WB"[c], wpstring[p]);
297 static char *append_holding_display(char *buf, struct game_state_t *gs, int white)
300 strcat(buf, "White holding: [");
302 strcat(buf, "Black holding: [");
303 strcat(buf, holding_str(gs->holding[white ? 0 : 1]));
308 void update_holding(int g, int pieceCaptured)
310 int p = piecetype(pieceCaptured);
311 int c = colorval(pieceCaptured);
312 struct game_state_t *gs = &game_globals.garray[g].game_state;
314 char tmp1[160], tmp2[160];
318 pp = game_globals.garray[g].white;
321 pp = game_globals.garray[g].black;
323 gs->holding[c][p-1]++;
325 append_holding_machine(tmp1, g, c, p);
326 sprintf(tmp2, "Game %d %s received: %s -> [%s]\n", g+1,
327 player_globals.parray[pp].name, wpstring[p], holding_str(gs->holding[c]));
328 for (pl = 0; pl < player_globals.p_num; pl++) {
329 if (player_globals.parray[pl].status == PLAYER_EMPTY)
331 if (player_is_observe(pl, g) || (player_globals.parray[pl].game == g)) {
332 pprintf_prompt(pl, IsMachineStyle(player_globals.parray[pl].style) ? tmp1 : tmp2);
338 /* Globals used for each board */
339 static int wTime, bTime;
341 static int forPlayer;
342 static int myTurn; /* 1 = my turn, 0 = observe, -1 = other turn */
343 /* 2 = examiner, -2 = observing examiner */
344 /* -3 = just send position (spos/refresh) */
346 char *board_to_string(char *wn, char *bn,
348 struct game_state_t *b, struct move_t *ml, int style,
349 int orientation, int relation,
352 int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0
353 || b->holdings || b->drops == 2); // [HGM] zh: make sure holdings are printed (also in Seirawan)
354 orient = orientation;
360 /* when examining we calculate times based on the time left when the
361 move happened, not current time */
362 if (game_globals.garray[b->gameNum].status == GAME_EXAMINE) {
363 unsigned nhm = game_globals.garray[b->gameNum].numHalfMoves;
366 wTime = ml[nhm - 1].wTime;
367 bTime = ml[nhm - 1].bTime;
369 wTime = game_globals.garray[b->gameNum].wInitTime;
370 bTime = game_globals.garray[b->gameNum].bInitTime;
374 /* cope with old stored games */
375 if (wTime == 0) wTime = wt;
376 if (bTime == 0) bTime = bt;
379 if ((style < 0) || (style >= MAX_STYLES))
382 if (style != 11) { /* game header */
383 sprintf(bstring, "Game %d (%s vs. %s)\n\n",
385 game_globals.garray[b->gameNum].white_name,
386 game_globals.garray[b->gameNum].black_name);
389 if (bh && !IsMachineStyle(style))
390 append_holding_display(bstring, b, orientation==BLACK);
392 if (styleFuncs[style] (b, ml))
396 if (IsMachineStyle(style))
397 append_holding_machine(bstring, b->gameNum, 0, 0);
399 append_holding_display(bstring, b, orientation==WHITE);
404 char *move_and_time(struct move_t *m)
409 sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */
410 m->score>0 ? "+" : "", m->score, m->depth);
413 sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
417 /* The following take the game state and whole move list */
419 void Enlarge(char *a, int ss, int w)
423 if(strlen(a) < ss) return;
426 p = a + l; q = p + ss;
427 while(q != a+l-ss) *q-- = *p--;
431 static int genstyle(struct game_state_t *b, struct move_t *ml, const char *wp[], const char *bp[],
432 const char *wsqr, const char *bsqr,
433 const char *top, const char *mid, const char *start, const char *end,
434 const char *label,const char *blabel)
437 char tmp[80], mylabel[80], *p, *q, myTop[80], myMid[80];
438 int firstR, lastR, firstF, lastF, inc;
439 int ws, bs, sqrSize = strlen(wp[0]);
441 board_calc_strength(b, &ws, &bs);
442 if (orient == WHITE) {
455 Enlarge(myTop, sqrSize, b->files);
456 Enlarge(myMid, sqrSize, b->files);
457 strcat(bstring, myTop);
458 for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) {
459 sprintf(tmp, " %d %s", f + (b->ranks < 10), start);
460 strcat(bstring, tmp);
461 for (r = lastF; r != firstF - inc; r = r - inc) {
462 if (square_color(r, f) == WHITE)
463 strcat(bstring, wsqr);
465 strcat(bstring, bsqr);
466 if (piecetype(b->board[r][f]) == NOPIECE) {
467 if (square_color(r, f) == WHITE)
468 strcat(bstring, bp[0]);
470 strcat(bstring, wp[0]);
472 int piece = piecetype(b->board[r][f]);
473 // if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles
474 if (colorval(b->board[r][f]) == WHITE)
475 strcat(bstring, wp[piece]);
477 strcat(bstring, bp[piece]);
480 sprintf(tmp, "%s", end);
481 strcat(bstring, tmp);
484 sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove));
485 strcat(bstring, tmp);
488 /* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */
489 /* The change from the above line to the one below is a kludge by hersco. */
490 if (game_globals.garray[b->gameNum].numHalfMoves > 0) {
491 /* loon: think this fixes the crashing ascii board on takeback bug */
492 sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)),
493 move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));
494 strcat(bstring, tmp);
500 sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
501 strcat(bstring, tmp);
504 sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
505 strcat(bstring, tmp);
508 sprintf(tmp, " Black Strength : %d", bs);
509 strcat(bstring, tmp);
512 sprintf(tmp, " White Strength : %d", ws);
513 strcat(bstring, tmp);
518 strcat(bstring, "\n");
520 strcat(bstring, myMid);
522 strcat(bstring, myTop);
525 if (orient == WHITE) {
534 if(++i > b->files) { *q++ = '\n'; *q++ = 0; }
547 *q++ = *p++ + b->files - 12;
548 if(++i >= b->files) { *q++ = '\n'; *q++ = 0; }
553 strcat(bstring, mylabel);
557 /* Experimental ANSI board for colour representation */
558 static int style13(struct game_state_t *b, struct move_t *ml)
560 static const char *wp[] = {" ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m A ", "\033[37m\033[1m C ", "\033[37m\033[1m M ", "\033[37m\033[1m Q ", "\033[37m\033[1m E ", "\033[37m\033[1m K "};
561 static const char *bp[] = {" ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m A ", "\033[21m\033[37m C ", "\033[21m\033[37m M ", "\033[21m\033[37m Q ", "\033[21m\033[37m E ", "\033[21m\033[37m K "};
562 static const char *wsqr = "\033[40m";
563 static const char *bsqr = "\033[45m";
564 static const char *top = "\t+------------------------+\n";
565 static const char *mid = "";
566 static const char *start = "|";
567 static const char *end = "\033[0m|";
568 static const char *label = "\t a b c d e f g h i j k l\n";
569 static const char *blabel = "\t l k j i h g f e d c b a\n";
571 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
575 static int style1(struct game_state_t *b, struct move_t *ml)
577 static const char *wp[] = {" |", " P |", " N |", " B |", " R |", " A |", " C |", " M |", " Q |", " E |", " B |", " Q |",
578 " W |", " H |", " N |", " D |", " H |", " L |", " C |", " S |", " G |", " H |", " A |", " F |",
579 " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", " K |", " H |", " E |"};
580 static const char *bp[] = {" |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|",
581 " *W|", " *H|", " *N|", " *D|", " *H|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|",
582 " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", " *K|", " *H|", " *E|"};
583 static char *wsqr = "";
584 static char *bsqr = "";
585 static char *top = "\t---------------------------------\n";
586 static char *mid = "\t|---+---+---+---+---+---+---+---|\n";
587 static char *start = "|";
588 static char *end = "";
589 static char *label = "\t a b c d e f g h i j k l\n";
590 static char *blabel = "\t l k j i h g f e d c b a\n";
592 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
595 /* USA-Today Sports Center-style board */
596 static int style2(struct game_state_t *b, struct move_t *ml)
598 static const char *wp[] = {"- ", "P ", "N ", "B ", "R ", "A ", "C ", "M ", "Q ", "E ", "B ", "Q ",
599 "W ", "H ", "N ", "D ", "H ", "L ", "C ", "S ", "G ", "H ", "A ", "F ",
600 "E ", "H ", "M ", "S ", "E ", "W ", "O ", "G ", "V ", "S ", "E ", "A ", "K ", "H ", "E "};
601 static const char *bp[] = {"+ ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ",
602 "w' ", "h' ", "n' ", "d' ", "h' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ",
603 "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", "k' ", "h' ", "e' "};
604 static char *wsqr = "";
605 static char *bsqr = "";
606 static char *top = "";
607 static char *mid = "";
608 static char *start = "";
609 static char *end = "";
610 static char *label = "\ta b c d e f g h i j k l\n";
611 static char *blabel = "\tl k j i h g f e d c b a\n";
613 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
616 /* Experimental vt-100 ANSI board for dark backgrounds */
617 static int style3(struct game_state_t *b, struct move_t *ml)
619 static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ",
620 " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
621 " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K ", " H ", " E "};
622 static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q",
623 " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
624 " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K", " *H", " *E"};
625 static char *wsqr = "\033[0m";
626 static char *bsqr = "\033[7m";
627 static char *top = "\t+------------------------+\n";
628 static char *mid = "";
629 static char *start = "|";
630 static char *end = "\033[0m|";
631 static char *label = "\t a b c d e f g h i j k l\n";
632 static char *blabel = "\t l k j i h g f e d c b a\n";
634 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
637 /* Experimental vt-100 ANSI board for light backgrounds */
638 static int style4(struct game_state_t *b, struct move_t *ml)
640 static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ",
641 " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
642 " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K ", " H ", " E "};
643 static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q",
644 " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
645 " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K", " *H", " *E"};
646 static char *wsqr = "\033[7m";
647 static char *bsqr = "\033[0m";
648 static char *top = "\t+------------------------+\n";
649 static char *mid = "";
650 static char *start = "|";
651 static char *end = "\033[0m|";
652 static char *label = "\t a b c d e f g h i j k l\n";
653 static char *blabel = "\t l k j i h g f e d c b a\n";
655 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
658 /* Style suggested by ajpierce@med.unc.edu */
659 static int style5(struct game_state_t *b, struct move_t *ml)
661 static const char *wp[] = {" ", " o ", " :N:", " <B>", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!",
662 " <B>", " {Q}", " .W.", " :H:", " :N:", " <H>", " |D|", " |L|",
663 " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:",
664 " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", " =K=", " (H)", " [E]"};
665 static const char *bp[] = {" ", " p ", " :n:", " <b>", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!",
666 " <b>", " {q}", " .w.", " :h:", " :n:", " <h>", " |d|", " |l|",
667 " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:",
668 " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", " =k=", " (f)", " [e]"};
669 static char *wsqr = "";
670 static char *bsqr = "";
671 static char *top = " . . . . . . . . .\n";
672 static char *mid = " . . . . . . . . .\n";
673 static char *start = "";
674 static char *end = "";
675 static char *label = "\t a b c d e f g h i j k l\n";
676 static char *blabel = "\t l k j i h g f e d c b a\n";
678 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
681 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
682 static int style6(struct game_state_t *b, struct move_t *ml)
684 static const char *wp[] = {" |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |",
685 " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WD |", " WH |", " WL |",
686 " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |",
687 " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", " WK |", " WH |", " WE |"};
688 static const char *bp[] = {" |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |",
689 " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BD |", " BH |", " BL |",
690 " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |",
691 " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", " BK |", " BH |", " BE |"};
692 static char *wsqr = "";
693 static char *bsqr = "";
694 static char *top = "\t-----------------------------------------\n";
696 static char *mid = "\t-----------------------------------------\n";
697 static char *start = "|";
698 static char *end = "";
699 static char *label = "\t A B C D E F G H I J K L\n";
700 static char *blabel = "\t L K J I H G F E D C B A\n";
702 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
705 /* Miniature board */
706 static int style7(struct game_state_t *b, struct move_t *ml)
708 static const char *wp[] = {" ", " 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 const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " d", " h", " l",
711 " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k", " h", " e"};
712 static char *wsqr = "";
713 static char *bsqr = "";
714 static char *top = "\t:::::::::::::::::::::\n";
715 static char *mid = "";
716 static char *start = "..";
717 static char *end = " ..";
718 static char *label = "\t a b c d e f g h i j k l\n";
719 static char *blabel = "\t l k j i h g f e d c b a\n";
721 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
724 /* ICS interface maker board-- raw data dump */
725 static int style8(struct game_state_t *b, struct move_t *ml)
731 board_calc_strength(b, &ws, &bs);
732 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,
733 game_globals.garray[b->gameNum].white_name,
734 (orient == WHITE) ? "*" : ":",
735 game_globals.garray[b->gameNum].black_name,
736 (orient == WHITE) ? ":" : "*");
737 strcat(bstring, tmp);
738 for (r = 0; r < b->ranks; r++) {
739 for (f = 0; f < b->files; f++) {
740 if (b->board[f][r] == NOPIECE) {
741 strcat(bstring, " ");
743 if (colorval(b->board[f][r]) == WHITE)
744 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
746 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
750 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
751 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
752 (b->onMove == WHITE) ? "W" : "B",
757 game_globals.garray[b->gameNum].numHalfMoves ?
758 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
760 game_globals.garray[b->gameNum].numHalfMoves ?
761 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
763 strcat(bstring, tmp);
767 /* last 2 moves only (previous non-verbose mode) */
768 static int style9(struct game_state_t *b, struct move_t *ml)
774 sprintf(tmp, "\nMove %-23s%s\n",
775 game_globals.garray[b->gameNum].white_name,
776 game_globals.garray[b->gameNum].black_name);
777 strcat(bstring, tmp);
778 sprintf(tmp, "---- -------------- --------------\n");
779 strcat(bstring, tmp);
780 startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;
783 for (i = startmove, count = 0;
784 i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
787 sprintf(tmp, " %2d ", i / 2 + 1);
788 strcat(bstring, tmp);
790 sprintf(tmp, "%-23s", move_and_time(&ml[i]));
791 strcat(bstring, tmp);
793 strcat(bstring, "\n");
796 strcat(bstring, "\n");
800 /* Sleator's 'new and improved' raw dump format... */
801 static int style10(struct game_state_t *b, struct move_t *ml)
807 board_calc_strength(b, &ws, &bs);
808 sprintf(tmp, "<10>\n");
809 strcat(bstring, tmp);
810 for (r = b->ranks-1; r >= 0; r--) {
811 strcat(bstring, "|");
812 for (f = 0; f < b->files; f++) {
813 if (b->board[f][r] == NOPIECE) {
814 strcat(bstring, " ");
816 if (colorval(b->board[f][r]) == WHITE)
817 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
819 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
822 strcat(bstring, "|\n");
824 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
825 if (game_globals.garray[b->gameNum].numHalfMoves) {
827 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
831 strcat(bstring, tmp);
832 sprintf(tmp, "%d %d %d %d %d\n",
833 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
834 (b->wkmoved >= 0 && b->wqrmoved >= 0),
835 (b->bkmoved >= 0 && b->bkrmoved >= 0),
836 (b->bkmoved >= 0 && b->bqrmoved >= 0),
837 (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :
838 b->lastIrreversable)));
839 strcat(bstring, tmp);
840 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",
842 game_globals.garray[b->gameNum].white_name,
843 game_globals.garray[b->gameNum].black_name,
845 game_globals.garray[b->gameNum].wInitTime / 600,
846 game_globals.garray[b->gameNum].wIncrement / 10,
851 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
852 game_globals.garray[b->gameNum].numHalfMoves ?
853 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
855 game_globals.garray[b->gameNum].numHalfMoves ?
856 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
858 game_globals.garray[b->gameNum].numHalfMoves ?
859 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
861 (orient == WHITE) ? 0 : 1);
862 strcat(bstring, tmp);
863 sprintf(tmp, ">10<\n");
864 strcat(bstring, tmp);
868 /* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */
869 static int style11(struct game_state_t *b, struct move_t *ml)
875 board_calc_strength(b, &ws, &bs);
876 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,
877 game_globals.garray[b->gameNum].white_name,
878 (orient == WHITE) ? "*" : ":",
879 game_globals.garray[b->gameNum].black_name,
880 (orient == WHITE) ? ":" : "*");
881 strcat(bstring, tmp);
882 for (r = 0; r < b->ranks; r++) {
883 for (f = 0; f < b->files; f++) {
884 if (b->board[f][r] == NOPIECE) {
885 strcat(bstring, " ");
887 if (colorval(b->board[f][r]) == WHITE)
888 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
890 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
894 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
895 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
896 (b->onMove == WHITE) ? "W" : "B",
901 game_globals.garray[b->gameNum].numHalfMoves ?
902 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
904 game_globals.garray[b->gameNum].numHalfMoves ?
905 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
907 strcat(bstring, tmp);
913 /* Similar to style 10. See the "style12" help file for information */
914 static int style12(struct game_state_t *b, struct move_t *ml)
917 char tmp[160]; // [HGM] 80 caused problems with long login names
919 int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves;
920 // [HGM] setup: the number of half moves appeared in this routine an enormous number of times,
921 // and had to be dug out of the game_globals, so that this routine could only be used to print
922 // a board from a game, and not just any board given by an isolated game_state_t. This was very
923 // inconvenient for printing initial boards in move lists of shuffle variants, so I added the
924 // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0.
926 board_calc_strength(b, &ws, &bs);
928 sprintf(bstring, "<12> ");
929 for (r = b->ranks-1; r >= 0; r--) {
930 for (f = 0; f < b->files; f++) {
931 if (b->board[f][r] == NOPIECE) {
932 strcat(bstring, "-");
934 if (colorval(b->board[f][r]) == WHITE)
935 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
937 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
940 strcat(bstring, " ");
943 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
946 ml[nhm - 1].doublePawn);
950 strcat(bstring, tmp);
951 sprintf(tmp, "%d %d %d %d %d ",
952 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
953 (b->wkmoved >= 0 && b->wqrmoved >= 0),
954 (b->bkmoved >= 0 && b->bkrmoved >= 0),
955 (b->bkmoved >= 0 && b->bqrmoved >= 0),
956 (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));
957 strcat(bstring, tmp);
958 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",
960 game_globals.garray[b->gameNum].white_name,
961 game_globals.garray[b->gameNum].black_name,
963 game_globals.garray[b->gameNum].wInitTime / 600,
964 game_globals.garray[b->gameNum].wIncrement / 10,
971 ml[nhm - 1].moveString :
974 tenth_str(ml[nhm - 1].tookTime, 0) :
977 ml[nhm - 1].algString :
978 "none", (orient == WHITE) ? 0 : 1,
979 b->moveNum > 1 ? 1 : 0); /* ticking */
981 strcat(bstring, tmp);
985 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
995 fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
1008 } else if (c == 'B') {
1012 } else if (c == 'S') { int f=8, r=8;
1013 // [HGM] rules: read rule modifiers
1014 fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r;
1015 while (!feof(fp) && c != '\n') {
1019 gs->royalKnight = 1;
1022 gs->capablancaPieces = 1;
1031 gs->holdings = -1; // color-flip holdings
1037 gs->promoType = 2; // only promote to captured pieces
1038 gs->holdings = 1; // use holdings to hold own captured pieces
1041 gs->promoType = 3; // Shogi-type promotions
1044 gs->promoZone = 3; // for Grand Chess
1045 gs->pawnDblStep = 2;
1048 gs->castlingStyle = 2; // FRC castling
1051 gs->castlingStyle = 1; // wild castling, from both center files
1054 gs->castlingStyle = 0; // no castling
1057 gs->castlingStyle = 3; // free castling
1060 gs->pawnDblStep = 0; // suppress pawn double step
1063 gs->bareKingLoses = 1; // apply baring rule
1066 gs->stalemate = 0; // stalemate loses
1071 } else if (c == '#') {
1072 while (!feof(fp) && c != '\n')
1073 c = fgetc(fp); /* Comment line */
1075 } else { /* Skip any line we don't understand */
1076 while (!feof(fp) && c != '\n')
1129 onPiece = PRIESTESS;
1138 onPiece = NIGHTRIDER;
1141 onPiece = MODERNELEPHANT;
1156 onPiece = HONORABLEHORSE;
1159 onPiece = DRAGONKING;
1162 onPiece = DRAGONHORSE;
1183 onPiece = SELEPHANT;
1201 if(onFile >= gs->files) { onFile = -1; break; }
1205 if (onColor >= 0 && onPiece >= 0) // allow placement in holdings
1206 gs->holding[onColor == BLACK][onPiece-1]++;
1218 onRank = c - '1' + (gs->ranks > 9);
1219 if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; }
1220 if (onFile >= 0 && onColor >= 0 && onPiece >= 0)
1221 gs->board[onFile][onRank] = onPiece | onColor;
1224 while (!feof(fp) && c != '\n')
1225 c = fgetc(fp); /* Comment line */
1242 #define WHITE_SQUARE 1
1243 #define BLACK_SQUARE 0
1244 #define ANY_SQUARE -1
1245 #define SquareColor(f, r) ((f ^ r) & 1)
1247 static void place_piece(board_t b, int piece, int squareColor, int width)
1248 { //[HGM] board: make width a variable
1252 if (iscolor(piece, BLACK))
1258 if (squareColor == ANY_SQUARE) {
1259 f = random() % width;
1261 f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
1262 if (SquareColor(f, r) != squareColor)
1265 if ((b)[f][r] == NOPIECE) {
1272 static void wild_update(board_t b, int style)
1276 for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
1277 for (r = 0; r < 8; r++)
1279 for (f = 0; f < 8; f++) {
1285 if (random() & 0x01) {
1292 if (random() & 0x01) {
1299 b[0][0] = b[7][0] = W_ROOK;
1300 b[0][7] = b[7][7] = B_ROOK;
1301 /* Must do bishops before knights to be sure opposite colored squares are
1303 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1304 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1305 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1306 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1307 place_piece(b, B_BISHOP, WHITE_SQUARE, 8);
1308 place_piece(b, B_BISHOP, BLACK_SQUARE, 8);
1309 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1310 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1313 place_piece(b, W_KING, ANY_SQUARE, 8);
1314 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1315 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1316 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1317 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1318 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1319 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1320 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1321 /* Black mirrors White */
1322 for (i = 0; i < 8; i++) {
1323 b[i][7] = b[i][0] | BLACK;
1327 /* Generate White king on random square plus random set of pieces */
1328 place_piece(b, W_KING, ANY_SQUARE, 8);
1329 for (i = 0; i < 8; i++) {
1330 if (b[i][0] != W_KING) {
1331 b[i][0] = (random() % 4) + 2;
1334 /* Black mirrors White */
1335 for (i = 0; i < 8; i++) {
1336 b[i][7] = b[i][0] | BLACK;
1340 /* Generate White king on random square plus random set of pieces */
1341 place_piece(b, W_KING, ANY_SQUARE, 8);
1342 for (i = 0; i < 8; i++) {
1343 if (b[i][0] != W_KING) {
1344 b[i][0] = (random() % 4) + 2;
1347 /* Black has same set of pieces, but randomly permuted, except that Black
1348 must have the same number of bishops on white squares as White has on
1349 black squares, and vice versa. So we must place Black's bishops first
1350 to be sure there are enough squares left of the correct color. */
1351 for (i = 0; i < 8; i++) {
1352 if (b[i][0] == W_BISHOP) {
1353 place_piece(b, B_BISHOP, !SquareColor(i, 0), 8);
1356 for (i = 0; i < 8; i++) {
1357 if (b[i][0] != W_BISHOP) {
1358 place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8);
1363 /* Chess960 placement: King between R */
1364 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1365 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1366 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1367 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1368 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1369 for (i = j = 0; i < 8; i++) {
1370 if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK);
1372 /* Black mirrors White */
1373 for (i = 0; i < 8; i++) {
1374 b[i][7] = b[i][0] | BLACK;
1378 /* Chess960 placement: King between R */
1379 place_piece(b, W_BISHOP, WHITE_SQUARE, 10);
1380 place_piece(b, W_BISHOP, BLACK_SQUARE, 10);
1381 place_piece(b, W_QUEEN, ANY_SQUARE, 10);
1382 place_piece(b, W_MARSHALL, ANY_SQUARE, 10);
1383 place_piece(b, W_CARDINAL, ANY_SQUARE, 10);
1384 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1385 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1386 for (i = j = 0; i < 10; i++) {
1387 if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK;
1389 /* Black mirrors White */
1390 for (i = 0; i < 10; i++) {
1391 b[i][7] = b[i][0] | BLACK;
1402 fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1404 d_printf( "CHESSD: Can't write wild style %d\n", style);
1409 for (r = 1; r >= 0; r--) {
1410 for (f = 0; f < 8; f++) {
1411 if (onPiece < 0 || b[f][r] != onPiece) {
1413 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1415 fprintf(fp, " %c%c", f + 'a', r + '1');
1418 fprintf(fp, "\nB:");
1420 for (r = 6; r < 8; r++) {
1421 for (f = 0; f < 8; f++) {
1422 if (onPiece < 0 || b[f][r] != onPiece) {
1424 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1426 fprintf(fp, " %c%c", f + 'a', r + '1');
1434 void wild_init(void)