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"};
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"};
31 int pieceValues[KING+1] = {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};
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 <= KING-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++)
\r
107 for (r = 0; r < BH; r++)
\r
108 gs->board[f][r] = NOPIECE;
\r
109 for (f = 0; f < gs->files; f++)
\r
110 gs->board[f][gs->ranks-7] = W_PAWN;
\r
111 for (f = 0; f < gs->files; f++)
\r
112 gs->board[f][6] = B_PAWN;
\r
113 gs->board[0][0] = W_ROOK;
\r
114 gs->board[1][0] = W_KNIGHT;
\r
115 gs->board[2][0] = W_BISHOP;
\r
116 gs->board[3][0] = W_QUEEN;
\r
117 gs->board[gs->files/2][0] = W_KING;
\r
118 gs->board[gs->files-3][0] = W_BISHOP;
\r
119 gs->board[gs->files-2][0] = W_KNIGHT;
\r
120 gs->board[gs->files-1][0] = W_ROOK;
\r
121 gs->board[0][gs->ranks-1] = B_ROOK;
\r
122 gs->board[1][gs->ranks-1] = B_KNIGHT;
\r
123 gs->board[2][gs->ranks-1] = B_BISHOP;
\r
124 gs->board[3][gs->ranks-1] = B_QUEEN;
\r
125 gs->board[gs->files/2][gs->ranks-1] = B_KING;
\r
126 gs->board[gs->files-3][gs->ranks-1] = B_BISHOP;
\r
127 gs->board[gs->files-2][gs->ranks-1] = B_KNIGHT;
\r
128 gs->board[gs->files-1][gs->ranks-1] = B_ROOK;
\r
130 if(gs->files == 10) {
\r
131 gs->board[6][0] = W_CARDINAL;
\r
132 gs->board[4][0] = W_MARSHALL;
\r
133 gs->board[6][gs->ranks-1] = B_CARDINAL;
\r
134 gs->board[4][gs->ranks-1] = B_MARSHALL;
\r
136 if(gs->royalKnight) {
\r
137 gs->board[1][0] = W_MAN;
\r
138 gs->board[gs->files-2][0] = W_MAN;
\r
139 gs->board[1][gs->ranks-1] = B_MAN;
\r
140 gs->board[gs->files-2][gs->ranks-1] = B_MAN;
\r
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;
\r
160 b->pawnDblStep = (!category || strcmp(category, "shatranj"));
\r
161 b->royalKnight = (category && !strcmp(category, "knightmate"));
\r
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
\r
173 if (!category || !board || !category[0] || !board[0])
\r
174 /* accounts for bughouse too */
\r
177 if(category && category[0]) strcpy(b->variant, category); // [HGM] variant: remember category name
\r
178 if (!strcmp(category, "wild") && sscanf(board, "%d", &wval) == 1) {
179 if(wval >= 1 && wval <= 4)
\r
180 wild_update(b->board, wval);
181 sprintf(b->variant, "wild/%d", wval);
\r
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
\r
187 if (!strcmp(category, "knightmate")) {
\r
189 } else if (!strcmp(category, "super")) {
\r
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")) {
\r
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
\r
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);
\r
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 < KING; 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 < KING; 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 ); // [HGM] zh: make sure holdings are printed
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)
436 int f, r, count, i;
\r
437 char tmp[80], mylabel[80], *p, *q, myTop[80], myMid[80];
\r
438 int firstR, lastR, firstF, lastF, inc;
\r
439 int ws, bs, sqrSize = strlen(wp[0]);
\r
441 board_calc_strength(b, &ws, &bs);
\r
442 if (orient == WHITE) {
\r
443 firstR = b->ranks-1;
\r
444 firstF = b->files-1;
\r
448 firstR = firstF = 0;
\r
449 lastR = b->ranks-1;
\r
450 lastF = b->files-1;
\r
455 Enlarge(myTop, sqrSize, b->files);
\r
456 Enlarge(myMid, sqrSize, b->files);
\r
457 strcat(bstring, myTop);
\r
458 for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) {
\r
459 sprintf(tmp, " %d %s", f + (b->ranks < 10), start);
\r
460 strcat(bstring, tmp);
\r
461 for (r = lastF; r != firstF - inc; r = r - inc) {
\r
462 if (square_color(r, f) == WHITE)
\r
463 strcat(bstring, wsqr);
\r
465 strcat(bstring, bsqr);
\r
466 if (piecetype(b->board[r][f]) == NOPIECE) {
\r
467 if (square_color(r, f) == WHITE)
\r
468 strcat(bstring, bp[0]);
\r
470 strcat(bstring, wp[0]);
\r
472 int piece = piecetype(b->board[r][f]);
473 // if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles
\r
474 if (colorval(b->board[r][f]) == WHITE)
\r
475 strcat(bstring, wp[piece]);
\r
477 strcat(bstring, bp[piece]);
\r
480 sprintf(tmp, "%s", end);
\r
481 strcat(bstring, tmp);
\r
484 sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove));
\r
485 strcat(bstring, tmp);
\r
488 /* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */
\r
489 /* The change from the above line to the one below is a kludge by hersco. */
\r
490 if (game_globals.garray[b->gameNum].numHalfMoves > 0) {
\r
491 /* loon: think this fixes the crashing ascii board on takeback bug */
\r
492 sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)),
\r
493 move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1]));
\r
494 strcat(bstring, tmp);
\r
500 sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1));
\r
501 strcat(bstring, tmp);
\r
504 sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1));
\r
505 strcat(bstring, tmp);
\r
508 sprintf(tmp, " Black Strength : %d", bs);
\r
509 strcat(bstring, tmp);
\r
512 sprintf(tmp, " White Strength : %d", ws);
\r
513 strcat(bstring, tmp);
\r
518 strcat(bstring, "\n");
\r
520 strcat(bstring, myMid);
\r
522 strcat(bstring, myTop);
\r
525 if (orient == WHITE) {
\r
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);
\r
557 /* Experimental ANSI board for colour representation */
\r
558 static int style13(struct game_state_t *b, struct move_t *ml)
\r
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 "};
\r
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 "};
\r
562 static const char *wsqr = "\033[40m";
\r
563 static const char *bsqr = "\033[45m";
\r
564 static const char *top = "\t+------------------------+\n";
\r
565 static const char *mid = "";
\r
566 static const char *start = "|";
\r
567 static const char *end = "\033[0m|";
\r
568 static const char *label = "\t a b c d e f g h i j k l\n";
\r
569 static const char *blabel = "\t l k j i h g f e d c b a\n";
\r
571 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
575 static int style1(struct game_state_t *b, struct move_t *ml)
\r
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 |"};
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|"};
583 static char *wsqr = "";
\r
584 static char *bsqr = "";
\r
585 static char *top = "\t---------------------------------\n";
\r
586 static char *mid = "\t|---+---+---+---+---+---+---+---|\n";
\r
587 static char *start = "|";
\r
588 static char *end = "";
\r
589 static char *label = "\t a b c d e f g h i j k l\n";
\r
590 static char *blabel = "\t l k j i h g f e d c b a\n";
\r
592 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
595 /* USA-Today Sports Center-style board */
\r
596 static int style2(struct game_state_t *b, struct move_t *ml)
\r
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 "};
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' "};
604 static char *wsqr = "";
\r
605 static char *bsqr = "";
\r
606 static char *top = "";
\r
607 static char *mid = "";
\r
608 static char *start = "";
\r
609 static char *end = "";
\r
610 static char *label = "\ta b c d e f g h i j k l\n";
\r
611 static char *blabel = "\tl k j i h g f e d c b a\n";
\r
613 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
616 /* Experimental vt-100 ANSI board for dark backgrounds */
\r
617 static int style3(struct game_state_t *b, struct move_t *ml)
\r
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 "};
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"};
625 static char *wsqr = "\033[0m";
\r
626 static char *bsqr = "\033[7m";
\r
627 static char *top = "\t+------------------------+\n";
\r
628 static char *mid = "";
\r
629 static char *start = "|";
\r
630 static char *end = "\033[0m|";
\r
631 static char *label = "\t a b c d e f g h i j k l\n";
\r
632 static char *blabel = "\t l k j i h g f e d c b a\n";
\r
634 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
637 /* Experimental vt-100 ANSI board for light backgrounds */
\r
638 static int style4(struct game_state_t *b, struct move_t *ml)
\r
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 "};
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"};
646 static char *wsqr = "\033[7m";
\r
647 static char *bsqr = "\033[0m";
\r
648 static char *top = "\t+------------------------+\n";
\r
649 static char *mid = "";
\r
650 static char *start = "|";
\r
651 static char *end = "\033[0m|";
\r
652 static char *label = "\t a b c d e f g h i j k l\n";
\r
653 static char *blabel = "\t l k j i h g f e d c b a\n";
\r
655 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
658 /* Style suggested by ajpierce@med.unc.edu */
\r
659 static int style5(struct game_state_t *b, struct move_t *ml)
\r
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="};
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="};
669 static char *wsqr = "";
\r
670 static char *bsqr = "";
\r
671 static char *top = " . . . . . . . . .\n";
\r
672 static char *mid = " . . . . . . . . .\n";
\r
673 static char *start = "";
\r
674 static char *end = "";
\r
675 static char *label = "\t a b c d e f g h i j k l\n";
\r
676 static char *blabel = "\t l k j i h g f e d c b a\n";
\r
678 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
681 /* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */
\r
682 static int style6(struct game_state_t *b, struct move_t *ml)
\r
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 |"};
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 |"};
692 static char *wsqr = "";
\r
693 static char *bsqr = "";
\r
694 static char *top = "\t-----------------------------------------\n";
\r
695 static char *mid = "\t-----------------------------------------\n";
\r
696 static char *start = "|";
\r
697 static char *end = "";
\r
698 static char *label = "\t A B C D E F G H I J K L\n";
\r
699 static char *blabel = "\t L K J I H G F E D C B A\n";
\r
701 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
704 /* Miniature board */
\r
705 static int style7(struct game_state_t *b, struct move_t *ml)
\r
707 static const char *wp[] = {" ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " D", " H", " L",
708 " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", " K"};
709 static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " d", " h", " l",
710 " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k"};
711 static char *wsqr = "";
\r
712 static char *bsqr = "";
\r
713 static char *top = "\t:::::::::::::::::::::\n";
\r
714 static char *mid = "";
\r
715 static char *start = "..";
\r
716 static char *end = " ..";
\r
717 static char *label = "\t a b c d e f g h i j k l\n";
\r
718 static char *blabel = "\t l k j i h g f e d c b a\n";
\r
720 return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel);
\r
723 /* ICS interface maker board-- raw data dump */
\r
724 static int style8(struct game_state_t *b, struct move_t *ml)
\r
730 board_calc_strength(b, &ws, &bs);
\r
731 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1,
\r
732 game_globals.garray[b->gameNum].white_name,
\r
733 (orient == WHITE) ? "*" : ":",
\r
734 game_globals.garray[b->gameNum].black_name,
\r
735 (orient == WHITE) ? ":" : "*");
\r
736 strcat(bstring, tmp);
\r
737 for (r = 0; r < b->ranks; r++) {
\r
738 for (f = 0; f < b->files; f++) {
\r
739 if (b->board[f][r] == NOPIECE) {
\r
740 strcat(bstring, " ");
\r
742 if (colorval(b->board[f][r]) == WHITE)
\r
743 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
\r
745 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
\r
749 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
\r
750 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
\r
751 (b->onMove == WHITE) ? "W" : "B",
\r
756 game_globals.garray[b->gameNum].numHalfMoves ?
\r
757 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
\r
759 game_globals.garray[b->gameNum].numHalfMoves ?
\r
760 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
\r
762 strcat(bstring, tmp);
\r
766 /* last 2 moves only (previous non-verbose mode) */
\r
767 static int style9(struct game_state_t *b, struct move_t *ml)
\r
773 sprintf(tmp, "\nMove %-23s%s\n",
\r
774 game_globals.garray[b->gameNum].white_name,
\r
775 game_globals.garray[b->gameNum].black_name);
\r
776 strcat(bstring, tmp);
\r
777 sprintf(tmp, "---- -------------- --------------\n");
\r
778 strcat(bstring, tmp);
\r
779 startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2;
\r
782 for (i = startmove, count = 0;
\r
783 i < game_globals.garray[b->gameNum].numHalfMoves && count < 4;
\r
786 sprintf(tmp, " %2d ", i / 2 + 1);
\r
787 strcat(bstring, tmp);
\r
789 sprintf(tmp, "%-23s", move_and_time(&ml[i]));
\r
790 strcat(bstring, tmp);
\r
792 strcat(bstring, "\n");
\r
795 strcat(bstring, "\n");
\r
799 /* Sleator's 'new and improved' raw dump format... */
\r
800 static int style10(struct game_state_t *b, struct move_t *ml)
\r
806 board_calc_strength(b, &ws, &bs);
\r
807 sprintf(tmp, "<10>\n");
\r
808 strcat(bstring, tmp);
\r
809 for (r = b->ranks-1; r >= 0; r--) {
\r
810 strcat(bstring, "|");
\r
811 for (f = 0; f < b->files; f++) {
\r
812 if (b->board[f][r] == NOPIECE) {
\r
813 strcat(bstring, " ");
\r
815 if (colorval(b->board[f][r]) == WHITE)
\r
816 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
\r
818 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
\r
821 strcat(bstring, "|\n");
\r
823 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
\r
824 if (game_globals.garray[b->gameNum].numHalfMoves) {
\r
825 sprintf(tmp, "%d ",
\r
826 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn);
\r
828 sprintf(tmp, "-1 ");
\r
830 strcat(bstring, tmp);
\r
831 sprintf(tmp, "%d %d %d %d %d\n",
\r
832 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
\r
833 (b->wkmoved >= 0 && b->wqrmoved >= 0),
\r
834 (b->bkmoved >= 0 && b->bkrmoved >= 0),
\r
835 (b->bkmoved >= 0 && b->bqrmoved >= 0),
\r
836 (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 :
\r
837 b->lastIrreversable)));
\r
838 strcat(bstring, tmp);
\r
839 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n",
\r
841 game_globals.garray[b->gameNum].white_name,
\r
842 game_globals.garray[b->gameNum].black_name,
\r
844 game_globals.garray[b->gameNum].wInitTime / 600,
\r
845 game_globals.garray[b->gameNum].wIncrement / 10,
\r
850 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
\r
851 game_globals.garray[b->gameNum].numHalfMoves ?
\r
852 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
\r
854 game_globals.garray[b->gameNum].numHalfMoves ?
\r
855 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
\r
857 game_globals.garray[b->gameNum].numHalfMoves ?
\r
858 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString :
\r
860 (orient == WHITE) ? 0 : 1);
\r
861 strcat(bstring, tmp);
\r
862 sprintf(tmp, ">10<\n");
\r
863 strcat(bstring, tmp);
\r
867 /* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */
\r
868 static int style11(struct game_state_t *b, struct move_t *ml)
\r
874 board_calc_strength(b, &ws, &bs);
\r
875 sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum,
\r
876 game_globals.garray[b->gameNum].white_name,
\r
877 (orient == WHITE) ? "*" : ":",
\r
878 game_globals.garray[b->gameNum].black_name,
\r
879 (orient == WHITE) ? ":" : "*");
\r
880 strcat(bstring, tmp);
\r
881 for (r = 0; r < b->ranks; r++) {
\r
882 for (f = 0; f < b->files; f++) {
\r
883 if (b->board[f][r] == NOPIECE) {
\r
884 strcat(bstring, " ");
\r
886 if (colorval(b->board[f][r]) == WHITE)
\r
887 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
\r
889 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
\r
893 sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n",
\r
894 game_globals.garray[b->gameNum].numHalfMoves / 2 + 1,
\r
895 (b->onMove == WHITE) ? "W" : "B",
\r
900 game_globals.garray[b->gameNum].numHalfMoves ?
\r
901 ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString :
\r
903 game_globals.garray[b->gameNum].numHalfMoves ?
\r
904 tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) :
\r
906 strcat(bstring, tmp);
\r
911 int kludgeFlag = 0;
\r
912 /* Similar to style 10. See the "style12" help file for information */
\r
913 static int style12(struct game_state_t *b, struct move_t *ml)
\r
916 char tmp[160]; // [HGM] 80 caused problems with long login names
\r
918 int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves;
919 // [HGM] setup: the number of half moves appeared in this routine an enormous number of times,
920 // and had to be dug out of the game_globals, so that this routine could only be used to print
921 // a board from a game, and not just any board given by an isolated game_state_t. This was very
922 // inconvenient for printing initial boards in move lists of shuffle variants, so I added the
923 // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0.
\r
925 board_calc_strength(b, &ws, &bs);
\r
927 sprintf(bstring, "<12> ");
\r
928 for (r = b->ranks-1; r >= 0; r--) {
\r
929 for (f = 0; f < b->files; f++) {
930 if (b->board[f][r] == NOPIECE) {
\r
931 strcat(bstring, "-");
\r
933 if (colorval(b->board[f][r]) == WHITE)
\r
934 strcat(bstring, wpstring[piecetype(b->board[f][r])]);
\r
936 strcat(bstring, bpstring[piecetype(b->board[f][r])]);
\r
939 strcat(bstring, " ");
\r
942 strcat(bstring, (b->onMove == WHITE) ? "W " : "B ");
\r
944 sprintf(tmp, "%d ",
\r
945 ml[nhm - 1].doublePawn);
\r
947 sprintf(tmp, "-1 ");
\r
949 strcat(bstring, tmp);
\r
950 sprintf(tmp, "%d %d %d %d %d ",
\r
951 (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights
\r
952 (b->wkmoved >= 0 && b->wqrmoved >= 0),
\r
953 (b->bkmoved >= 0 && b->bkrmoved >= 0),
\r
954 (b->bkmoved >= 0 && b->bqrmoved >= 0),
\r
955 (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable)));
\r
956 strcat(bstring, tmp);
957 sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n",
\r
959 game_globals.garray[b->gameNum].white_name,
\r
960 game_globals.garray[b->gameNum].black_name,
\r
962 game_globals.garray[b->gameNum].wInitTime / 600,
\r
963 game_globals.garray[b->gameNum].wIncrement / 10,
\r
970 ml[nhm - 1].moveString :
\r
973 tenth_str(ml[nhm - 1].tookTime, 0) :
\r
976 ml[nhm - 1].algString :
\r
977 "none", (orient == WHITE) ? 0 : 1,
\r
978 b->moveNum > 1 ? 1 : 0); /* ticking */
\r
980 strcat(bstring, tmp);
\r
984 static int board_read_file(char *category, char *gname, struct game_state_t *gs)
994 fp = fopen_p("%s/%s/%s", "r", BOARD_DIR, category, gname);
1007 } else if (c == 'B') {
1011 } else if (c == 'S') { int f=8, r=8;
1012 // [HGM] rules: read rule modifiers
1013 fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r;
1014 while (!feof(fp) && c != '\n') {
1018 gs->royalKnight = 1;
1021 gs->capablancaPieces = 1;
1027 gs->holdings = -1; // color-flip holdings
1033 gs->promoType = 2; // only promote to captured pieces
1034 gs->holdings = 1; // use holdings to hold own captured pieces
1037 gs->promoType = 3; // Shogi-type promotions
1040 gs->promoZone = 3; // for Grand Chess
1041 gs->pawnDblStep = 2;
1044 gs->castlingStyle = 2; // FRC castling
1047 gs->castlingStyle = 1; // wild castling, from both center files
1050 gs->castlingStyle = 0; // no castling
1053 gs->castlingStyle = 3; // free castling
1056 gs->pawnDblStep = 0; // suppress pawn double step
1059 gs->bareKingLoses = 1; // apply baring rule
1062 gs->stalemate = 0; // stalemate loses
1067 } else if (c == '#') {
1068 while (!feof(fp) && c != '\n')
1069 c = fgetc(fp); /* Comment line */
1071 } else { /* Skip any line we don't understand */
1072 while (!feof(fp) && c != '\n')
1092 onPiece = CARDINAL;
\r
1095 onPiece = MARSHALL;
\r
1125 onPiece = PRIESTESS;
1134 onPiece = NIGHTRIDER;
1137 onPiece = MODERNELEPHANT;
1152 onPiece = HONORABLEHORSE;
1155 onPiece = DRAGONKING;
1158 onPiece = DRAGONHORSE;
1191 if(onFile >= gs->files) { onFile = -1; break; }
\r
1195 if (onColor >= 0 && onPiece >= 0) // allow placement in holdings
\r
1196 gs->holding[onColor == BLACK][onPiece-1]++;
1208 onRank = c - '1' + (gs->ranks > 9);
\r
1209 if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; }
\r
1210 if (onFile >= 0 && onColor >= 0 && onPiece >= 0)
\r
1211 gs->board[onFile][onRank] = onPiece | onColor;
\r
1213 while (!feof(fp) && c != '\n')
1214 c = fgetc(fp); /* Comment line */
1231 #define WHITE_SQUARE 1
1232 #define BLACK_SQUARE 0
1233 #define ANY_SQUARE -1
1234 #define SquareColor(f, r) ((f ^ r) & 1)
1236 static void place_piece(board_t b, int piece, int squareColor, int width)
1237 { //[HGM] board: make width a variable
1241 if (iscolor(piece, BLACK))
1247 if (squareColor == ANY_SQUARE) {
1248 f = random() % width;
1250 f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards
1251 if (SquareColor(f, r) != squareColor)
1254 if ((b)[f][r] == NOPIECE) {
1261 static void wild_update(board_t b, int style)
1265 for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards
1266 for (r = 0; r < 8; r++)
1268 for (f = 0; f < 8; f++) {
1274 if (random() & 0x01) {
1281 if (random() & 0x01) {
1288 b[0][0] = b[7][0] = W_ROOK;
1289 b[0][7] = b[7][7] = B_ROOK;
1290 /* Must do bishops before knights to be sure opposite colored squares are
1292 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1293 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1294 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1295 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1296 place_piece(b, B_BISHOP, WHITE_SQUARE, 8);
1297 place_piece(b, B_BISHOP, BLACK_SQUARE, 8);
1298 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1299 place_piece(b, B_KNIGHT, ANY_SQUARE, 8);
1302 place_piece(b, W_KING, ANY_SQUARE, 8);
1303 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1304 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1305 place_piece(b, W_ROOK, ANY_SQUARE, 8);
1306 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1307 place_piece(b, W_BISHOP, ANY_SQUARE, 8);
1308 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1309 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1310 /* Black mirrors White */
1311 for (i = 0; i < 8; i++) {
1312 b[i][7] = b[i][0] | BLACK;
1316 /* Generate White king on random square plus random set of pieces */
1317 place_piece(b, W_KING, ANY_SQUARE, 8);
1318 for (i = 0; i < 8; i++) {
1319 if (b[i][0] != W_KING) {
1320 b[i][0] = (random() % 4) + 2;
1323 /* Black mirrors White */
1324 for (i = 0; i < 8; i++) {
1325 b[i][7] = b[i][0] | BLACK;
1329 /* Generate White king on random square plus random set of pieces */
1330 place_piece(b, W_KING, ANY_SQUARE, 8);
1331 for (i = 0; i < 8; i++) {
1332 if (b[i][0] != W_KING) {
1333 b[i][0] = (random() % 4) + 2;
1336 /* Black has same set of pieces, but randomly permuted, except that Black
1337 must have the same number of bishops on white squares as White has on
1338 black squares, and vice versa. So we must place Black's bishops first
1339 to be sure there are enough squares left of the correct color. */
1340 for (i = 0; i < 8; i++) {
1341 if (b[i][0] == W_BISHOP) {
1342 place_piece(b, B_BISHOP, !SquareColor(i, 0), 8);
1345 for (i = 0; i < 8; i++) {
1346 if (b[i][0] != W_BISHOP) {
1347 place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8);
1352 /* Chess960 placement: King between R */
1353 place_piece(b, W_BISHOP, WHITE_SQUARE, 8);
1354 place_piece(b, W_BISHOP, BLACK_SQUARE, 8);
1355 place_piece(b, W_QUEEN, ANY_SQUARE, 8);
1356 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1357 place_piece(b, W_KNIGHT, ANY_SQUARE, 8);
1358 for (i = j = 0; i < 8; i++) {
1359 if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK);
1361 /* Black mirrors White */
1362 for (i = 0; i < 8; i++) {
1363 b[i][7] = b[i][0] | BLACK;
1367 /* Chess960 placement: King between R */
1368 place_piece(b, W_BISHOP, WHITE_SQUARE, 10);
1369 place_piece(b, W_BISHOP, BLACK_SQUARE, 10);
1370 place_piece(b, W_QUEEN, ANY_SQUARE, 10);
1371 place_piece(b, W_MARSHALL, ANY_SQUARE, 10);
1372 place_piece(b, W_CARDINAL, ANY_SQUARE, 10);
1373 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1374 place_piece(b, W_KNIGHT, ANY_SQUARE, 10);
1375 for (i = j = 0; i < 10; i++) {
1376 if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK;
1378 /* Black mirrors White */
1379 for (i = 0; i < 10; i++) {
1380 b[i][7] = b[i][0] | BLACK;
1391 fp = fopen_p("%s/wild/%d", "w", BOARD_DIR, style);
1393 d_printf( "CHESSD: Can't write wild style %d\n", style);
1398 for (r = 1; r >= 0; r--) {
1399 for (f = 0; f < 8; f++) {
1400 if (onPiece < 0 || b[f][r] != onPiece) {
1402 fprintf(fp, " %s", wpstring[piecetype(b[f][r])]);
1404 fprintf(fp, " %c%c", f + 'a', r + '1');
1407 fprintf(fp, "\nB:");
1409 for (r = 6; r < 8; 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');
1423 void wild_init(void)