From c3eee8e333866d92e5fd94ae83cef618758c11bb Mon Sep 17 00:00:00 2001 From: Markus Uhlin Date: Mon, 15 Sep 2025 18:50:32 +0200 Subject: FICS RPBLC v1.4.6 --- FICS/board.c | 1385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1385 insertions(+) create mode 100644 FICS/board.c (limited to 'FICS/board.c') diff --git a/FICS/board.c b/FICS/board.c new file mode 100644 index 0000000..2423024 --- /dev/null +++ b/FICS/board.c @@ -0,0 +1,1385 @@ +/* board.c + * + */ + +/* + fics - An internet chess server. + Copyright (C) 1993 Richard V. Nash + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* Revision history: + name email yy/mm/dd Change + Richard Nash 93/10/22 Created + Markus Uhlin 23/12/17 Fixed compiler warnings + Markus Uhlin 23/12/23 Reformatted all functions + Markus Uhlin 24/04/13 Added usage of the functions + from 'maxxes-utils.h'. + Markus Uhlin 24/06/01 Added and made use of brand(). + Markus Uhlin 25/04/06 Fixed Clang Tidy warnings. + Markus Uhlin 25/09/02 wild_update: fixed file created + without restricting permissions. +*/ + +#include "stdinclude.h" +#include "common.h" + +#include +#include + +#include "board.h" +#include "ficsmain.h" +#include "gamedb.h" +#include "maxxes-utils.h" +#include "playerdb.h" +#include "utils.h" + +#define WHITE_SQUARE 1 +#define BLACK_SQUARE 0 +#define ANY_SQUARE -1 + +#define SquareColor(f, r) ((f ^ r) & 1) + +#define IsMachineStyle(n) (((1 << (n)) & mach_type) != 0) + +PUBLIC char *wpstring[] = {" ", "P", "N", "B", "R", "Q", "K"}; +PUBLIC char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"}; + +PUBLIC int pieceValues[7] = {0, 1, 3, 3, 5, 9, 0}; + +PRIVATE int (*styleFuncs[MAX_STYLES])(game_state_t *, move_t *) = { + style1, + style2, + style3, + style4, + style5, + style6, + style7, + style8, + style9, + style10, + style11, + style12, + style13 +}; + +PRIVATE char bstring[MAX_BOARD_STRING_LEGTH]; + +PRIVATE const int mach_type = ((1 << 7) | + (1 << 8) | + (1 << 9) | + (1 << 10) | + (1 << 11)); + +/* + * Globals used for each board + */ +PRIVATE char *wName, *bName; +PRIVATE int wTime, bTime; +PRIVATE int orient; +PRIVATE int forPlayer; +PRIVATE int myTurn; + +PRIVATE int +brand(void) +{ +#if RAND_MAX < 32767 || RAND_MAX > INT_MAX +#error RAND_MAX unacceptable +#endif + return ((int) arc4random_uniform(RAND_MAX)); +} + +PUBLIC int +board_init(game_state_t *b, char *category, char *board) +{ + int retval; + int wval; + + if (category == NULL || board == NULL || + !category[0] || !board[0]) { + retval = board_read_file("standard", "standard", b); + } else { + if (!strcmp(category, "wild")) { + if (sscanf(board, "%d", &wval) == 1 && + wval >= 1 && + wval <= 4) + wild_update(wval); + } + + retval = board_read_file(category, board, b); + } + + b->gameNum = -1; + return retval; +} + +PUBLIC void +board_calc_strength(game_state_t *b, int *ws, int *bs) +{ + int *p; + int r, f; + + *ws = *bs = 0; + + for (f = 0; f < 8; f++) { + for (r = 0; r < 8; r++) { + if (colorval(b->board[r][f]) == WHITE) + p = ws; + else + p = bs; + *p += pieceValues[piecetype(b->board[r][f])]; + } + } + + for (r = PAWN; r <= QUEEN; r++) { + *ws += (b->holding[0][r - 1] * pieceValues[r]); + *bs += (b->holding[1][r - 1] * pieceValues[r]); + } +} + +PRIVATE char * +holding_str(int *holding) +{ + int p, i, j; + static char tmp[30]; + + i = 0; + + for (p = PAWN; p <= QUEEN; p++) { + for (j = 0; j < holding[p - 1]; j++) + tmp[i++] = wpstring[p][0]; + } + + tmp[i] = '\0'; + return tmp; +} + +PRIVATE char * +append_holding_machine(char *buf, const size_t bufsize, int g, int c, int p) +{ + char tmp[50]; + game_state_t *gs = &garray[g].game_state; + + msnprintf(tmp, sizeof tmp, " game %d white [%s] black [", (g + 1), + holding_str(gs->holding[0])); + mstrlcat(tmp, holding_str(gs->holding[1]), sizeof tmp); + mstrlcat(buf, tmp, bufsize); + + if (p) { + msnprintf(tmp, sizeof tmp, "] <- %c%s\n", "WB"[c], wpstring[p]); + mstrlcat(buf, tmp, bufsize); + } else + mstrlcat(buf, "]\n", bufsize); + return buf; +} + +PRIVATE char * +append_holding_display(char *buf, const size_t bufsize, game_state_t *gs, + int white) +{ + if (white) + mstrlcat(buf, "White holding: [", bufsize); + else + mstrlcat(buf, "Black holding: [", bufsize); + mstrlcat(buf, holding_str(gs->holding[white ? 0 : 1]), bufsize); + mstrlcat(buf, "]\n", bufsize); + return buf; +} + +PUBLIC void +update_holding(int g, int pieceCaptured) +{ + char tmp1[80]; + char tmp2[80]; + game_state_t *gs = &garray[g].game_state; + int c = colorval(pieceCaptured); + int p = piecetype(pieceCaptured); + int pp, pl; + + if (c == WHITE) { + c = 0; + pp = garray[g].white; + } else { + c = 1; + pp = garray[g].black; + } + + gs->holding[c][p - 1]++; + + tmp1[0] = '\0'; + append_holding_machine(tmp1, sizeof tmp1, g, c, p); + + msnprintf(tmp2, sizeof tmp2, "Game %d %s received: %s -> [%s]\n", + (g + 1), + parray[pp].name, + wpstring[p], + holding_str(gs->holding[c])); + + for (pl = 0; pl < p_num; pl++) { + if (parray[pl].status == PLAYER_EMPTY) + continue; + + if (player_is_observe(pl, g) || parray[pl].game == g) { + pprintf_prompt(pl, "%s", + (IsMachineStyle(parray[pl].style) ? &tmp1[0] : + &tmp2[0])); + } + } +} + +PUBLIC char * +board_to_string(char *wn, char *bn, int wt, int bt, game_state_t *b, move_t *ml, + int style, int orientation, int relation, int p) +{ + int bh = (b->gameNum >= 0 && garray[b->gameNum].link >= 0); + + wName = wn; + bName = bn; + wTime = wt; + bTime = bt; + orient = orientation; + myTurn = relation; + forPlayer = p; + + if (style < 0 || style >= MAX_STYLES) + return NULL; + + if (style != 11) { // game header + msnprintf(bstring, sizeof bstring, "Game %d (%s vs. %s)\n\n", + (b->gameNum + 1), + garray[b->gameNum].white_name, + garray[b->gameNum].black_name); + } else + bstring[0] = '\0'; + + if (bh && !IsMachineStyle(style)) { + append_holding_display(bstring, sizeof bstring, b, + (orientation == BLACK)); + } + if (styleFuncs[style](b, ml)) + return NULL; + if (bh) { + if (IsMachineStyle(style)) { + append_holding_machine(bstring, sizeof bstring, + b->gameNum, 0, 0); + } else { + append_holding_display(bstring, sizeof bstring, b, + (orientation == WHITE)); + } + } + + return bstring; +} + +PUBLIC char * +move_and_time(move_t *m) +{ + static char tmp[20]; + + msnprintf(tmp, sizeof tmp, "%-7s (%s)", m->algString, + tenth_str(m->tookTime, 0)); + return &tmp[0]; +} + +PRIVATE int +genstyle(game_state_t *b, move_t *ml, char *wp[], char *bp[], + char *wsqr, char *bsqr, char *top, char *mid, char *start, char *end, + char *label, char *blabel) +{ + char tmp[80]; + int f, r, count; + int first, last, inc; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + + if (orient == WHITE) { + first = 7; + last = 0; + inc = -1; + } else { + first = 0; + last = 7; + inc = 1; + } + + mstrlcat(bstring, top, sizeof bstring); + + for (f = first, count = 7; f != last + inc; f += inc, count--) { + msnprintf(tmp, sizeof tmp, " %d %s", f + 1, start); + mstrlcat(bstring, tmp, sizeof bstring); + + for (r = last; r != first - inc; r = r - inc) { + if (square_color(r, f) == WHITE) + mstrlcat(bstring, wsqr, sizeof bstring); + else + mstrlcat(bstring, bsqr, sizeof bstring); + + if (piecetype(b->board[r][f]) == NOPIECE) { + if (square_color(r, f) == WHITE) { + mstrlcat(bstring, bp[0], + sizeof bstring); + } else { + mstrlcat(bstring, wp[0], + sizeof bstring); + } + } else { + if (colorval(b->board[r][f]) == WHITE) { + mstrlcat(bstring, + wp[piecetype(b->board[r][f])], + sizeof bstring); + } else { + mstrlcat(bstring, + bp[piecetype(b->board[r][f])], + sizeof bstring); + } + } + } + + msnprintf(tmp, sizeof tmp, "%s", end); + mstrlcat(bstring, tmp, sizeof bstring); + + switch (count) { + case 7: + msnprintf(tmp, sizeof tmp, " Move # : %d (%s)", + b->moveNum, + CString(b->onMove)); + mstrlcat(bstring, tmp, sizeof bstring); + break; + case 6: + if (garray[b->gameNum].numHalfMoves > 0) { + // loon: think this fixes the crashing ascii + // board on takeback bug + msnprintf(tmp, sizeof tmp, " %s Moves : " + "'%s'", + CString(CToggle(b->onMove)), move_and_time + (&ml[garray[b->gameNum].numHalfMoves - 1])); + mstrlcat(bstring, tmp, sizeof bstring); + } + break; + case 5: + break; + case 4: + msnprintf(tmp, sizeof tmp, " Black Clock : %s", + tenth_str((bTime > 0 ? bTime : 0), 1)); + mstrlcat(bstring, tmp, sizeof bstring); + break; + case 3: + msnprintf(tmp, sizeof tmp, " White Clock : %s", + tenth_str((wTime > 0 ? wTime : 0), 1)); + mstrlcat(bstring, tmp, sizeof bstring); + break; + case 2: + msnprintf(tmp, sizeof tmp, " Black Strength : %d", + bs); + mstrlcat(bstring, tmp, sizeof bstring); + break; + case 1: + msnprintf(tmp, sizeof tmp, " White Strength : %d", + ws); + mstrlcat(bstring, tmp, sizeof bstring); + break; + case 0: + break; + } // switch + + mstrlcat(bstring, "\n", sizeof bstring); + + if (count != 0) + mstrlcat(bstring, mid, sizeof bstring); + else + mstrlcat(bstring, top, sizeof bstring); + } // for + + if (orient == WHITE) + mstrlcat(bstring, label, sizeof bstring); + else + mstrlcat(bstring, blabel, sizeof bstring); + return 0; +} + +/* + * Experimental ANSI board for colour representation + */ +PUBLIC int +style13(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " ", + "\033[37m\033[1m P ", + "\033[37m\033[1m N ", + "\033[37m\033[1m B ", + "\033[37m\033[1m R ", + "\033[37m\033[1m Q ", + "\033[37m\033[1m K " + }; + static char *bp[] = { + " ", + "\033[21m\033[37m P ", + "\033[21m\033[37m N ", + "\033[21m\033[37m B ", + "\033[21m\033[37m R ", + "\033[21m\033[37m Q ", + "\033[21m\033[37m K " + }; + static char *wsqr = "\033[40m"; + static char *bsqr = "\033[45m"; + static char *top = "\t+------------------------+\n"; + static char *mid = ""; + static char *start = "|"; + static char *end = "\033[0m|"; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Standard ICS + */ +PUBLIC int +style1(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " |", + " P |", + " N |", + " B |", + " R |", + " Q |", + " K |" + }; + static char *bp[] = { + " |", + " *P|", + " *N|", + " *B|", + " *R|", + " *Q|", + " *K|" + }; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t---------------------------------\n"; + static char *mid = "\t|---+---+---+---+---+---+---+---|\n"; + static char *start = "|"; + static char *end = ""; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * USA-Today Sports Center-style board + */ +PUBLIC int +style2(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + "+ ", + "P ", + "N ", + "B ", + "R ", + "Q ", + "K " + }; + static char *bp[] = { + "- ", + "p' ", + "n' ", + "b' ", + "r' ", + "q' ", + "k' " + }; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = ""; + static char *mid = ""; + static char *start = ""; + static char *end = ""; + static char *label = "\ta b c d e f g h\n"; + static char *blabel = "\th g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Experimental vt-100 ANSI board for dark backgrounds + */ +PUBLIC int +style3(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " ", + " P ", + " N ", + " B ", + " R ", + " Q ", + " K " + }; + static char *bp[] = { + " ", + " *P", + " *N", + " *B", + " *R", + " *Q", + " *K" + }; + static char *wsqr = "\033[0m"; + static char *bsqr = "\033[7m"; + static char *top = "\t+------------------------+\n"; + static char *mid = ""; + static char *start = "|"; + static char *end = "\033[0m|"; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Experimental vt-100 ANSI board for light backgrounds + */ +PUBLIC int +style4(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " ", + " P ", + " N ", + " B ", + " R ", + " Q ", + " K " + }; + static char *bp[] = { + " ", + " *P", + " *N", + " *B", + " *R", + " *Q", + " *K" + }; + static char *wsqr = "\033[7m"; + static char *bsqr = "\033[0m"; + static char *top = "\t+------------------------+\n"; + static char *mid = ""; + static char *start = "|"; + static char *end = "\033[0m|"; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Style suggested by ajpierce@med.unc.edu + */ +PUBLIC int style5(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " ", + " o ", + " :N:", + " ", + " |R|", + " {Q}", + " =K=" + }; + static char *bp[] = { + " ", + " p ", + " :n:", + " ", + " |r|", + " {q}", + " =k=" + }; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = " . . . . . . . . .\n"; + static char *mid = " . . . . . . . . .\n"; + static char *start = ""; + static char *end = ""; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) + */ +PUBLIC int +style6(game_state_t *b, move_t *ml) +{ + static char *wp[] = { + " |", + " wp |", + " WN |", + " WB |", + " WR |", + " WQ |", + " WK |" + }; + static char *bp[] = { + " |", + " bp |", + " BN |", + " BB |", + " BR |", + " BQ |", + " BK |"}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t-----------------------------------------\n"; + static char *mid = "\t-----------------------------------------\n"; + static char *start = "|"; + static char *end = ""; + static char *label = "\t A B C D E F G H\n"; + static char *blabel = "\t H G F E D C B A\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * Miniature board + */ +PUBLIC int +style7(game_state_t *b, move_t *ml) +{ + static char *wp[] = {" ", " P", " N", " B", " R", " Q", " K"}; + static char *bp[] = {" -", " p", " n", " b", " r", " q", " k"}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t:::::::::::::::::::::\n"; + static char *mid = ""; + static char *start = ".."; + static char *end = " .."; + static char *label = "\t a b c d e f g h\n"; + static char *blabel = "\t h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, + blabel); +} + +/* + * ICS interface maker board -- raw data dump. + */ +PUBLIC int +style8(game_state_t *b, move_t *ml) +{ + char tmp[80]; + int f, r; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + + msnprintf(tmp, sizeof tmp, "#@#%03d%-16s%s%-16s%s", + (b->gameNum + 1), + + garray[b->gameNum].white_name, + (orient == WHITE ? "*" : ":"), + + garray[b->gameNum].black_name, + (orient == WHITE ? ":" : "*")); + + mstrlcat(bstring, tmp, sizeof bstring); + + for (r = 0; r < 8; r++) { + for (f = 0; f < 8; f++) { + if (b->board[f][r] == NOPIECE) { + mstrlcat(bstring, " ", sizeof bstring); + } else { + if (colorval(b->board[f][r]) == WHITE) { + mstrlcat(bstring, wpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } else { + mstrlcat(bstring, bpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } + } + } + } + + msnprintf(tmp, sizeof tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", + (garray[b->gameNum].numHalfMoves / 2 + 1), + (b->onMove == WHITE ? "W" : "B"), + ws, + bs, + ((wTime + 5) / 10), + ((bTime + 5) / 10), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].algString + : "none"), + + (garray[b->gameNum].numHalfMoves + ? tenth_str(ml[garray[b->gameNum].numHalfMoves - 1].tookTime, 0) + : "0:00")); + + mstrlcat(bstring, tmp, sizeof bstring); + return 0; +} + +/* + * Last 2 moves only (previous non-verbose mode). + */ +PUBLIC int +style9(game_state_t *b, move_t *ml) +{ + char tmp[80]; + int i, count; + int startmove; + + msnprintf(tmp, sizeof tmp, "\nMove %-23s%s\n", + garray[b->gameNum].white_name, + garray[b->gameNum].black_name); + mstrlcat(bstring, tmp, sizeof bstring); + + msnprintf(tmp, sizeof tmp, "---- -------------- " + "--------------\n"); + mstrlcat(bstring, tmp, sizeof bstring); + + startmove = ((garray[b->gameNum].numHalfMoves - 3) / 2) * 2; + + if (startmove < 0) + startmove = 0; + + i = startmove; + count = 0; + + while (i < garray[b->gameNum].numHalfMoves && count < 4) { + if (!(i & 0x01)) { + msnprintf(tmp, sizeof tmp, " %2d ", (i / 2 + 1)); + mstrlcat(bstring, tmp, sizeof bstring); + } + + msnprintf(tmp, sizeof tmp, "%-23s", move_and_time(&ml[i])); + mstrlcat(bstring, tmp, sizeof bstring); + + if (i & 0x01) + mstrlcat(bstring, "\n", sizeof bstring); + i++; + count++; + } + + if (i & 0x01) + mstrlcat(bstring, "\n", sizeof bstring); + return 0; +} + +/* + * Sleator's 'new and improved' raw dump format... + */ +PUBLIC int +style10(game_state_t *b, move_t *ml) +{ + char tmp[80]; + int f, r; + int ret, too_long; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + msnprintf(tmp, sizeof tmp, "<10>\n"); + mstrlcat(bstring, tmp, sizeof bstring); + + for (r = 7; r >= 0; r--) { + mstrlcat(bstring, "|", sizeof bstring); + + for (f = 0; f < 8; f++) { + if (b->board[f][r] == NOPIECE) { + mstrlcat(bstring, " ", sizeof bstring); + } else { + if (colorval(b->board[f][r]) == WHITE) { + mstrlcat(bstring, wpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } else { + mstrlcat(bstring, bpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } + } + } + + mstrlcat(bstring, "|\n", sizeof bstring); + } + + mstrlcat(bstring, (b->onMove == WHITE ? "W " : "B "), sizeof bstring); + + if (garray[b->gameNum].numHalfMoves) { + msnprintf(tmp, sizeof tmp, "%d ", + ml[garray[b->gameNum].numHalfMoves - 1].doublePawn); + } else { + msnprintf(tmp, sizeof tmp, "-1 "); + } + + mstrlcat(bstring, tmp, sizeof bstring); + + msnprintf(tmp, sizeof tmp, "%d %d %d %d %d\n", + !(b->wkmoved || b->wkrmoved), + !(b->wkmoved || b->wqrmoved), + !(b->bkmoved || b->bkrmoved), + !(b->bkmoved || b->bqrmoved), + + (garray[b->gameNum].numHalfMoves - + (b->lastIrreversable == -1 ? 0 : b->lastIrreversable))); + + mstrlcat(bstring, tmp, sizeof bstring); + + ret = snprintf(tmp, sizeof tmp, "%d %s %s %d %d %d %d %d %d %d %d %s " + "(%s) %s %d\n", + b->gameNum, + garray[b->gameNum].white_name, + garray[b->gameNum].black_name, + myTurn, + (garray[b->gameNum].wInitTime / 600), + (garray[b->gameNum].wIncrement / 10), + ws, + bs, + ((wTime + 5) / 10), + ((bTime + 5) / 10), + (garray[b->gameNum].numHalfMoves / 2 + 1), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].moveString + : "none"), + + (garray[b->gameNum].numHalfMoves + ? tenth_str(ml[garray[b->gameNum].numHalfMoves - 1].tookTime, 0) + : "0:00"), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].algString + : "none"), + + (orient == WHITE ? 0 : 1)); + + too_long = (ret < 0 || (size_t)ret >= sizeof tmp); + + if (too_long) { + fprintf(stderr, "FICS: %s: warning: snprintf truncated\n", + __func__); + } + + mstrlcat(bstring, tmp, sizeof bstring); + + msnprintf(tmp, sizeof tmp, ">10<\n"); + mstrlcat(bstring, tmp, sizeof bstring); + + return 0; +} + +/* + * Same as 8, but with verbose moves ("P/e3-e4", instead of "e4"). + */ +PUBLIC int +style11(game_state_t *b, move_t *ml) +{ + char tmp[80]; + int f, r; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + + msnprintf(tmp, sizeof tmp, "#@#%03d%-16s%s%-16s%s", + b->gameNum, + + garray[b->gameNum].white_name, + (orient == WHITE ? "*" : ":"), + + garray[b->gameNum].black_name, + (orient == WHITE ? ":" : "*")); + + mstrlcat(bstring, tmp, sizeof bstring); + + for (r = 0; r < 8; r++) { + for (f = 0; f < 8; f++) { + if (b->board[f][r] == NOPIECE) { + mstrlcat(bstring, " ", sizeof bstring); + } else { + if (colorval(b->board[f][r]) == WHITE) { + mstrlcat(bstring, wpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } else { + mstrlcat(bstring, bpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } + } + } + } + + msnprintf(tmp, sizeof tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", + (garray[b->gameNum].numHalfMoves / 2 + 1), + (b->onMove == WHITE ? "W" : "B"), + ws, + bs, + ((wTime + 5) / 10), + ((bTime + 5) / 10), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].moveString + : "none"), + + (garray[b->gameNum].numHalfMoves + ? tenth_str(ml[garray[b->gameNum].numHalfMoves - 1].tookTime, 0) + : "0:00")); + + mstrlcat(bstring, tmp, sizeof bstring); + return 0; +} + +/* + * Similar to style 10. See the "style12" help file for information. + */ +PUBLIC int +style12(game_state_t *b, move_t *ml) +{ + char tmp[80]; + int f, r; + int ret, too_long; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + msnprintf(bstring, sizeof bstring, "<12> "); + + for (r = 7; r >= 0; r--) { + for (f = 0; f < 8; f++) { + if (b->board[f][r] == NOPIECE) { + mstrlcat(bstring, "-", sizeof bstring); + } else { + if (colorval(b->board[f][r]) == WHITE) { + mstrlcat(bstring, wpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } else { + mstrlcat(bstring, bpstring + [piecetype(b->board[f][r])], + sizeof bstring); + } + } + } + + mstrlcat(bstring, " ", sizeof bstring); + } + + mstrlcat(bstring, (b->onMove == WHITE ? "W " : "B "), sizeof bstring); + + if (garray[b->gameNum].numHalfMoves) { + msnprintf(tmp, sizeof tmp, "%d ", + ml[garray[b->gameNum].numHalfMoves - 1].doublePawn); + } else { + msnprintf(tmp, sizeof tmp, "-1 "); + } + + mstrlcat(bstring, tmp, sizeof bstring); + + msnprintf(tmp, sizeof tmp, "%d %d %d %d %d ", + !(b->wkmoved || b->wkrmoved), + !(b->wkmoved || b->wqrmoved), + !(b->bkmoved || b->bkrmoved), + !(b->bkmoved || b->bqrmoved), + + (garray[b->gameNum].numHalfMoves - + (b->lastIrreversable == -1 ? 0 : b->lastIrreversable))); + mstrlcat(bstring, tmp, sizeof bstring); + + ret = snprintf(tmp, sizeof tmp, "%d %s %s %d %d %d %d %d %d %d %d %s " + "(%s) %s %d\n", + (b->gameNum + 1), + garray[b->gameNum].white_name, + garray[b->gameNum].black_name, + myTurn, + (garray[b->gameNum].wInitTime / 600), + (garray[b->gameNum].wIncrement / 10), + ws, + bs, + ((wTime + 5) / 10), + ((bTime + 5) / 10), + (garray[b->gameNum].numHalfMoves / 2 + 1), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].moveString + : "none"), + + (garray[b->gameNum].numHalfMoves + ? tenth_str(ml[garray[b->gameNum].numHalfMoves - 1].tookTime, 0) + : "0:00"), + + (garray[b->gameNum].numHalfMoves + ? ml[garray[b->gameNum].numHalfMoves - 1].algString + : "none"), + + (orient == WHITE ? 0 : 1)); + + too_long = (ret < 0 || (size_t)ret >= sizeof tmp); + + if (too_long) { + fprintf(stderr, "FICS: %s: warning: snprintf truncated\n", + __func__); + } + + mstrlcat(bstring, tmp, sizeof bstring); + + return 0; +} + +PUBLIC int +board_read_file(char *category, char *gname, game_state_t *gs) +{ + FILE *fp; + char fname[MAX_FILENAME_SIZE + 1]; + int c; + int f, r; + int onColor = -1; + int onFile = -1; + int onNewLine = 1; + int onPiece = -1; + int onRank = -1; + + msnprintf(fname, sizeof fname, "%s/%s/%s", board_dir, category, gname); + + if ((fp = fopen(fname, "r")) == NULL) + return 1; + for (f = 0; f < 8; f++) + for (r = 0; r < 8; r++) + gs->board[f][r] = NOPIECE; + for (f = 0; f < 2; f++) { + for (r = 0; r < 8; r++) + gs->ep_possible[f][r] = 0; + for (r = PAWN; r <= QUEEN; r++) + gs->holding[f][r - 1] = 0; + } + + gs->wkmoved = gs->wqrmoved = gs->wkrmoved = 0; + gs->bkmoved = gs->bqrmoved = gs->bkrmoved = 0; + + gs->onMove = -1; + gs->moveNum = 1; + gs->lastIrreversable = -1; + + while (!feof(fp)) { + c = fgetc(fp); + + if (onNewLine) { + if (c == 'W') { + onColor = WHITE; + if (gs->onMove < 0) + gs->onMove = WHITE; + } else if (c == 'B') { + onColor = BLACK; + if (gs->onMove < 0) + gs->onMove = BLACK; + } else if (c == '#') { + while (!feof(fp) && c != '\n') + c = fgetc(fp); // Comment line + continue; + } else { // Skip any line we don't understand + while (!feof(fp) && c != '\n') + c = fgetc(fp); + continue; + } + + onNewLine = 0; + } else { + switch (c) { + case 'P': + onPiece = PAWN; + break; + case 'R': + onPiece = ROOK; + break; + case 'N': + onPiece = KNIGHT; + break; + case 'B': + onPiece = BISHOP; + break; + case 'Q': + onPiece = QUEEN; + break; + case 'K': + onPiece = KING; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + onFile = (c - 'a'); + onRank = -1; // NOLINT: dead store + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + onRank = (c - '1'); + + if (onFile >= 0 && + onColor >= 0 && + onPiece >= 0) { + gs->board[onFile][onRank] = + (onPiece | onColor); + } + + break; + case '#': + while (!feof(fp) && c != '\n') + c = fgetc(fp); // Comment line + case '\n': + onNewLine = 1; + onColor = -1; + onPiece = -1; + onFile = -1; + onRank = -1; // NOLINT: dead store + break; + default: + break; + } // switch + } + } // while + + fclose(fp); + return 0; +} + +PRIVATE void +place_piece(board_t b, int piece, int squareColor) +{ + int placed = 0; + int r, f; + + if (iscolor(piece, BLACK)) + r = 7; + else + r = 0; + + while (!placed) { + if (squareColor == ANY_SQUARE) { + f = (brand() % 8); + } else { + f = (brand() % 4) * 2; + + if (SquareColor(f, r) != squareColor) + f++; + } + + if ((b)[f][r] == NOPIECE) { + (b)[f][r] = piece; + placed = 1; + } + } +} + +PUBLIC void +wild_update(int style) +{ + board_t b; + int f, r, i; + + for (f = 0; f < 8; f++) { + for (r = 0; r < 8; r++) + b[f][r] = NOPIECE; + } + + for (f = 0; f < 8; f++) { + b[f][1] = W_PAWN; + b[f][6] = B_PAWN; + } + + switch (style) { + case 1: + if (brand() & 0x01) { + b[4][0] = W_KING; + b[3][0] = W_QUEEN; + } else { + b[3][0] = W_KING; + b[4][0] = W_QUEEN; + } + if (brand() & 0x01) { + b[4][7] = B_KING; + b[3][7] = B_QUEEN; + } else { + b[3][7] = B_KING; + b[4][7] = B_QUEEN; + } + + b[0][0] = b[7][0] = W_ROOK; + b[0][7] = b[7][7] = B_ROOK; + + /* + * Must do bishops before knights to be sure opposite + * colored squares are available. + */ + place_piece(b, W_BISHOP, WHITE_SQUARE); + place_piece(b, W_BISHOP, BLACK_SQUARE); + place_piece(b, W_KNIGHT, ANY_SQUARE); + place_piece(b, W_KNIGHT, ANY_SQUARE); + place_piece(b, B_BISHOP, WHITE_SQUARE); + place_piece(b, B_BISHOP, BLACK_SQUARE); + place_piece(b, B_KNIGHT, ANY_SQUARE); + place_piece(b, B_KNIGHT, ANY_SQUARE); + break; + case 2: + place_piece(b, W_KING, ANY_SQUARE); + place_piece(b, W_QUEEN, ANY_SQUARE); + place_piece(b, W_ROOK, ANY_SQUARE); + place_piece(b, W_ROOK, ANY_SQUARE); + place_piece(b, W_BISHOP, ANY_SQUARE); + place_piece(b, W_BISHOP, ANY_SQUARE); + place_piece(b, W_KNIGHT, ANY_SQUARE); + place_piece(b, W_KNIGHT, ANY_SQUARE); + + /* Black mirrors White */ + for (i = 0; i < 8; i++) + b[i][7] = (b[i][0] | BLACK); + break; + case 3: + /* + * Generate White king on random square plus random + * set of pieces. + */ + place_piece(b, W_KING, ANY_SQUARE); + + for (i = 0; i < 8; i++) { + if (b[i][0] != W_KING) { + b[i][0] = (brand() % 4) + 2; + } + } + + /* Black mirrors White */ + for (i = 0; i < 8; i++) + b[i][7] = (b[i][0] | BLACK); + break; + case 4: + /* + * Generate White king on random square plus random + * set of pieces. + */ + place_piece(b, W_KING, ANY_SQUARE); + + for (i = 0; i < 8; i++) { + if (b[i][0] != W_KING) + b[i][0] = (brand() % 4) + 2; + } + + /* + * Black has the same set of pieces, but randomly + * permuted, except that Black must have the same + * number of bishops on white squares as White has on + * black squares, and vice versa. So we must place + * Black's bishops first to be sure there are enough + * squares left of the correct color. + */ + + for (i = 0; i < 8; i++) { + if (b[i][0] == W_BISHOP) + place_piece(b, B_BISHOP, !SquareColor(i, 0)); + } + + for (i = 0; i < 8; i++) { + if (b[i][0] != W_BISHOP) + place_piece(b, (b[i][0] | BLACK), ANY_SQUARE); + } + break; + default: + return; + break; + } + + { + FILE *fp; + char fname[MAX_FILENAME_SIZE + 1]; + int fd; + int onPiece; + + msnprintf(fname, sizeof fname, "%s/wild/%d", board_dir, style); + + if ((fd = open(fname, g_open_flags[1], g_open_modes)) < 0) { + warn("%s: can't write file name: %s", __func__, fname); + return; + } else if ((fp = fdopen(fd, "w")) == NULL) { + warn("%s: can't write file name: %s", __func__, fname); + close(fd); + return; + } + + fprintf(fp, "W:"); + onPiece = -1; + + for (r = 1; r >= 0; r--) { + for (f = 0; f < 8; f++) { + if (onPiece < 0 || b[f][r] != onPiece) { + onPiece = b[f][r]; + + fprintf(fp, " %s", wpstring + [piecetype(b[f][r])]); + } + + fprintf(fp, " %c%c", (f + 'a'), (r + '1')); + } + } + + fprintf(fp, "\nB:"); + onPiece = -1; + + for (r = 6; r < 8; r++) { + for (f = 0; f < 8; f++) { + if (onPiece < 0 || b[f][r] != onPiece) { + onPiece = b[f][r]; + + fprintf(fp, " %s", wpstring + [piecetype(b[f][r])]); + } + + fprintf(fp, " %c%c", (f + 'a'), (r + '1')); + } + } + + fprintf(fp, "\n"); + fclose(fp); + } +} + +PUBLIC void +wild_init(void) +{ + wild_update(1); + wild_update(2); + wild_update(3); + wild_update(4); +} -- cgit v1.2.3