/* vi: set tabstop=4 shiftwidth=4: */ /* * $Id: board.c,v 1.3 1996/12/28 22:11:05 schweikh Exp $ */ #include /* printf */ #include /* memset */ #include /* malloc */ #include "board.h" #include "chess.h" #include "error.h" #include "init.h" #include "initlang.h" #include "shutup.h" int read_board (char *l, State * s) /* * Read board and other information from l. * Write state information into s. Return the requested `mate in'. */ { int row; int col; int errors = 0; /* 0 .. ? */ unsigned char *board; char *lang; char **word, *c; int words, i, mate_in; /* break the line into blank separated words */ for (c = l, words = 1; *c != '\0'; ++c) { if (*c == ' ') { ++words; *c = '\0'; } } if (words < 8) { err_quit ("incomplete input"); } word = malloc (words * sizeof *word); check_sys (word != NULL); word[0] = l; for (i = 1; i < words; ++i) { while (*l++ != '\0'); word[i] = l; } lang = "english"; /* default language */ for (i = 6; i < words; ++i) { if ((strcmp (word[i], LANGUAGE_TAG) == 0) && (i + 1 < words)) { lang = word[i + 1]; if (lang[strlen (lang) - 1] == ';') { lang[strlen (lang) - 1] = '\0'; } } } Initialize_language (lang); board = s->brd; Memset (board, 0, 64 * sizeof board[0]); l = word[0]; /* parse the position */ row = 7; col = 0; for (; *l != '\0'; ++l) { switch (*l) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': col += *l - '0'; break; case '/': if (col != 8) { err_msg ("%s", M.not8); Fprintf (stderr, "%s\n", word[0]); Fprintf (stderr, "%*s^\n", l - word[0], ""); ++errors; } col = 0; --row; if (row < 0) { err_msg ("%s", M.more_rows); Fprintf (stderr, "%s\n", word[0]); Fprintf (stderr, "%*s^\n", l - word[0], ""); row = 0; /* or we cross array bounds later on */ ++errors; } break; default: if (*l == M.K) board[8 * row + col] = WHITE | KING; else if (*l == M.k) board[8 * row + col] = BLACK | KING; else if (*l == M.Q) board[8 * row + col] = WHITE | QUEEN; else if (*l == M.q) board[8 * row + col] = BLACK | QUEEN; else if (*l == M.R) board[8 * row + col] = WHITE | ROOK; else if (*l == M.r) board[8 * row + col] = BLACK | ROOK; else if (*l == M.B) board[8 * row + col] = WHITE | BISHOP; else if (*l == M.b) board[8 * row + col] = BLACK | BISHOP; else if (*l == M.N) board[8 * row + col] = WHITE | KNIGHT; else if (*l == M.n) board[8 * row + col] = BLACK | KNIGHT; else if (*l == M.P) board[8 * row + col] = WHITE | PAWN; else if (*l == M.p) board[8 * row + col] = BLACK | PAWN; else { err_msg ("%s `%c'", M.inv_piece, *l); ++errors; } ++col; } } if (row != 0 || col != 8) { err_msg ("%s", M.not8); Fprintf (stderr, "%s\n", word[0]); Fprintf (stderr, "%*s^\n", strlen (word[0]), ""); ++errors; } /* Reset everything but s.brd, which MUST BE the first struct member */ Memset (board + sizeof s->brd, 0, sizeof (State) - sizeof s->brd); scan_board (s); /* now we have pos[], fig[], n[], pm[], lm[] * but not sp */ /* who is to move? */ if (*word[1] == M.black1) { s->sp |= SP_BLACK2MV; } else { s->sp &= ~SP_BLACK2MV; } /* Who may castle? */ if (*word[2] != '-') { for (l = word[2]; *l != '\0'; ++l) { if (*l == M.K) { if (POSSIBLE_O_O) { s->sp |= SP_O_O; } else { err_msg ("%s %s", M.w_short, M.impossible); ++errors; } } else if (*l == M.Q) { if (POSSIBLE_O_O_O) { s->sp |= SP_O_O_O; } else { err_msg ("%s %s", M.w_long, M.impossible); ++errors; } } else if (*l == M.k) { if (POSSIBLE_o_o) { s->sp |= SP_o_o; } else { err_msg ("%s %s", M.b_short, M.impossible); ++errors; } } else if (*l == M.q) { if (POSSIBLE_o_o_o) { s->sp |= SP_o_o_o; } else { err_msg ("%s %s", M.b_long, M.impossible); ++errors; } } else { err_msg ("invalid castling specification"); ++errors; } } } /* any ep possible? */ if (*word[3] != '-') { i = *word[3] - 'a'; if (i < 0 || i > 7) { err_msg ("invalid ep specification"); ++errors; } else { if (BLACK_TO_MOVE) { if (board[A4 + i] == (WHITE | PAWN) && board[A3 + i] == FREE && board[A2 + i] == FREE) { s->sp |= (s->sp & ~SP_EP_POS) + A4 + i; } else { err_msg ("%s %s", M.ep, M.impossible); ++errors; } } else { if (board[A5 + i] == (BLACK | PAWN) && board[A6 + i] == FREE && board[A7 + i] == FREE) { s->sp |= (s->sp & ~SP_EP_POS) + A5 + i; } else { err_msg ("%s %s", M.ep, M.impossible); ++errors; } } } } if (strcmp (word[4], "bm") != 0) { err_msg ("expected word bm"); ++errors; } /* do some sanity checks */ if (s->fig[0][0] == 0) { /* no white king */ err_msg ("%s", M.no_w_king); ++errors; } if (s->fig[1][0] == 0) { /* no black king */ err_msg ("%s", M.no_b_king); ++errors; } /* Number of moves to mate in */ mate_in = 0; for (i = 6; i < words; ++i) { if ((strcmp (word[i], MATE_TAG) == 0) && (i + 1 < words)) { mate_in = atoi (word[i + 1]); } } if (mate_in < 1) { err_msg ("%s", M.n_mate); ++errors; } if (errors) { err_quit ("%u %s", (unsigned) errors, errors == 1 ? M.error : M.errors); draw_board (s->brd); return INPUT_ERROR; } /* firstmv remains constant throughout the program */ if (BLACK_TO_MOVE) firstmv = BLACK; else firstmv = WHITE; return (int) mate_in; } void draw_board (unsigned char board[64]) /* * Draw a board. */ { int row; /* 0 .. 7 */ int line; /* 0 .. 7 */ #if 0 Puts ("board[64] = (hex)"); row = 8; do { --row; Printf (" %2x %2x %2x %2x %2x %2x %2x %2x\n", (int) board[8 * row], (int) board[8 * row + 1], (int) board[8 * row + 2], (int) board[8 * row + 3], (int) board[8 * row + 4], (int) board[8 * row + 5], (int) board[8 * row + 6], (int) board[8 * row + 7]); } while (row != 0); #endif Puts (" +-A--B--C--D--E--F--G--H-+"); row = 8; do { Printf ("%d |", row--); for (line = 0; line < 8; ++line) { switch (board[row * 8 + line]) { case FREE: Printf ((row + line) & 1 ? " " : ":::"); break; case WHITE | KING: Printf ((row + line) & 1 ? " %c " : ":%c:", M.K); break; case BLACK | KING: Printf ((row + line) & 1 ? " %c " : ":%c:", M.k); break; case WHITE | QUEEN: Printf ((row + line) & 1 ? " %c " : ":%c:", M.Q); break; case BLACK | QUEEN: Printf ((row + line) & 1 ? " %c " : ":%c:", M.q); break; case WHITE | ROOK: Printf ((row + line) & 1 ? " %c " : ":%c:", M.R); break; case BLACK | ROOK: Printf ((row + line) & 1 ? " %c " : ":%c:", M.r); break; case WHITE | BISHOP: Printf ((row + line) & 1 ? " %c " : ":%c:", M.B); break; case BLACK | BISHOP: Printf ((row + line) & 1 ? " %c " : ":%c:", M.b); break; case WHITE | KNIGHT: Printf ((row + line) & 1 ? " %c " : ":%c:", M.N); break; case BLACK | KNIGHT: Printf ((row + line) & 1 ? " %c " : ":%c:", M.n); break; case WHITE | PAWN: Printf ((row + line) & 1 ? " %c " : ":%c:", M.P); break; case BLACK | PAWN: Printf ((row + line) & 1 ? " %c " : ":%c:", M.p); break; default: err_msg ("board[row * 8 + line = %d] = %d\n", row * 8 + line, board[row * 8 + line]); } } Printf ("| %d\n", row + 1); } while (row != 0); Puts (" +-A--B--C--D--E--F--G--H-+"); } void tell_special (unsigned char mate_in, State * s) /* * print the information in the special variable */ { int p; /* 24 .. 39 */ unsigned char *board = s->brd; Puts (BLACK_TO_MOVE ? M.to_move_b : M.to_move_w); /* who's to move */ Printf (M.mate_in, (unsigned) mate_in); Putchar ('\n'); if (POSSIBLE_O_O) { Printf ("%s %s\n", M.w_short, s->sp & SP_O_O ? M.allowed : M.disallowed); } if (POSSIBLE_O_O_O) { Printf ("%s %s\n", M.w_long, s->sp & SP_O_O_O ? M.allowed : M.disallowed); } if (POSSIBLE_o_o) { Printf ("%s %s\n", M.b_short, s->sp & SP_o_o ? M.allowed : M.disallowed); } if (POSSIBLE_o_o_o) { Printf ("%s %s\n", M.b_long, s->sp & SP_o_o_o ? M.allowed : M.disallowed); } if (s->sp & SP_EP_POS) { p = (int) (s->sp & SP_EP_POS); Printf (M.can_ep, pos2string (p)); Putchar ('\n'); } else { if (BLACK_TO_MOVE) { for (p = A4; p <= H4; ++p) { if (board[p] == (WHITE | PAWN) && board[p - 8] == FREE && board[p - 16] == FREE && ((COL (p) != 0 && board[p - 1] == (BLACK | PAWN)) || (COL (p) != 7 && board[p + 1] == (BLACK | PAWN)))) { Printf (M.cant_ep, pos2string (p)); Putchar ('\n'); } } } else { for (p = A5; p <= H5; ++p) { if (board[p] == (BLACK | PAWN) && board[p + 8] == FREE && board[p + 16] == FREE && ((COL (p) != 0 && board[p - 1] == (WHITE | PAWN)) || (COL (p) != 7 && board[p + 1] == (WHITE | PAWN)))) { Printf (M.cant_ep, pos2string (p)); Putchar ('\n'); } } } } } void scan_board (State * s) /* * Initialize all other members of s (except sp) from board[], * that is fig[], pos[], n[], pm[] and lm[]. * Called after every move_pieces, so make this fast! */ { int i; /* 0 .. 64 */ int nw = 1; /* 1 .. 16 */ int nb = 1; /* 1 .. 16 */ unsigned char *board = s->brd; unsigned char *posw = s->pos[0], *posb = s->pos[1]; unsigned char *figw = s->fig[0], *figb = s->fig[1]; s->pm[0] = s->pm[1] = s->lm[0] = s->lm[1] = 0; for (i = 0; i < 64; ++i) { /* This loop is unrolled, don't count down */ if (board[i] != FREE) { switch (board[i]) { case BLACK | KING: posb[0] = (char) i; figb[0] = KING; break; case BLACK | PAWN: posb[nb] = (char) i; figb[nb] = PAWN; s->pm[1] |= bit[nb++]; break; case BLACK | KNIGHT: posb[nb] = (char) i; figb[nb++] = KNIGHT; break; case BLACK | BISHOP: posb[nb] = (char) i; figb[nb] = BISHOP; s->lm[1] |= bit[nb++]; break; case BLACK | ROOK: posb[nb] = (char) i; figb[nb] = ROOK; s->lm[1] |= bit[nb++]; break; case BLACK | QUEEN: posb[nb] = (char) i; figb[nb] = QUEEN; s->lm[1] |= bit[nb++]; break; case WHITE | KING: posw[0] = (char) i; figw[0] = KING; break; case WHITE | PAWN: posw[nw] = (char) i; figw[nw] = PAWN; s->pm[0] |= bit[nw++]; break; case WHITE | KNIGHT: posw[nw] = (char) i; figw[nw++] = KNIGHT; break; case WHITE | BISHOP: posw[nw] = (char) i; figw[nw] = BISHOP; s->lm[0] |= bit[nw++]; break; case WHITE | ROOK: posw[nw] = (char) i; figw[nw] = ROOK; s->lm[0] |= bit[nw++]; break; case WHITE | QUEEN: posw[nw] = (char) i; figw[nw] = QUEEN; s->lm[0] |= bit[nw++]; break; } } } s->n[0] = nw; s->n[1] = nb; } char * pos2string (unsigned char pos) /* * Convert a position (0-63) into a two byte string "a1" - "h8". * Toggle the address of the returned string after every call to * allow *two* calls to this function in two arguments like in * printf ("%s-%s\n", pos2string(a), pos2string(b)); */ { static char ret[2][3] = { {0, 0, 0}, {0, 0, 0}}; static int which = 0; if (pos > 63) { ret[which][0] = '?'; ret[which][1] = '?'; } else { ret[which][0] = 'a' + (pos & 7); ret[which][1] = '1' + ((pos >> 3) & 7); } which ^= 1; return ret[which ^ 1]; }