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",
28 "K", "H", "E", "W", "G", "L", "C", "H"};
29 const char *bpstring[] = {" ", "p", "n", "b", "r", "a", "c", "m", "q", "e", "b", "q", "w", "h", "n", "d", "h", "l",
30 "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a",
31 "k", "h", "e", "w", "g", "l", "c", "h"};
33 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,
34 0, 8, 9, 8, 7, 3, 3, 1};
36 static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11);
37 #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0)
39 static char bstring[MAX_BOARD_STRING_LENGTH];
41 static int board_read_file(char *category, char *gname, struct game_state_t *gs);
42 static void wild_update(board_t b, int style);
44 static int style1(struct game_state_t *b, struct move_t *ml);
45 static int style2(struct game_state_t *b, struct move_t *ml);
46 static int style3(struct game_state_t *b, struct move_t *ml);
47 static int style4(struct game_state_t *b, struct move_t *ml);
48 static int style5(struct game_state_t *b, struct move_t *ml);
49 static int style6(struct game_state_t *b, struct move_t *ml);
50 static int style7(struct game_state_t *b, struct move_t *ml);
51 static int style8(struct game_state_t *b, struct move_t *ml);
52 static int style9(struct game_state_t *b, struct move_t *ml);
53 static int style10(struct game_state_t *b, struct move_t *ml);
54 static int style11(struct game_state_t *b, struct move_t *ml);
55 static int style12(struct game_state_t *b, struct move_t *ml);
56 static int style13(struct game_state_t *b, struct move_t *ml);
58 static int (*styleFuncs[MAX_STYLES])() = {
75 static void reset_board_vars(struct game_state_t *gs)
79 if(gs->files <= 0) gs->files = 8; // [HGM] for pristine board, set default size
80 if(gs->ranks <= 0) gs->ranks = 8;
81 for (f = 0; f < 2; f++) {
82 for (r = 0; r < BW; r++)
83 gs->ep_possible[f][r] = 0;
84 for (r = PAWN; r <= PIECES-1; r++)
85 gs->holding[f][r-PAWN] = 0;
87 gs->wkmoved = gs->wqrmoved = gs->wkrmoved = -1; // [HGM] castle: no rights
88 gs->bkmoved = gs->bqrmoved = gs->bkrmoved = -1;
91 gs->lastIrreversable = -1;
95 void board_clear(struct game_state_t *gs)
99 for (f = 0; f < BW; f++)
100 for (r = 0; r < BH; r++)
101 gs->board[f][r] = NOPIECE;
102 reset_board_vars(gs);
105 void board_standard(struct game_state_t *gs)
109 for (f = 0; f < BW; f++)
110 for (r = 0; r < BH; r++)
111 gs->board[f][r] = NOPIECE;
112 for (f = 0; f < gs->files; f++)
113 gs->board[f][gs->ranks-7] = W_PAWN;
114 for (f = 0; f < gs->files; f++)
115 gs->board[f][6] = B_PAWN;
116 gs->board[0][0] = W_ROOK;
117 gs->board[1][0] = W_KNIGHT;
118 gs->board[2][0] = W_BISHOP;
119 gs->board[3][0] = W_QUEEN;
120 gs->board[gs->files/2][0] = W_KING;
121 gs->board[gs->files-3][0] = W_BISHOP;
122 gs->board[gs->files-2][0] = W_KNIGHT;
123 gs->board[gs->files-1][0] = W_ROOK;
124 gs->board[0][gs->ranks-1] = B_ROOK;
125 gs->board[1][gs->ranks-1] = B_KNIGHT;
126 gs->board[2][gs->ranks-1] = B_BISHOP;
127 gs->board[3][gs->ranks-1] = B_QUEEN;
128 gs->board[gs->files/2][gs->ranks-1] = B_KING;
129 gs->board[gs->files-3][gs->ranks-1] = B_BISHOP;
130 gs->board[gs->files-2][gs->ranks-1] = B_KNIGHT;
131 gs->board[gs->files-1][gs->ranks-1] = B_ROOK;
133 if(gs->files == 10) {
134 gs->board[6][0] = W_CARDINAL;
135 gs->board[4][0] = W_MARSHALL;
136 gs->board[6][gs->ranks-1] = B_CARDINAL;
137 gs->board[4][gs->ranks-1] = B_MARSHALL;
139 if(gs->royalKnight) {
140 gs->board[1][0] = W_MAN;
141 gs->board[gs->files-2][0] = W_MAN;
142 gs->board[1][gs->ranks-1] = B_MAN;
143 gs->board[gs->files-2][gs->ranks-1] = B_MAN;
147 reset_board_vars(gs);
148 // [HGM] castle: standard setup has rights for corner Rooks and central King
149 gs->wkmoved = gs->files/2;
150 gs->bkmoved = gs->files/2;
151 gs->wkrmoved = gs->files-1;
152 gs->bkrmoved = gs->files-1;
157 int board_init(int g,struct game_state_t *b, char *category, char *board)
162 b->files = b->ranks = 8;
163 b->pawnDblStep = (!category || strcmp(category, "shatranj"));
164 b->royalKnight = (category && !strcmp(category, "knightmate"));
165 b->capablancaPieces = 0;
168 b->castlingStyle = 1;
171 b->bareKingLoses = 0;
175 b->variant[0] = 0; // [HGM] variant: default is normal, if variant name is missing
176 if (!category || !board || !category[0] || !board[0])
177 /* accounts for bughouse too */
180 if(category && category[0]) strcpy(b->variant, category); // [HGM] variant: remember category name
181 if (!strcmp(category, "wild") && sscanf(board, "%d", &wval) == 1) {
182 if(wval >= 1 && wval <= 4)
183 wild_update(b->board, wval);
184 sprintf(b->variant, "wild/%d", wval);
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);
390 if (bh && !IsMachineStyle(style))
391 append_holding_display(bstring, b, orientation==BLACK);
393 if (styleFuncs[style] (b, ml))
397 if (IsMachineStyle(style))
398 append_holding_machine(bstring, b->gameNum, 0, 0);
400 append_holding_display(bstring, b, orientation==WHITE);
405 char *move_and_time(struct move_t *m)
410 sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */
411 m->score>0 ? "+" : "", m->score, m->depth);
414 sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0));
418 /* The following take the game state and whole move list */
420 void Enlarge(char *a, int ss, int w)
424 if(strlen(a) < ss) return;
427 p = a + l; q = p + ss;
428 while(q != a+l-ss) *q-- = *p--;
432 static int genstyle(struct game_state_t *b, struct move_t *ml, const char *wp[], const char *bp[],
433 const char *wsqr, const char *bsqr,
434 const char *top, const char *mid, const char *start, const char *end,
435 const char *label,const char *blabel)
438 char tmp[80], mylabel[80], *p, *q, myTop[80], myMid[80];
439 int firstR, lastR, firstF, lastF, inc;
440 int ws, bs, sqrSize = strlen(wp[0]);
442 board_calc_strength(b, &ws, &bs);
443 if (orient == WHITE) {
456 Enlarge(myTop, sqrSize, b->files);
457 Enlarge(myMid, sqrSize, b->files);
458 strcat(bstring, myTop);
459 for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) {
460 sprintf(tmp, " %d %s", f + (b->ranks < 10), start);
461 strcat(bstring, tmp);
462 for (r = lastF; r != firstF - inc; r = r - inc) {
463 if (square_color(r, f) == WHITE)
464 strcat(bstring, wsqr);
466 strcat(bstring, bsqr);
467 if (piecetype(b->board[r][f]) == NOPIECE) {
468 if (square_color(r, f) == WHITE)
469 strcat(bstring, bp[0]);
471 strcat(bstring, wp[0]);
473 int piece = piecetype(b->board[r][f]);
474 // if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles
475 if (colorval(b->board[r][f]) == WHITE)
476 strcat(bstring, wp[piece]);
478 strcat(bstring, bp[piece]);
481 sprintf(tmp, "%s", end);
482 strcat(bstring, tmp);
485 sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove));
486 strcat(bstring, tmp);
489 /* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */
490 /* The change from the above line to the one below is a kludge by hersco. */
491 if (game_globals.garray[b->gameNum].numHalfMoves > 0) {
492 /* loon: think this fixes the crashing ascii board on takeback bug */
493 sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)),
494 move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));
495 strcat(bstring, tmp);
501 sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
502 strcat(bstring, tmp);
505 sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
506 strcat(bstring, tmp);
509 sprintf(tmp, " Black Strength : %d", bs);
510 strcat(bstring, tmp);
513 sprintf(tmp, " White Strength : %d", ws);
514 strcat(bstring, tmp);
519 strcat(bstring, "\n");
521 strcat(bstring, myMid);
523 strcat(bstring, myTop);
526 if (orient == WHITE) {
535 if(++i > b->files) { *q++ = '\n'; *q++ = 0; }
548 *q++ = *p++ + b->files - 12;
549 if(++i >= b->files) { *q++ = '\n'; *q++ = 0; }
554 strcat(bstring, mylabel);
558 /* Experimental ANSI board for colour representation */
559 static int style13(struct game_state_t *b, struct move_t *ml)
561 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 "};
562 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 "};
563 static const char *wsqr = "\033[40m";
564 static const char *bsqr = "\033[45m";
565 static const char *top = "\t+------------------------+\n";
566 static const char *mid = "";
567 static const char *start = "|";
568 static const char *end = "\033[0m|";
569 static const char *label = "\t a b c d e f g h i j k l\n";
570 static const char *blabel = "\t l k j i h g f e d c b a\n";
572 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
576 static int style1(struct game_state_t *b, struct move_t *ml)
578 static const char *wp[] = {" |", " 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 |",
581 " K |", " H |", " E |", " W |", " G |", " L |", " C |", " H |"};
582 static const char *bp[] = {" |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|",
583 " *W|", " *H|", " *N|", " *D|", " *H|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|",
584 " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|",
585 " *K|", " *H|", " *E|", " *W|", " *G|", " *L|", " *C|", " *H|"};
586 static char *wsqr = "";
587 static char *bsqr = "";
588 static char *top = "\t---------------------------------\n";
589 static char *mid = "\t|---+---+---+---+---+---+---+---|\n";
590 static char *start = "|";
591 static char *end = "";
592 static char *label = "\t a b c d e f g h i j k l\n";
593 static char *blabel = "\t l k j i h g f e d c b a\n";
595 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
598 /* USA-Today Sports Center-style board */
599 static int style2(struct game_state_t *b, struct move_t *ml)
601 static const char *wp[] = {"- ", "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 ",
604 "K ", "H ", "E ", "W ", "G ", "L ", "C ", "H "};
605 static const char *bp[] = {"+ ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ",
606 "w' ", "h' ", "n' ", "d' ", "h' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ",
607 "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ",
608 "k' ", "h' ", "e' ", "w' ", "g' ", "l' ", "c' ", "h' "};
609 static char *wsqr = "";
610 static char *bsqr = "";
611 static char *top = "";
612 static char *mid = "";
613 static char *start = "";
614 static char *end = "";
615 static char *label = "\ta b c d e f g h i j k l\n";
616 static char *blabel = "\tl k j i h g f e d c b a\n";
618 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
621 /* Experimental vt-100 ANSI board for dark backgrounds */
622 static int style3(struct game_state_t *b, struct move_t *ml)
624 static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ",
625 " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
626 " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ",
627 " K ", " H ", " E ", " W ", " G ", " L ", " C ", " H "};
628 static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q",
629 " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
630 " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A",
631 " *K", " *H", " *E", " *W", " *G", " *L", " *C", " *H"};
632 static char *wsqr = "\033[0m";
633 static char *bsqr = "\033[7m";
634 static char *top = "\t+------------------------+\n";
635 static char *mid = "";
636 static char *start = "|";
637 static char *end = "\033[0m|";
638 static char *label = "\t a b c d e f g h i j k l\n";
639 static char *blabel = "\t l k j i h g f e d c b a\n";
641 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
644 /* Experimental vt-100 ANSI board for light backgrounds */
645 static int style4(struct game_state_t *b, struct move_t *ml)
647 static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ",
648 " W ", " H ", " N ", " D ", " H ", " L ", " C ", " S ", " G ", " H ", " A ", " F ",
649 " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ",
650 " K ", " H ", " E ", " W ", " G ", " L ", " C ", " H "};
651 static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q",
652 " *W", " *H", " *N", " *D", " *H", " *L", " *C", " *S", " *G", " *H", " *A", " *F",
653 " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A",
654 " *K", " *H", " *E", " *W", " *G", " *L", " *C", " *H"};
655 static char *wsqr = "\033[7m";
656 static char *bsqr = "\033[0m";
657 static char *top = "\t+------------------------+\n";
658 static char *mid = "";
659 static char *start = "|";
660 static char *end = "\033[0m|";
661 static char *label = "\t a b c d e f g h i j k l\n";
662 static char *blabel = "\t l k j i h g f e d c b a\n";
664 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
667 /* Style suggested by ajpierce@med.unc.edu */
668 static int style5(struct game_state_t *b, struct move_t *ml)
670 static const char *wp[] = {" ", " o ", " :N:", " <B>", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!",
671 " <B>", " {Q}", " .W.", " :H:", " :N:", " <H>", " |D|", " |L|",
672 " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:",
673 " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&",
674 " =K=", " (H)", " [E]", " (W)", " [G]", " <L>", " |C|", " h "};
675 static const char *bp[] = {" ", " p ", " :n:", " <b>", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!",
676 " <b>", " {q}", " .w.", " :h:", " :n:", " <h>", " |d|", " |l|",
677 " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:",
678 " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&",
679 " =k=", " (f)", " [e]", " (w)", " [g]", " <l>", " |c|", " h "};
680 static char *wsqr = "";
681 static char *bsqr = "";
682 static char *top = " . . . . . . . . .\n";
683 static char *mid = " . . . . . . . . .\n";
684 static char *start = "";
685 static char *end = "";
686 static char *label = "\t a b c d e f g h i j k l\n";
687 static char *blabel = "\t l k j i h g f e d c b a\n";
689 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
692 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
693 static int style6(struct game_state_t *b, struct move_t *ml)
695 static const char *wp[] = {" |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |",
696 " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WD |", " WH |", " WL |",
697 " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |",
698 " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |",
699 " WK |", " WH |", " WE |", " WW |", " WG |", " WL |", " WC |", " Wh |"};
700 static const char *bp[] = {" |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |",
701 " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BD |", " BH |", " BL |",
702 " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |",
703 " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |",
704 " BK |", " BH |", " BE |", " BW |", " BG |", " BL |", " BC |", " Bh |"};
705 static char *wsqr = "";
706 static char *bsqr = "";
707 static char *top = "\t-----------------------------------------\n";
709 static char *mid = "\t-----------------------------------------\n";
710 static char *start = "|";
711 static char *end = "";
712 static char *label = "\t A B C D E F G H I J K L\n";
713 static char *blabel = "\t L K J I H G F E D C B A\n";
715 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
718 /* Miniature board */
719 static int style7(struct game_state_t *b, struct move_t *ml)
721 static const char *wp[] = {" ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " D", " H", " L",
722 " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A",
723 " K", " H", " E", " W", " G", " L", " C", " H"};
724 static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " d", " h", " l",
725 " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a",
726 " k", " h", " e", " w", " g", " l", " c", " h"};
727 static char *wsqr = "";
728 static char *bsqr = "";
729 static char *top = "\t:::::::::::::::::::::\n";
730 static char *mid = "";
731 static char *start = "..";
732 static char *end = " ..";
733 static char *label = "\t a b c d e f g h i j k l\n";
734 static char *blabel = "\t l k j i h g f e d c b a\n";
736 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
739 /* ICS interface maker board-- raw data dump */
740 static int style8(struct game_state_t *b, struct move_t *ml)
746 board_calc_strength(b, &ws, &bs);
747 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,
748 game_globals.garray[b->gameNum].white_name,
749 (orient == WHITE) ? "*" : ":",
750 game_globals.garray[b->gameNum].black_name,
751 (orient == WHITE) ? ":" : "*");
752 strcat(bstring, tmp);
753 for (r = 0; r < b->ranks; r++) {
754 for (f = 0; f < b->files; f++) {
755 if (b->board[f][r] == NOPIECE) {
756 strcat(bstring, " ");
758 if (colorval(b->board[f][r]) == WHITE)
759 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
761 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
765 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
766 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
767 (b->onMove == WHITE) ? "W" : "B",
772 game_globals.garray[b->gameNum].numHalfMoves ?
773 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
775 game_globals.garray[b->gameNum].numHalfMoves ?
776 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
778 strcat(bstring, tmp);
782 /* last 2 moves only (previous non-verbose mode) */
783 static int style9(struct game_state_t *b, struct move_t *ml)
789 sprintf(tmp, "\nMove %-23s%s\n",
790 game_globals.garray[b->gameNum].white_name,
791 game_globals.garray[b->gameNum].black_name);
792 strcat(bstring, tmp);
793 sprintf(tmp, "---- -------------- --------------\n");
794 strcat(bstring, tmp);
795 startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;
798 for (i = startmove, count = 0;
799 i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
802 sprintf(tmp, " %2d ", i / 2 + 1);
803 strcat(bstring, tmp);
805 sprintf(tmp, "%-23s", move_and_time(&ml[i]));
806 strcat(bstring, tmp);
808 strcat(bstring, "\n");
811 strcat(bstring, "\n");
815 /* Sleator's 'new and improved' raw dump format... */
816 static int style10(struct game_state_t *b, struct move_t *ml)
822 board_calc_strength(b, &ws, &bs);
823 sprintf(tmp, "<10>\n");
824 strcat(bstring, tmp);
825 for (r = b->ranks-1; r >= 0; r--) {
826 strcat(bstring, "|");
827 for (f = 0; f < b->files; f++) {
828 if (b->board[f][r] == NOPIECE) {
829 strcat(bstring, " ");
831 if (colorval(b->board[f][r]) == WHITE)
832 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
834 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
837 strcat(bstring, "|\n");
839 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
840 if (game_globals.garray[b->gameNum].numHalfMoves) {
842 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
846 strcat(bstring, tmp);
847 sprintf(tmp, "%d %d %d %d %d\n",
848 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
849 (b->wkmoved >= 0 && b->wqrmoved >= 0),
850 (b->bkmoved >= 0 && b->bkrmoved >= 0),
851 (b->bkmoved >= 0 && b->bqrmoved >= 0),
852 (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :
853 b->lastIrreversable)));
854 strcat(bstring, tmp);
855 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",
857 game_globals.garray[b->gameNum].white_name,
858 game_globals.garray[b->gameNum].black_name,
860 game_globals.garray[b->gameNum].wInitTime / 600,
861 game_globals.garray[b->gameNum].wIncrement / 10,
866 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
867 game_globals.garray[b->gameNum].numHalfMoves ?
868 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
870 game_globals.garray[b->gameNum].numHalfMoves ?
871 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
873 game_globals.garray[b->gameNum].numHalfMoves ?
874 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
876 (orient == WHITE) ? 0 : 1);
877 strcat(bstring, tmp);
878 sprintf(tmp, ">10<\n");
879 strcat(bstring, tmp);
883 /* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */
884 static int style11(struct game_state_t *b, struct move_t *ml)
890 board_calc_strength(b, &ws, &bs);
891 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,
892 game_globals.garray[b->gameNum].white_name,
893 (orient == WHITE) ? "*" : ":",
894 game_globals.garray[b->gameNum].black_name,
895 (orient == WHITE) ? ":" : "*");
896 strcat(bstring, tmp);
897 for (r = 0; r < b->ranks; r++) {
898 for (f = 0; f < b->files; f++) {
899 if (b->board[f][r] == NOPIECE) {
900 strcat(bstring, " ");
902 if (colorval(b->board[f][r]) == WHITE)
903 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
905 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
909 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
910 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
911 (b->onMove == WHITE) ? "W" : "B",
916 game_globals.garray[b->gameNum].numHalfMoves ?
917 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
919 game_globals.garray[b->gameNum].numHalfMoves ?
920 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
922 strcat(bstring, tmp);
928 /* Similar to style 10. See the "style12" help file for information */
929 static int style12(struct game_state_t *b, struct move_t *ml)
932 char tmp[160]; // [HGM] 80 caused problems with long login names
934 int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves;
935 // [HGM] setup: the number of half moves appeared in this routine an enormous number of times,
936 // and had to be dug out of the game_globals, so that this routine could only be used to print
937 // a board from a game, and not just any board given by an isolated game_state_t. This was very
938 // inconvenient for printing initial boards in move lists of shuffle variants, so I added the
939 // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0.
941 board_calc_strength(b, &ws, &bs);
943 sprintf(bstring, "<12> ");
944 for (r = b->ranks-1; r >= 0; r--) {
945 for (f = 0; f < b->files; f++) {
946 if (b->board[f][r] == NOPIECE) {
947 strcat(bstring, "-");
949 if (colorval(b->board[f][r]) == WHITE)
950 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
952 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
955 strcat(bstring, " ");
958 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
961 ml[nhm - 1].doublePawn);
965 strcat(bstring, tmp);
966 sprintf(tmp, "%d %d %d %d %d ",
967 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
968 (b->wkmoved >= 0 && b->wqrmoved >= 0),
969 (b->bkmoved >= 0 && b->bkrmoved >= 0),
970 (b->bkmoved >= 0 && b->bqrmoved >= 0),
971 (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));
972 strcat(bstring, tmp);
973 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",
975 game_globals.garray[b->gameNum].white_name,
976 game_globals.garray[b->gameNum].black_name,
978 game_globals.garray[b->gameNum].wInitTime / 600,
979 game_globals.garray[b->gameNum].wIncrement / 10,
986 ml[nhm - 1].moveString :
989 tenth_str(ml[nhm - 1].tookTime, 0) :
992 ml[nhm - 1].algString :
993 "none", (orient == WHITE) ? 0 : 1,
994 b->moveNum > 1 ? 1 : 0); /* ticking */
996 strcat(bstring, tmp);
1000 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
1010 fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
1016 if (gname && !strcmp(gname, "0"))
1017 gs->setup = 0; // [HGM] variant: any board in the default file "0" is supposed to be implied by the variant
1026 } else if (c == 'B') {
1030 } else if (c == 'S') { int f=8, r=8;
1031 // [HGM] rules: read rule modifiers
1032 fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r;
1033 while (!feof(fp) && c != '\n') {
1037 gs->royalKnight = 1;
1040 gs->capablancaPieces = 1;
1049 gs->holdings = -1; // color-flip holdings
1055 gs->promoType = 2; // only promote to captured pieces
1056 gs->holdings = 1; // use holdings to hold own captured pieces
1059 gs->promoType = 3; // Shogi-type promotions
1062 gs->promoZone = 3; // for Grand Chess
1063 gs->pawnDblStep = 2;
1066 gs->castlingStyle = 2; // FRC castling
1069 gs->castlingStyle = 1; // wild castling, from both center files
1072 gs->castlingStyle = 0; // no castling
1075 gs->castlingStyle = 3; // free castling
1078 gs->pawnDblStep = 0; // suppress pawn double step
1081 gs->bareKingLoses = 1; // apply baring rule
1084 gs->stalemate = 0; // stalemate loses
1089 } else if (c == '#') {
1090 while (!feof(fp) && c != '\n')
1091 c = fgetc(fp); /* Comment line */
1093 } else { /* Skip any line we don't understand */
1094 while (!feof(fp) && c != '\n')
1111 onPiece = SELEPHANT;
1126 onPiece = DRAGONHORSE;
1129 onPiece = DRAGONKING;
1183 onPiece = HONORABLEHORSE;
1186 onPiece = MODERNELEPHANT;
1189 onPiece = PRIESTESS;
1204 onPiece = NIGHTRIDER;
1213 onPiece = LIEUTENANT;
1234 if(onFile >= gs->files) { onFile = -1; break; }
1238 if (onColor >= 0 && onPiece >= 0) // allow placement in holdings
1239 gs->holding[onColor == BLACK][onPiece-1]++;
1251 onRank = c - '1' + (gs->ranks > 9);
1252 if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; }
1253 if (onFile >= 0 && onColor >= 0 && onPiece >= 0)
1254 gs->board[onFile][onRank] = onPiece | onColor;
1257 while (!feof(fp) && c != '\n')
1258 c = fgetc(fp); /* Comment line */
1275 #define WHITE_SQUARE 1
1276 #define BLACK_SQUARE 0
1277 #define ANY_SQUARE -1
1278 #define SquareColor(f, r) ((f ^ r) & 1)
1280 static void place_piece(board_t b, int piece, int squareColor, int width)
1281 { //[HGM] board: make width a variable
1285 if (iscolor(piece, BLACK))
1291 if (squareColor == ANY_SQUARE) {
1292 f = random() % width;
1294 f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
1295 if (SquareColor(f, r) != squareColor)
1298 if ((b)[f][r] == NOPIECE) {
1305 static void wild_update(board_t b, int style)
1309 for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
1310 for (r = 0; r < 8; r++)
1312 for (f = 0; f < 8; f++) {
1318 if (random() & 0x01) {
1325 if (random() & 0x01) {
1332 b[0][0] = b[7][0] = W_ROOK;
1333 b[0][7] = b[7][7] = B_ROOK;
1334 /* Must do bishops before knights to be sure opposite colored squares are
1336 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1337 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1338 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1339 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1340 place_piece(b, B_BISHOP, WHITE_SQUARE, 8);
1341 place_piece(b, B_BISHOP, BLACK_SQUARE, 8);
1342 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1343 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1346 place_piece(b, W_KING, ANY_SQUARE, 8);
1347 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1348 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1349 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1350 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1351 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1352 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1353 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1354 /* Black mirrors White */
1355 for (i = 0; i < 8; i++) {
1356 b[i][7] = b[i][0] | BLACK;
1360 /* Generate White king on random square plus random set of pieces */
1361 place_piece(b, W_KING, ANY_SQUARE, 8);
1362 for (i = 0; i < 8; i++) {
1363 if (b[i][0] != W_KING) {
1364 b[i][0] = (random() % 4) + 2; if(b[i][0] == 5) b[i][0] += 3;
1367 /* Black mirrors White */
1368 for (i = 0; i < 8; i++) {
1369 b[i][7] = b[i][0] | BLACK;
1373 /* Generate White king on random square plus random set of pieces */
1374 place_piece(b, W_KING, ANY_SQUARE, 8);
1375 for (i = 0; i < 8; i++) {
1376 if (b[i][0] != W_KING) {
1377 b[i][0] = (random() % 4) + 2; if(b[i][0] == 5) b[i][0] += 3;
1380 /* Black has same set of pieces, but randomly permuted, except that Black
1381 must have the same number of bishops on white squares as White has on
1382 black squares, and vice versa. So we must place Black's bishops first
1383 to be sure there are enough squares left of the correct color. */
1384 for (i = 0; i < 8; i++) {
1385 if (b[i][0] == W_BISHOP) {
1386 place_piece(b, B_BISHOP, !SquareColor(i, 0), 8);
1389 for (i = 0; i < 8; i++) {
1390 if (b[i][0] != W_BISHOP) {
1391 place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8);
1396 /* Chess960 placement: King between R */
1397 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1398 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1399 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1400 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1401 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1402 for (i = j = 0; i < 8; i++) {
1403 if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK);
1405 /* Black mirrors White */
1406 for (i = 0; i < 8; i++) {
1407 b[i][7] = b[i][0] | BLACK;
1411 /* Chess960 placement: King between R */
1412 place_piece(b, W_BISHOP, WHITE_SQUARE, 10);
1413 place_piece(b, W_BISHOP, BLACK_SQUARE, 10);
1414 place_piece(b, W_QUEEN, ANY_SQUARE, 10);
1415 place_piece(b, W_MARSHALL, ANY_SQUARE, 10);
1416 place_piece(b, W_CARDINAL, ANY_SQUARE, 10);
1417 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1418 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1419 for (i = j = 0; i < 10; i++) {
1420 if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK;
1422 /* Black mirrors White */
1423 for (i = 0; i < 10; i++) {
1424 b[i][7] = b[i][0] | BLACK;
1435 fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1437 d_printf( "CHESSD: Can't write wild style %d\n", style);
1442 for (r = 1; r >= 0; r--) {
1443 for (f = 0; f < 8; f++) {
1444 if (onPiece < 0 || b[f][r] != onPiece) {
1446 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1448 fprintf(fp, " %c%c", f + 'a', r + '1');
1451 fprintf(fp, "\nB:");
1453 for (r = 6; r < 8; r++) {
1454 for (f = 0; f < 8; f++) {
1455 if (onPiece < 0 || b[f][r] != onPiece) {
1457 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1459 fprintf(fp, " %c%c", f + 'a', r + '1');
1467 void wild_init(void)