#include #include #include #include #include #include #include "gui.h" #include "chess.h" #include "engine.h" #include "mistakes.h" typedef struct { Position pos; Engine engine; Gui gui; MistakeList mistakes; bool replay_mode; // allow revisiting mistakes size_t replay_index; } App; static void append_uci(char *line, size_t sz, const char *mv){ if (line[0]) strncat(line, " ", sz-1); strncat(line, mv, sz-1); } static void position_push_move_text(Position *pos, const Move *m, char *line, size_t lsz){ (void)pos; char u[8]; move_to_uci(m, u); append_uci(line, lsz, u); } static void collect_all_legal_uci(const Position *pos, char list[][8], size_t *n, size_t max){ Move mv[MAX_MOVES]; size_t k = chess_generate_legal_moves(pos, mv, MAX_MOVES); *n = 0; for (size_t i=0;i0)? (rand()%wsum) : 0; size_t pick=0; for (size_t i=0;i0 && parse_uci_move(props[0].uci, &app.pos, &m)) pick=0; else { snprintf(status, sizeof(status), "No engine move"); quit=true; continue; } } chess_make_move(&app.pos, &m); position_push_move_text(&app.pos, &m, line_uci, sizeof(line_uci)); awaiting_player = true; // 6. Ask engine for optimal response from player engine_get_best_move(&app.engine, &app.pos, expected_player_move); snprintf(status, sizeof(status), "Your turn"); continue; } // Player move input int key=0; bool updated = gui_poll_move(&app.gui, &sel, &quit, &key); if (quit) break; if (key=='m' || key=='M'){ // enter simple replay: load a mistake line and restart from it to the position where best move is required if (app.mistakes.count>0){ if (app.replay_index >= app.mistakes.count) app.replay_index = 0; Mistake *mk = &app.mistakes.items[app.replay_index++]; // reset and play the line moves to reach the mistake position chess_init_start(&app.pos); char tmp[512]; snprintf(tmp, sizeof(tmp), "%s", mk->line); char *tok = strtok(tmp, " "); while (tok){ Move m; if (parse_uci_move(tok, &app.pos, &m)) chess_make_move(&app.pos, &m); tok = strtok(NULL, " "); } snprintf(status, sizeof(status), "Practice: best is %s", mk->best_move); strncpy(expected_player_move, mk->best_move, sizeof(expected_player_move)); awaiting_player = true; gui_set_flipped(&app.gui, !app.pos.white_to_move); // if it's black to move, flip so black bottom } } if (updated && sel.clicked && sel.to_sq>=0){ Move list[MAX_MOVES]; size_t n = chess_generate_legal_moves(&app.pos, list, MAX_MOVES); bool moved=false; Move chosen={0}; for (size_t i=0;i