/* board.c * */ /* icds - Internet Checkers and Draughts Server Copyright (c) 1997 by Michael Rohrer 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 Michael Rohrer 97/05/01 Modified */ #include "stdinclude.h" #include "common.h" #include "board.h" #include "playerdb.h" #include "gamedb.h" #include "utils.h" extern int style1(); extern int style2(); extern int style3(); extern int style4(); extern int style5(); PUBLIC char *wpstring[] = {" ", "w", "W", "w", "W"}; /*for now, just w and b to represent pieces. */ PUBLIC char *bpstring[] = {" ", "b", "B", "b", "B"}; PUBLIC int pieceValues[5] = {0, 1, 2, 1, 6}; PUBLIC int (*styleFuncs[MAX_STYLES]) () = { style1, style2, style3, style4, style5 }; PRIVATE const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11); #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0) PRIVATE char bstring[MAX_BOARD_STRING_LEGTH]; /* lets change char *board to int value for board... easier for * comparisons */ PUBLIC int board_init(game_state_t *b, int boardtype) { int retval; switch (boardtype) { case TYPE_POOL: { retval = board_load_pool(b); break; } case TYPE_SPANISH: { retval = board_load_spanish(b); break; } case TYPE_POLISH: { retval = board_load_polish(b); break; } case TYPE_BRITISH: { retval = board_load_british(b); break; } default: { retval = board_load_british(b); break; } } b->gameNum = -1; return retval; } PUBLIC void board_calc_strength(game_state_t *b, int *ws, int *bs) { int r, f; int *p; int boardsize = (garray[b->gameNum].type == TYPE_POLISH ? 10 : 8); *ws = *bs = 0; for (f = 0; f < boardsize; f++) { for (r = 0; r < boardsize; r++) { if (colorval(b->board[r][f]) == WHITE) p = ws; else p = bs; *p += pieceValues[piecetype(b->board[r][f])]; } } } /* Globals used for each board */ /* PRIVATE char *wName, *bName; */ PRIVATE int wTime, bTime; PRIVATE int orient; PRIVATE int forPlayer; PRIVATE int myTurn; /* 1 = my turn, 0 = observe, -1 = other turn */ /* 2 = examiner, -2 = observing examiner */ /* -3 = just send position (spos/refresh) */ 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) { wTime = wt; bTime = bt; orient = orientation; myTurn = relation; forPlayer = p; if ((style < 0) || (style >= MAX_STYLES)) { return NULL; } /* game header */ sprintf(bstring, "Game %d (%s vs. %s)\n\n", b->gameNum + 1, wn, bn); if (styleFuncs[style] (b, ml)) { return NULL; } return bstring; } PUBLIC char *move_and_time(move_t *m) { static char tmp[20]; sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0)); return tmp; } /* The following take the game state and whole move list */ 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) { int f, r, count; char tmp[80]; int first, last, inc; int ws, bs; int boardsize = (garray[b->gameNum].type == TYPE_POLISH ? 10 : 8); board_calc_strength(b, &ws, &bs); if (orient == WHITE) { first = (boardsize - 1); last = 0; inc = -1; } else { first = 0; last = (boardsize - 1); inc = 1; } strcat(bstring, top); for (f = first, count = (boardsize - 1); f != last + inc; f += inc, count--) { sprintf(tmp, " %d %s", f + 1, start); strcat(bstring, tmp); for (r = last; r != first - inc; r = r - inc) { if (square_color(r, f) == WHITE) strcat(bstring, wsqr); else strcat(bstring, bsqr); if (piecetype(b->board[r][f]) == NOPIECE) { if (square_color(r, f) == WHITE) strcat(bstring, bp[0]); else strcat(bstring, wp[0]); } else { if (colorval(b->board[r][f]) == WHITE) strcat(bstring, wp[piecetype(b->board[r][f])]); else strcat(bstring, bp[piecetype(b->board[r][f])]); } } sprintf(tmp, "%s", end); strcat(bstring, tmp); switch (count) { case 7: sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove)); strcat(bstring, tmp); break; case 6: /* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */ /* The change from the above line to the one below is a kludge by hersco. */ if (garray[b->gameNum].numHalfMoves > 0) { /* loon: think this fixes the crashing ascii board on takeback bug */ sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)), move_and_time(&ml[garray[b->gameNum].numHalfMoves - 1])); strcat(bstring, tmp); } break; case 5: break; case 4: sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1)); strcat(bstring, tmp); break; case 3: sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1)); strcat(bstring, tmp); break; case 2: sprintf(tmp, " Black Strength : %d", bs); strcat(bstring, tmp); break; case 1: sprintf(tmp, " White Strength : %d", ws); strcat(bstring, tmp); break; case 0: break; } strcat(bstring, "\n"); if (count != 0) strcat(bstring, mid); else strcat(bstring, top); } if (orient == WHITE) strcat(bstring, label); else strcat(bstring, blabel); return 0; } /* Standard ICS */ /* fixed a little bit for 10 x 10 board */ PUBLIC int style1(game_state_t *b, move_t *ml) { static char *wp[] = {" |", " w |", " W |", " w |", " W |"}; static char *bp[] = {" |", " b |", " B |", " b |", " B |"}; 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"; /* for 10 x 10 board */ static char *poltop = "\t-----------------------------------------\n"; static char *polmid = "\t|---+---+---+---+---+---+---+---+---+---|\n"; static char *pollabel = "\t a b c d e f g h i j\n"; static char *polblabel = "\t j i h g f e d c b a\n"; if (garray[b->gameNum].type == TYPE_POLISH) { return genstyle(b, ml, wp, bp, wsqr, bsqr, poltop, polmid, start, end, pollabel, polblabel); } return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); } /* last 2 moves only (previous non-verbose mode) */ PUBLIC int style2(game_state_t *b, move_t *ml) { int i, count; char tmp[80]; int startmove; sprintf(tmp, "\nMove %-23s%s\n", garray[b->gameNum].white_name, garray[b->gameNum].black_name); strcat(bstring, tmp); sprintf(tmp, "---- -------------- --------------\n"); strcat(bstring, tmp); startmove = ((garray[b->gameNum].numHalfMoves - 3) / 2) * 2; if (startmove < 0) startmove = 0; for (i = startmove, count = 0; i < garray[b->gameNum].numHalfMoves && count < 4; i++, count++) { if (!(i & 0x01)) { sprintf(tmp, " %2d ", i / 2 + 1); strcat(bstring, tmp); } sprintf(tmp, "%-23s", move_and_time(&ml[i])); strcat(bstring, tmp); if (i & 0x01) strcat(bstring, "\n"); } if (i & 0x01) strcat(bstring, "\n"); return 0; } /* Similar to style 10. See the "style12" help file for information */ PUBLIC int style3(game_state_t *b, move_t *ml) { int f, r; char tmp[80]; int ws, bs; int boardsize = (garray[b->gameNum].type == TYPE_POLISH ? 10 : 8); board_calc_strength(b, &ws, &bs); sprintf(bstring, "<3> "); switch (garray[b->gameNum].type) { case TYPE_POLISH: { strcat(bstring, "20 "); break; } case TYPE_BRITISH: { strcat(bstring, "21 "); break; } case TYPE_SPANISH: { strcat(bstring, "24 "); break; } case TYPE_POOL: { strcat(bstring, "23 "); break; } default: strcat(bstring, "99 "); /* error */ } if (orient == BLACK) { strcat(bstring, "B "); } else { strcat(bstring, "W "); } if (orient == BLACK) { /* black moving */ for (r = (boardsize - 1); r >= 0; r--) { for (f = 0; f <= (boardsize - 1); f++) { if (b->board[f][r] == NOPIECE) { strcat(bstring, "-"); } else { if (colorval(b->board[f][r]) == WHITE) strcat(bstring, wpstring[piecetype(b->board[f][r])]); else strcat(bstring, bpstring[piecetype(b->board[f][r])]); } } strcat(bstring, " "); } } else { /* white moving */ for (r = 0; r <= (boardsize - 1); r++) { for (f = (boardsize - 1); f >= 0; f--) { if (b->board[f][r] == NOPIECE) { strcat(bstring, "-"); } else { if (colorval(b->board[f][r]) == WHITE) strcat(bstring, wpstring[piecetype(b->board[f][r])]); else strcat(bstring, bpstring[piecetype(b->board[f][r])]); } } strcat(bstring, " "); } } strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); if (garray[b->gameNum].numHalfMoves) { sprintf(tmp, "1 "); } else { sprintf(tmp, "-1 "); } strcat(bstring, tmp); sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d (%s) %s\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, bTime, garray[b->gameNum].numHalfMoves / 2 + 1, 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"); strcat(bstring, tmp); return 0; } PUBLIC int style4(game_state_t *b, move_t *ml) { int f, r; char tmp[80]; int ws, bs; int boardsize = (garray[b->gameNum].type == TYPE_POLISH ? 10 : 8); board_calc_strength(b, &ws, &bs); sprintf(bstring, "<4> "); switch (garray[b->gameNum].type) { case TYPE_POLISH: { strcat(bstring, "20 "); break; } case TYPE_BRITISH: { strcat(bstring, "21 "); break; } case TYPE_SPANISH: { strcat(bstring, "24 "); break; } case TYPE_POOL: { strcat(bstring, "23 "); break; } default: strcat(bstring, "99 "); /* error */ } if (orient == BLACK) { strcat(bstring, "B "); } else { strcat(bstring, "W "); } if (orient == BLACK) { /* black moving */ for (r = (boardsize - 1); r >= 0; r--) { for (f = 0; f <= (boardsize - 1); f++) { if (b->board[f][r] == NOPIECE) { /* a modified version of a patch written by girbal * to only show relevant squares */ if ((f + r) % 2 == 1) { if (garray[b->gameNum].type == TYPE_SPANISH) { strcat(bstring, "-"); } } else { if (garray[b->gameNum].type != TYPE_SPANISH) { strcat(bstring, "-"); } } } else { if (colorval(b->board[f][r]) == WHITE) strcat(bstring, wpstring[piecetype(b->board[f][r])]); else strcat(bstring, bpstring[piecetype(b->board[f][r])]); } } strcat(bstring, " "); } } else { /* white moving */ for (r = 0; r <= (boardsize - 1); r++) { for (f = (boardsize - 1); f >= 0; f--) { if (b->board[f][r] == NOPIECE) { /* a modified version of a patch written by girbal * to only show relevant squares */ if ((f + r) % 2 == 1) { if (garray[b->gameNum].type == TYPE_SPANISH) { strcat(bstring, "-"); } } else { if (garray[b->gameNum].type != TYPE_SPANISH) { strcat(bstring, "-"); } } } else { if (colorval(b->board[f][r]) == WHITE) strcat(bstring, wpstring[piecetype(b->board[f][r])]); else strcat(bstring, bpstring[piecetype(b->board[f][r])]); } } strcat(bstring, " "); } } strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); if (garray[b->gameNum].numHalfMoves) { sprintf(tmp, "1 "); } else { sprintf(tmp, "-1 "); } strcat(bstring, tmp); sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d (%s) %s\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 ? tenth_str(ml[garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : "0:00", garray[b->gameNum].numHalfMoves ? ml[garray[b->gameNum].numHalfMoves - 1].algString : "none"); strcat(bstring, tmp); return 0; } /* style 5, written mainly by girbal from the original style12 */ PUBLIC int style5(game_state_t *b, move_t *ml) { int f, r; char tmp[80]; int ws, bs; int boardsize = (garray[b->gameNum].type == TYPE_POLISH ? 10 : 8); board_calc_strength(b, &ws, &bs); sprintf(bstring, "<5>%03d%s%s%s%-17s%-17s", /* Style info [ 0] */ b->gameNum + 1, /* Game number [ 4] */ boardsize == 10 ? "p" : "o", /* Board Size [ 7] */ orient == BLACK ? "B" : "W", /* Point of View [ 8] */ b->onMove == BLACK ? "B" : "W", /* Who is next [ 9] */ garray[b->gameNum].black_name, /* Black player [10] */ garray[b->gameNum].white_name); /* White player [27] */ for (r = (boardsize - 1); r >= 0; r--) { /* The Board [44] */ for (f = 0; f <= (boardsize - 1); f++) { if (b->board[f][r] == NOPIECE) { if ((f + r) % 2 == 1) strcat(bstring, " "); else strcat(bstring, "-"); } else { if (colorval(b->board[f][r]) == WHITE) strcat(bstring, wpstring[piecetype(b->board[f][r])]); else strcat(bstring, bpstring[piecetype(b->board[f][r])]); } } } sprintf(tmp, "%3d %3d %2d %2d %+d %d %d %d (%s) %s %s\n", bTime, wTime, bs, ws, myTurn, garray[b->gameNum].wInitTime / 600, garray[b->gameNum].wIncrement / 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", garray[b->gameNum].numHalfMoves ? "+1" : "-1"); strcat(bstring, tmp); return 0; } PUBLIC int board_load_british(game_state_t *gs) { int f, r; for (f = 0; f <= 9; f++){ for (r = 0; r <= 9; r++) gs->board[f][r] = NOPIECE; } gs->onMove = BLACK; gs->moveNum = 1; gs->lastIrreversable = -1; gs->board[0][0] = W_PIECE; gs->board[2][0] = W_PIECE; gs->board[4][0] = W_PIECE; gs->board[6][0] = W_PIECE; gs->board[1][1] = W_PIECE; gs->board[3][1] = W_PIECE; gs->board[5][1] = W_PIECE; gs->board[7][1] = W_PIECE; gs->board[0][2] = W_PIECE; gs->board[2][2] = W_PIECE; gs->board[4][2] = W_PIECE; gs->board[6][2] = W_PIECE; gs->board[1][7] = B_PIECE; gs->board[3][7] = B_PIECE; gs->board[5][7] = B_PIECE; gs->board[7][7] = B_PIECE; gs->board[0][6] = B_PIECE; gs->board[2][6] = B_PIECE; gs->board[4][6] = B_PIECE; gs->board[6][6] = B_PIECE; gs->board[1][5] = B_PIECE; gs->board[3][5] = B_PIECE; gs->board[5][5] = B_PIECE; gs->board[7][5] = B_PIECE; return 0; } /* load board for spanish match */ PUBLIC int board_load_spanish(game_state_t *gs) { int f, r; for (f = 0; f <= 9; f++){ for (r = 0; r <= 9; r++) gs->board[f][r] = NOPIECE; } gs->onMove = BLACK; gs->moveNum = 1; gs->lastIrreversable = -1; gs->board[1][0] = W_PIECE; gs->board[3][0] = W_PIECE; gs->board[5][0] = W_PIECE; gs->board[7][0] = W_PIECE; gs->board[2][1] = W_PIECE; gs->board[4][1] = W_PIECE; gs->board[6][1] = W_PIECE; gs->board[0][1] = W_PIECE; gs->board[1][2] = W_PIECE; gs->board[3][2] = W_PIECE; gs->board[5][2] = W_PIECE; gs->board[7][2] = W_PIECE; gs->board[0][7] = B_PIECE; gs->board[2][7] = B_PIECE; gs->board[4][7] = B_PIECE; gs->board[6][7] = B_PIECE; gs->board[1][6] = B_PIECE; gs->board[3][6] = B_PIECE; gs->board[5][6] = B_PIECE; gs->board[7][6] = B_PIECE; gs->board[0][5] = B_PIECE; gs->board[2][5] = B_PIECE; gs->board[4][5] = B_PIECE; gs->board[6][5] = B_PIECE; return 0; } /* load board for pool match */ PUBLIC int board_load_pool(game_state_t *gs) { int f, r; for (f = 0; f <= 9; f++){ for (r = 0; r <= 9; r++) gs->board[f][r] = NOPIECE; } gs->onMove = BLACK; gs->moveNum = 1; gs->lastIrreversable = -1; gs->board[0][0] = W_PIECE; gs->board[2][0] = W_PIECE; gs->board[4][0] = W_PIECE; gs->board[6][0] = W_PIECE; gs->board[1][1] = W_PIECE; gs->board[3][1] = W_PIECE; gs->board[5][1] = W_PIECE; gs->board[7][1] = W_PIECE; gs->board[0][2] = W_PIECE; gs->board[2][2] = W_PIECE; gs->board[4][2] = W_PIECE; gs->board[6][2] = W_PIECE; gs->board[1][7] = B_PIECE; gs->board[3][7] = B_PIECE; gs->board[5][7] = B_PIECE; gs->board[7][7] = B_PIECE; gs->board[0][6] = B_PIECE; gs->board[2][6] = B_PIECE; gs->board[4][6] = B_PIECE; gs->board[6][6] = B_PIECE; gs->board[1][5] = B_PIECE; gs->board[3][5] = B_PIECE; gs->board[5][5] = B_PIECE; gs->board[7][5] = B_PIECE; return 0; } /* load board for polish match */ PUBLIC int board_load_polish(game_state_t *gs) { int f, r; for (f = 0; f <= 9; f++){ for (r = 0; r <= 9; r++) gs->board[f][r] = NOPIECE; } gs->onMove = BLACK; gs->moveNum = 1; gs->lastIrreversable = -1; gs->board[0][0] = W_PIECE; gs->board[2][0] = W_PIECE; gs->board[4][0] = W_PIECE; gs->board[6][0] = W_PIECE; gs->board[8][0] = W_PIECE; gs->board[1][1] = W_PIECE; gs->board[3][1] = W_PIECE; gs->board[5][1] = W_PIECE; gs->board[7][1] = W_PIECE; gs->board[9][1] = W_PIECE; gs->board[0][2] = W_PIECE; gs->board[2][2] = W_PIECE; gs->board[4][2] = W_PIECE; gs->board[6][2] = W_PIECE; gs->board[8][2] = W_PIECE; gs->board[1][3] = W_PIECE; gs->board[3][3] = W_PIECE; gs->board[5][3] = W_PIECE; gs->board[7][3] = W_PIECE; gs->board[9][3] = W_PIECE; gs->board[1][9] = B_PIECE; gs->board[3][9] = B_PIECE; gs->board[5][9] = B_PIECE; gs->board[7][9] = B_PIECE; gs->board[9][9] = B_PIECE; gs->board[0][8] = B_PIECE; gs->board[2][8] = B_PIECE; gs->board[4][8] = B_PIECE; gs->board[6][8] = B_PIECE; gs->board[8][8] = B_PIECE; gs->board[1][7] = B_PIECE; gs->board[3][7] = B_PIECE; gs->board[5][7] = B_PIECE; gs->board[7][7] = B_PIECE; gs->board[9][7] = B_PIECE; gs->board[0][6] = B_PIECE; gs->board[2][6] = B_PIECE; gs->board[4][6] = B_PIECE; gs->board[6][6] = B_PIECE; gs->board[8][6] = B_PIECE; return 0; } /* Taken out since i think it would be much easier to load * board from program instead of outside file. It works if * you want it back. */ #if 0 PUBLIC int board_read_file(char *gname, game_state_t *gs) { int f, r; FILE *fp; char fname[MAX_FILENAME_SIZE + 1]; int c; int onNewLine = 1; int onColor = -1; int onPiece = -1; int onFile = -1; int onRank = -1; sprintf(fname, "%s/%s", board_dir, gname); fp = fopen(fname, "r"); if (!fp) return 1; for (f = 0; f <= 9; f++){ for (r = 0; r <= 9; r++) gs->board[f][r] = NOPIECE; } 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 = PIECE; break; case 'Q': onPiece = PIECE; break; case 'K': onPiece = KING; break; case 'L': onPiece = KING; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': onFile = c - 'a'; onRank = -1; 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; break; default: break; } } } fclose(fp); return 0; } #endif #define WHITE_SQUARE 1 #define BLACK_SQUARE 0 #define ANY_SQUARE -1 #define SquareColor(f, r) ((f ^ r) & 1) /* PRIVATE void place_piece(board_t b, int piece, int squareColor) { int r, f; int placed = 0; if (iscolor(piece, BLACK)) r = 7; else r = 0; while (!placed) { if (squareColor == ANY_SQUARE) { f = rand() % 8; } else { f = (rand() % 4) * 2; if (SquareColor(f, r) != squareColor) f++; } if ((b)[f][r] == NOPIECE) { (b)[f][r] = piece; placed = 1; } } } */