#include #include #include #include #include FILE *lcd = NULL; static char *gamelog = 0; static int human, search_depth; static void append_to_gamelog(const char *line, const uint8_t win_line) { // I _could_ dynamically compute the size but ... don't let // `perfect' be the enemy of `good' ? char prepend[8]; if (win_line) { prepend[0] = '\n'; prepend[1] = 0; } else if (ply & 1) { snprintf(prepend, 7, "%s%d. ", (ply == 1) ? "" : "\n", ply/2+1); } else { strcpy(prepend, " "); } // Make room for this line gamelog = realloc(gamelog, strlen(gamelog) + strlen(prepend) + strlen(line) + 1); strcat(gamelog,prepend); strcat(gamelog,line); } static void end_game(char *line, char *win) { append_to_gamelog(line, 0); append_to_gamelog(win, 1); fputs("Game over: ",lcd); fputs(win,lcd); fflush(lcd); } static int handle_turn(char *line) { // Track win state uint8_t new_win = (won == 0xFF); switch (do_ptn(line)) { // Errors case PTN_INVALID: { fputs("Invalid PTN.",lcd); return -1; break; } case ACT_ILLEGAL: { fputs("Illegal action.",lcd); return -1; break; } case ACT_OVERFLOW: { fputs("Move would cause internal overflow, select another."); return EXIT_FAILURE; break; } // Game has ended case GAME_END: { // Did it end this turn? if (new_win) { switch (won) { case WIN_DRAW: { end_game(line,"1/2-1/2"); break; } case WIN_FLAT_BLACK: { end_game(line,"0-F"); break; } case WIN_FLAT_WHITE: { end_game(line,"F-0"); break; } case WIN_ROAD_BLACK: { end_game(line,"0-R"); break; } case WIN_ROAD_WHITE: { end_game(line,"R-0"); break; } } } fputs("Game over, enter `new' to play again."); if (! new_win) return EXIT_FAILURE; break; } // Valid, append to game log case PTN_VALID: case ACT_OK: { append_to_gamelog(line, 0); break; } } return EXIT_SUCCESS; } static void new_game(uint8_t size) { reset_state(size); fputs("New 5x5 game! ct1986 at search depth "); fputc(search_depth + '0', lcd); fputc('.', lcd); fflush(lcd); if (gamelog) gamelog = realloc(gamelog, sizeof(char)); else gamelog = malloc(sizeof(char)); gamelog[0] = 0; } static void dot(const uint8_t depth) { if (depth == 0) { fputc('#', lcd); } } static int ct1986_turn(const uint8_t search_depth) { // Prepare progress bar fputs("Computing "); // Run the minimax float minimax = ct1986_generate(search_depth); // Failed to find a move? if ((minimax <= -infty && (ply & 1) == 1) ||(minimax >= infty && (ply & 1) == 0)) { fputs("Opponent concedes!"); return EXIT_FAILURE; } else { fputs("Result: "); fputs(ct1986_ptn); handle_turn(ct1986_ptn); return EXIT_SUCCESS; } } static int input_is_not_turn(const char *line) { if (!strcmp(line,"help")) { fputs("Valid commands: depth [0-9], help, new, \ play (b|w), self-play, ."); } else if (!strcmp(line,"log")) { fputs(gamelog); } else if (!strcmp(line,"new")) { new_game(5); } else if (!strcmp(line,"self-play")) { while (ct1986_turn(search_depth) == 0); } else if (!strncmp(line,"depth",5)) { if (strnlen(line,7) == 7 && line[6] >= '0' && line[6] <= '9') { search_depth = line[6] - '0'; fputs("New search depth: ",lcd); fputc(line[6], lcd); fflush(lcd); } else { fputs("Usage: depth [0-9].",lcd); } } else if (!strncmp(line,"play",4)) { if (strnlen(line,7) == 6 && ((line[5] == 'b' || line[5] == 'B') || (line[5] == 'w' || line[5] == 'W'))) { // 'b' is even :) human = 1 - (line[5] & 1); new_game(5); } else { fputs("Usage: play (b|w).\n", lcd); } } else { return EXIT_FAILURE; } return EXIT_SUCCESS; } int main(int argc, char **argv) { (void)(argc); (void)(argv); lcd = fopen("/dev/lcd","w"); if (lcd == NULL) return EXIT_FAILURE; // Set up output function for ct1986 ct1986_display_progress = ˙ human = 0; search_depth = 3; new_game(5); char *line = NULL; ssize_t read; size_t alloc_size; for (int playing = 1; playing;) { fputs("Welcome to ct1986!\n",lcd); fflush(lcd); fflush(stdout); while ((human == 0) && (read = getline(&line, &alloc_size, stdin)) != -1) { if (read) { line[read - 1] = 0; if (input_is_not_turn(line)) { int r = handle_turn(line); if (r == EXIT_SUCCESS && won == 0xFF) { human = 1; } } } } if ((human == 0) && (read == -1)) { playing = 0; } else { ct1986_turn(search_depth); human = 0; } } return 0; }