/* Sjeng - a chess variants playing program Copyright (C) 2000 Gian-Carlo Pascutto 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA File: book.c Purpose: book initialization, selection of book moves, etc... */ #include "sjeng.h" #include "protos.h" #include "extvars.h" char book[4000][161]; char book_flags[4000][41]; int num_book_lines; int book_ply; int use_book; char opening_history[STR_BUFF]; #define book_always 1 /* corresponds with ! */ #define book_never 2 /* corresponds with ? */ #define book_interesting 3 /* !? */ #define book_solid 4 /* = */ #define book_murky 5 /* ?! */ int init_book (void) { /* simply read all the book moves into a book array. The book will be a simple char[5000][81] array (5000 max book lines, since you can't have *too* many when you're doing this slow strncpy method ;) After all, this is really just a kludge 'till I add hashing, and support transpositions and such ;) Returns true if reading in the book was successful. */ FILE *f_book; int ch, i = 0, j = 0; int tagmode = FALSE; /* recognize multiple tags */ int commentmode = FALSE; memset(book_flags, 0, sizeof(book_flags)); memset(book, 0, sizeof(book)); num_book_lines = 0; /* init our random numbers: */ srand((unsigned) time (NULL)); if (Variant == Normal) { if ((f_book = fopen ("normal.opn", "r")) == NULL) return FALSE; } else if (Variant == Crazyhouse) { if ((f_book = fopen ("zh.opn", "r")) == NULL) return FALSE; } else if (Variant == Suicide) { if ((f_book = fopen ("suicide.opn", "r")) == NULL) return FALSE; } else if (Variant == Losers) { if ((f_book = fopen ("losers.opn", "r")) == NULL) return FALSE; } else { if ((f_book = fopen ("bug.opn", "r")) == NULL) return FALSE; } while ((ch = getc(f_book)) != EOF) { if (commentmode) { if (ch == '/') /* end comment */ { commentmode = FALSE; } } else { if (ch == '\n') { /* end of book line */ /* not ending an empty book line */ if (j > 0) { book[i++][j] = '\0'; j = 0; } tagmode = FALSE; } else if (ch == '!') { if (!tagmode) { book_flags[i][((j + 1) / 4) - 1] = book_always; tagmode = TRUE; } else { book_flags[i][((j + 1) / 4) - 1] = book_murky; } } else if (ch == '?') { if (!tagmode) { book_flags[i][((j + 1) / 4) - 1] = book_never; tagmode = TRUE; } else { book_flags[i][((j + 1) / 4) - 1] = book_interesting; } } else if (ch == '=') { book_flags[i][((j + 1) / 4) - 1] = book_solid; tagmode = TRUE; } else if ((ch == ' ') || (ch == '\t')) { /* skip spaces and tabs */ tagmode = FALSE; } else if (ch == '/') /* start comment */ { commentmode = TRUE; } else if (j < 160 && i < 4000) /* middle of book line */ { book[i][j++] = ch; tagmode = FALSE; } /* If j >= 100, then the book line was too long. The rest will be read, but ignored, and will be null-character terminated when a '\n' is read. If i >= 2000, then there are too many book lines. The remaining lines will be read, but ignored. */ } } num_book_lines = i; fclose(f_book); return TRUE; } move_s choose_book_move (void) { /* Since the book is sorted alphabetically, we can use strncpy, and hope to get early exits once we've found the first few moves in the book. Once we choose a book move, we'll make a variable indicate where it was found, so we can start our search for the next move there. */ static int last_book_move = 0; int book_match = FALSE; int i, j, num_moves, random_number, num_replies; char possible_move[5], coord_move[5]; move_s book_replies[4000], moves[400]; char force_move = FALSE; int ic; srand((unsigned)time(0)); if (!book_ply) last_book_move = 0; num_replies = 0; gen(&moves[0]); num_moves = numb_moves; for (i = last_book_move; i < num_book_lines; i++) { /* check to see if opening line matches up to current book_ply: */ if (!strncmp(opening_history, book[i], (book_ply * 4)) || (!book_ply)) { /* if book move is legal, add it to possible list of book moves */ if ((book_flags[i][book_ply] != book_never) && (book_flags[i][book_ply] != book_murky)) { if (book_flags[i][book_ply] == book_always) { if (force_move != TRUE) { /* found 1st ! move -> remove normal ones */ force_move = TRUE; num_replies = 0; } } if ((force_move != TRUE) || ((force_move == TRUE) && (book_flags[i][book_ply] == book_always))) { strncpy(possible_move, book[i] + (book_ply * 4), 4); possible_move[4] = '\0'; for (j = 0; j < num_moves; j++) { comp_to_coord(moves[j], coord_move); if (!strcmp(possible_move, coord_move)) { ic = in_check(); make(&moves[0], j); if (check_legal(&moves[0], j, ic)) { book_replies[num_replies++] = moves[j]; book_match = TRUE; } unmake(&moves[0], j); } } } } } /* we can exit the search for a book move early, if we've no longer have a match, but we have found at least one match */ if (!book_match && num_replies) break; } /* now, if we have some book replies, pick our move randomly from book_replies: */ if (!num_replies) return dummy; printf("Book moves: %d\n", num_replies); random_number = rand() % num_replies; return book_replies[random_number]; }