/*
ct1986, an interface to the ct library designed to be embedded on
a Raspberry Pi Zero
Copyright (C) 2021, tslil clingman
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 3 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, see .
*/
#include
#include
#include
#include
#include
#include
static int human;
static char *gamelog = 0;
static void
new_game(uint8_t size) {
reset_state(size);
lcd_printf_line(L_SCROLL, "New 5s game @ D%d",
negamax_search_depth);
if (gamelog) gamelog = realloc(gamelog, sizeof(char));
else gamelog = malloc(sizeof(char));
gamelog[0] = 0;
}
static int
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' ?
if (gamelog == NULL) return EXIT_FAILURE;
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);
// TODO: trap errno
strcat(gamelog, prepend);
strcat(gamelog, line);
return EXIT_SUCCESS;
}
static void
end_game(char *line, char *win) {
append_to_gamelog(line, 0);
append_to_gamelog(win, 1);
lcd_printf_line(L_SCROLL, "Game over: %s", win);
}
static int
handle_turn(char *line) {
// Track win state
uint8_t new_win = (won == 0xFF);
switch (do_ptn(line)) {
// Errors
case ACT_INVALID_PTN: {
lcd_put_line(L_SCROLL, "Invalid PTN.");
break;
}
case ACT_ILLEGAL: {
lcd_put_line(L_SCROLL, "Illegal ply.");
break; }
case ACT_OVERFLOW: {
lcd_put_line(L_SCROLL, "Overflow.");
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; }
}
return EXIT_SUCCESS;
} else {
lcd_put_line(L_SCROLL, "Game over.");
break;
}
}
// Valid, append to game log
default: {
append_to_gamelog(line, 0);
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
// Set up output function for negamax
static uint32_t perc;
inline void
negamax_display_progress(const uint8_t depth, const uint32_t length) {
if (depth == negamax_search_depth) {
lcd_printf_line(L_OVERWRITE, "Computing: %d%%",
(++perc*100)/length);
}
}
static int
negamax_turn() {
// Prepare progress bar
perc = 0;
lcd_put_line(L_SCROLL, "Computing: 0%");
// Run the minimax
float minimax = negamax_generate();
// Failed to find a move?
if (minimax < -infty) {
lcd_printf_line(L_SCROLL, "%s concedes!",
(ply & 1) ? "Black" : "White");
return EXIT_FAILURE;
} else {
lcd_printf_line(L_SCROLL, "%s: %s",
(ply & 1) ? "Black" : "White",
negamax_ptn);
return handle_turn(negamax_ptn);
}
}
static void
do_game_log(void) {
lcd_put_line(L_SCROLL, "TODO!");
}
static int
input_is_not_turn(const char *line) {
switch (line[0]) {
case 'l': { do_game_log(); break; }
case 'n': { new_game(5); break; }
case 'D': {
negamax_search_depth = line[1] - '0';
lcd_printf_line(L_SCROLL, "Search depth: %d",
negamax_search_depth);
break;
}
case 'B': { human = 1; new_game(5); break; }
case 'W': { human = 0; new_game(5); break; }
default: return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
const char* license = "ct1986, an interface to the ct library designed to be embedded on a Raspberry Pi Zero\n\
\n\
Copyright (C) 2021, tslil clingman\n\
\n\
This program comes with ABSOLUTELY NO WARRANTY; and is made available under the terms of the GNU GPL v3 license. This is free software, and you are welcome to redistribute it under certain conditions; see COPYING for details.\n";
#define LINE_BUFF_LEN 9
static char line[LINE_BUFF_LEN+1];
static int
poll_input(void) {
char c, *prompt;
int idx = 0, polling = 1;
if (ply & 1) prompt = "Black: ";
else prompt = "White: ";
lcd_put_line(L_SCROLL, prompt);
line[0] = 0;
while (polling) {
lcd_printf_line(L_OVERWRITE, "%s%s", prompt, line);
c = getchar();
switch (c) {
case 0x7F: {
if (idx>0) idx--;
line[idx] = 0;
break;
}
case 0xFF: // fall-through
case '\r': // fall-through
case '\n': {
polling = 0;
break;
}
default: {
if (idx+1 0) {
if (input_is_not_turn(line)) {
int r = handle_turn(line);
if (r == EXIT_SUCCESS && won == 0xFF) {
human = 1;
}
}
} else {
playing = 0;
human = 1;
}
}
lcd_stop_blink();
if (playing) {
negamax_turn();
human = 0;
}
}
free(gamelog);
negamax_free();
lcd_end();
endwin();
return EXIT_SUCCESS;
}