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 (!strcmp(category, "knightmate")) {
186 } else if (!strcmp(category, "super")) {
190 for(i=CENTAUR; i<=AMAZON; i++) {
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;
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")) {
210 wild_update(b->board, 46);
211 b->castlingStyle = 2;
213 } else retval = board_read_file(category, board, b);
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;
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) {
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;
237 MakeFENpos(g, game_globals.garray[g].FENstartPos);
242 void board_calc_strength(struct game_state_t *b, int *ws, int *bs)
248 for (f = 0; f < b->ranks; f++) {
249 for (r = 0; r < b->files; r++) {
250 if (colorval(b->board[r][f]) == WHITE)
254 *p += pieceValues[piecetype(b->board[r][f])];
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];
263 static char *holding_str(int *holding)
269 for (p = PAWN; p < PIECES; p++) {
270 for (j = 0; j < holding[p-1]; j++) {
271 tmp[i++] = wpstring[p][0];
278 static char *append_holding_machine(char *buf, int g, int c, int p)
280 struct game_state_t *gs = &game_globals.garray[g].game_state;
283 sprintf(tmp, "<b1> game %d white [%s] black [", g+1, holding_str(gs->holding[0]));
284 strcat(tmp, holding_str(gs->holding[1]));
287 sprintf(tmp, "] <- %c%s\n", "WB"[c], wpstring[p]);
294 static char *append_holding_display(char *buf, struct game_state_t *gs, int white)
297 strcat(buf, "White holding: [");
299 strcat(buf, "Black holding: [");
300 strcat(buf, holding_str(gs->holding[white ? 0 : 1]));
305 void update_holding(int g, int pieceCaptured)
307 int p = piecetype(pieceCaptured);
308 int c = colorval(pieceCaptured);
309 struct game_state_t *gs = &game_globals.garray[g].game_state;
311 char tmp1[160], tmp2[160];
315 pp = game_globals.garray[g].white;
318 pp = game_globals.garray[g].black;
320 gs->holding[c][p-1]++;
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)
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);
335 /* Globals used for each board */
336 static int wTime, bTime;
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) */
343 char *board_to_string(char *wn, char *bn,
345 struct game_state_t *b, struct move_t *ml, int style,
346 int orientation, int relation,
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;
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;
363 wTime = ml[nhm - 1].wTime;
364 bTime = ml[nhm - 1].bTime;
366 wTime = game_globals.garray[b->gameNum].wInitTime;
367 bTime = game_globals.garray[b->gameNum].bInitTime;
371 /* cope with old stored games */
372 if (wTime == 0) wTime = wt;
373 if (bTime == 0) bTime = bt;
376 if ((style < 0) || (style >= MAX_STYLES))
379 if (style != 11) { /* game header */
380 sprintf(bstring, "Game %d (%s vs. %s)\n\n",
382 game_globals.garray[b->gameNum].white_name,
383 game_globals.garray[b->gameNum].black_name);
387 if (bh && !IsMachineStyle(style))
388 append_holding_display(bstring, b, orientation==BLACK);
390 if (styleFuncs[style] (b, ml))
394 if (IsMachineStyle(style))
395 append_holding_machine(bstring, b->gameNum, 0, 0);
397 append_holding_display(bstring, b, orientation==WHITE);
402 char *move_and_time(struct move_t *m)
407 sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */
408 m->score>0 ? "+" : "", m->score, m->depth);
411 sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
415 /* The following take the game state and whole move list */
417 void Enlarge(char *a, int ss, int w)
421 if(strlen(a) < ss) return;
424 p = a + l; q = p + ss;
425 while(q != a+l-ss) *q-- = *p--;
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)
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]);
439 board_calc_strength(b, &ws, &bs);
440 if (orient == WHITE) {
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);
463 strcat(bstring, bsqr);
464 if (piecetype(b->board[r][f]) == NOPIECE) {
465 if (square_color(r, f) == WHITE)
466 strcat(bstring, bp[0]);
468 strcat(bstring, wp[0]);
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]);
475 strcat(bstring, bp[piece]);
478 sprintf(tmp, "%s", end);
479 strcat(bstring, tmp);
482 sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove));
483 strcat(bstring, tmp);
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);
498 sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
499 strcat(bstring, tmp);
502 sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
503 strcat(bstring, tmp);
506 sprintf(tmp, " Black Strength : %d", bs);
507 strcat(bstring, tmp);
510 sprintf(tmp, " White Strength : %d", ws);
511 strcat(bstring, tmp);
516 strcat(bstring, "\n");
518 strcat(bstring, myMid);
520 strcat(bstring, myTop);
523 if (orient == WHITE) {
532 if(++i > b->files) { *q++ = '\n'; *q++ = 0; }
545 *q++ = *p++ + b->files - 12;
546 if(++i >= b->files) { *q++ = '\n'; *q++ = 0; }
551 strcat(bstring, mylabel);
555 /* Experimental ANSI board for colour representation */
556 static int style13(struct game_state_t *b, struct move_t *ml)
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";
569 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
573 static int style1(struct game_state_t *b, struct move_t *ml)
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";
590 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
593 /* USA-Today Sports Center-style board */
594 static int style2(struct game_state_t *b, struct move_t *ml)
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";
611 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
614 /* Experimental vt-100 ANSI board for dark backgrounds */
615 static int style3(struct game_state_t *b, struct move_t *ml)
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";
632 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
635 /* Experimental vt-100 ANSI board for light backgrounds */
636 static int style4(struct game_state_t *b, struct move_t *ml)
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";
653 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
656 /* Style suggested by ajpierce@med.unc.edu */
657 static int style5(struct game_state_t *b, struct move_t *ml)
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";
676 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
679 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
680 static int style6(struct game_state_t *b, struct move_t *ml)
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";
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";
700 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
703 /* Miniature board */
704 static int style7(struct game_state_t *b, struct move_t *ml)
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";
719 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
722 /* ICS interface maker board-- raw data dump */
723 static int style8(struct game_state_t *b, struct move_t *ml)
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, " ");
741 if (colorval(b->board[f][r]) == WHITE)
742 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
744 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
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",
755 game_globals.garray[b->gameNum].numHalfMoves ?
756 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
758 game_globals.garray[b->gameNum].numHalfMoves ?
759 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
761 strcat(bstring, tmp);
765 /* last 2 moves only (previous non-verbose mode) */
766 static int style9(struct game_state_t *b, struct move_t *ml)
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;
781 for (i = startmove, count = 0;
782 i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
785 sprintf(tmp, " %2d ", i / 2 + 1);
786 strcat(bstring, tmp);
788 sprintf(tmp, "%-23s", move_and_time(&ml[i]));
789 strcat(bstring, tmp);
791 strcat(bstring, "\n");
794 strcat(bstring, "\n");
798 /* Sleator's 'new and improved' raw dump format... */
799 static int style10(struct game_state_t *b, struct move_t *ml)
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, " ");
814 if (colorval(b->board[f][r]) == WHITE)
815 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
817 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
820 strcat(bstring, "|\n");
822 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
823 if (game_globals.garray[b->gameNum].numHalfMoves) {
825 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
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",
840 game_globals.garray[b->gameNum].white_name,
841 game_globals.garray[b->gameNum].black_name,
843 game_globals.garray[b->gameNum].wInitTime / 600,
844 game_globals.garray[b->gameNum].wIncrement / 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 :
853 game_globals.garray[b->gameNum].numHalfMoves ?
854 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
856 game_globals.garray[b->gameNum].numHalfMoves ?
857 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
859 (orient == WHITE) ? 0 : 1);
860 strcat(bstring, tmp);
861 sprintf(tmp, ">10<\n");
862 strcat(bstring, tmp);
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)
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, " ");
885 if (colorval(b->board[f][r]) == WHITE)
886 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
888 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
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",
899 game_globals.garray[b->gameNum].numHalfMoves ?
900 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
902 game_globals.garray[b->gameNum].numHalfMoves ?
903 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
905 strcat(bstring, tmp);
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)
915 char tmp[160]; // [HGM] 80 caused problems with long login names
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.
924 board_calc_strength(b, &ws, &bs);
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, "-");
932 if (colorval(b->board[f][r]) == WHITE)
933 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
935 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
938 strcat(bstring, " ");
941 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
944 ml[nhm - 1].doublePawn);
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",
958 game_globals.garray[b->gameNum].white_name,
959 game_globals.garray[b->gameNum].black_name,
961 game_globals.garray[b->gameNum].wInitTime / 600,
962 game_globals.garray[b->gameNum].wIncrement / 10,
969 ml[nhm - 1].moveString :
972 tenth_str(ml[nhm - 1].tookTime, 0) :
975 ml[nhm - 1].algString :
976 "none", (orient == WHITE) ? 0 : 1,
977 b->moveNum > 1 ? 1 : 0); /* ticking */
979 strcat(bstring, tmp);
983 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
993 fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
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
1009 } else if (c == 'B') {
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') {
1020 gs->royalKnight = 1;
1023 gs->capablancaPieces = 1;
1032 gs->holdings = -1; // color-flip holdings
1038 gs->promoType = 2; // only promote to captured pieces
1039 gs->holdings = 1; // use holdings to hold own captured pieces
1042 gs->promoType = 3; // Shogi-type promotions
1045 gs->promoZone = 3; // for Grand Chess
1046 gs->pawnDblStep = 2;
1049 gs->castlingStyle = 2; // FRC castling
1052 gs->castlingStyle = 1; // wild castling, from both center files
1055 gs->castlingStyle = 0; // no castling
1058 gs->castlingStyle = 3; // free castling
1061 gs->pawnDblStep = 0; // suppress pawn double step
1064 gs->bareKingLoses = 1; // apply baring rule
1067 gs->stalemate = 0; // stalemate loses
1072 } else if (c == '#') {
1073 while (!feof(fp) && c != '\n')
1074 c = fgetc(fp); /* Comment line */
1076 } else { /* Skip any line we don't understand */
1077 while (!feof(fp) && c != '\n')
1130 onPiece = PRIESTESS;
1139 onPiece = NIGHTRIDER;
1142 onPiece = MODERNELEPHANT;
1157 onPiece = HONORABLEHORSE;
1160 onPiece = DRAGONKING;
1163 onPiece = DRAGONHORSE;
1184 onPiece = SELEPHANT;
1202 if(onFile >= gs->files) { onFile = -1; break; }
1206 if (onColor >= 0 && onPiece >= 0) // allow placement in holdings
1207 gs->holding[onColor == BLACK][onPiece-1]++;
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;
1225 while (!feof(fp) && c != '\n')
1226 c = fgetc(fp); /* Comment line */
1243 #define WHITE_SQUARE 1
1244 #define BLACK_SQUARE 0
1245 #define ANY_SQUARE -1
1246 #define SquareColor(f, r) ((f ^ r) & 1)
1248 static void place_piece(board_t b, int piece, int squareColor, int width)
1249 { //[HGM] board: make width a variable
1253 if (iscolor(piece, BLACK))
1259 if (squareColor == ANY_SQUARE) {
1260 f = random() % width;
1262 f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
1263 if (SquareColor(f, r) != squareColor)
1266 if ((b)[f][r] == NOPIECE) {
1273 static void wild_update(board_t b, int style)
1277 for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
1278 for (r = 0; r < 8; r++)
1280 for (f = 0; f < 8; f++) {
1286 if (random() & 0x01) {
1293 if (random() & 0x01) {
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
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);
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;
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;
1335 /* Black mirrors White */
1336 for (i = 0; i < 8; i++) {
1337 b[i][7] = b[i][0] | BLACK;
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;
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);
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);
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);
1373 /* Black mirrors White */
1374 for (i = 0; i < 8; i++) {
1375 b[i][7] = b[i][0] | BLACK;
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;
1390 /* Black mirrors White */
1391 for (i = 0; i < 10; i++) {
1392 b[i][7] = b[i][0] | BLACK;
1403 fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1405 d_printf( "CHESSD: Can't write wild style %d\n", style);
1410 for (r = 1; r >= 0; r--) {
1411 for (f = 0; f < 8; f++) {
1412 if (onPiece < 0 || b[f][r] != onPiece) {
1414 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1416 fprintf(fp, " %c%c", f + 'a', r + '1');
1419 fprintf(fp, "\nB:");
1421 for (r = 6; r < 8; r++) {
1422 for (f = 0; f < 8; f++) {
1423 if (onPiece < 0 || b[f][r] != onPiece) {
1425 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1427 fprintf(fp, " %c%c", f + 'a', r + '1');
1435 void wild_init(void)