chess

Terminal based Chess trainer using Anki
git clone git://git.dimitrijedobrota.com/chess.git
Log | Files | Refs

commit 3bc33d613e5898f992e13a8a1a9f1801a7b3b87e
parent 2fc01f0a8ff7da1fafbcf537702e54c2cf94711e
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Wed, 14 Sep 2022 16:14:45 +0200

Remove move.c and general improvements

Diffstat:
MMakefile | 36+++++++++++-------------------------
Minclude/anki.h | 2+-
Minclude/board.h | 35++++++++++++++++++-----------------
Minclude/display.h | 7++++---
Dinclude/move.h | 17-----------------
Msrc/anki.c | 6+++---
Msrc/board.c | 50+++++++++++++++++++++++++++++++++++++++++---------
Msrc/display.c | 50++++++++++++++++++++++++++++++--------------------
Msrc/main.c | 105++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Dsrc/move.c | 47-----------------------------------------------
10 files changed, 180 insertions(+), 175 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,57 +1,44 @@ # GNU Makefile for Chess Anki Trainer # -# Usage: make [-f path\Makefile] [DEBUG=Y] [NO_UNICODE=Y] [NO_MOUSE=Y] target +# Usage: make [-f path\Makefile] [DEBUG=Y] [NO_UNICODE=Y] target NAME = chess CC = gcc CFLAGS = -I include -LDFLAGS =-lcurl -ljson-c -lncursesw -lm +LDFLAGS =-lcurl -ljson-c -lm SRC = src OBJ = obj -BINDIR = bin +BIN = bin -BIN = bin/$(NAME) SRCS=$(wildcard $(SRC)/*.c) OBJS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SRCS)) +TRGT=$(BIN)/$(NAME) -ifeq ($(OS),Windows_NT) - RM = del - NAME := $(NAME).exe - DEL_CLEAN = $(subst /,\,$(BIN)) $(subst /,\,$(OBJS)) -else - RM = rm -f - DEL_CLEAN = $(BIN) $(OBJS) -endif - ifeq ($(DEBUG),Y) - CFLAGS += -lciid -ldisplayd - CFLAGS += -Wall -Wextra -Werror -Wpedantic -fsanitize=address -ggdb + LDFLAGS += -lciid -lpaned + CFLAGS += -ggdb -Wall -Wextra -Werror -Wpedantic else - CFLAGS += -lcii -ldisplay + LDFLAGS += -lcii -lpane endif ifeq ($(NO_UNICODE),Y) CFLAGS += -D NO_UNICODE endif -ifeq ($(NO_MOUSE),Y) - CFLAGS += -D NO_MOUSE -endif - -all: $(BIN) +all: $(TRGT) -$(BIN): $(OBJS) +$(TRGT): $(OBJS) $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ)/%.o: $(SRC)/%.c $(CC) -c $< -o $@ $(CFLAGS) $(LDFLAGS) clean: - -$(RM) $(DEL_CLEAN) + -$(RM) $(BIN)/* $(OBJ)/* help: - @echo "Game of Life Simulation" + @echo "Chess Anki Trainer" @echo @echo "Usage: make [-f path\Makefile] [DEBUG=Y] [NO_UNICODE=Y] target" @echo @@ -63,7 +50,6 @@ help: @echo "Optional parameters:" @echo " DEBUG - Compile binary file with debug flags enabled" @echo " NO_UNICODE - Compile binary file that does not use Unicode characters" - @echo " NO_MOUSE - Compile binary file that does not have mouse support even if terminal supports it" @echo .PHONY: all clean help docs diff --git a/include/anki.h b/include/anki.h @@ -1,7 +1,7 @@ #ifndef ANKI_H #define ANKI_H -#include <except.h> +#include <cii/except.h> #include <stddef.h> #define Move_T card_T diff --git a/include/board.h b/include/board.h @@ -2,13 +2,12 @@ #define BOARD_H #include "anki.h" -#include "move.h" -#define Move_T Board_T -#define G Grave_T +#define T Board_T +#define G Grave_T -typedef struct Move_T *Move_T; -typedef struct G *G; +typedef struct G *G; +typedef struct T *T; enum AC { AC_QUIT = -3, AC_SUSPEND, AC_INDEX }; @@ -18,7 +17,7 @@ typedef void (*review_f)(void); typedef struct game_T *game_T; struct game_T { card_T card; - move_T *moves; + char **moves; review_f review_next; int pass; @@ -33,29 +32,31 @@ struct game_T { char buffer[BUFF_SIZE + 1]; int buffer_crnt; - size_t moves_size; - size_t boards_size; - Move_T boards[]; + size_t moves_num; + T boards[]; }; -Move_T Board_new(void); -Move_T Board_from_FEN(char *fen); -void Board_free(Move_T *self); +T Board_new(void); +T Board_from_FEN(char *fen); +void Board_free(T *self); -Move_T Board_play(Move_T self, char *m); -void Board_print(Move_T self); +T Board_play(T self, char *m); +void Board_print(T self); -char Board_atIndex(Move_T self, int i, int j); +char Board_atIndex(T self, int i, int j); int piece_get_index(char l); -G Board_grave(Move_T self, char player); +G Board_grave(T self, char player); char Grave_atIndex(G self, int index); int Grave_size(G self); /* GAME */ game_T game_new(size_t moves); -#undef Move_T +/* MOVE */ +char ** Move_list(char *pgn, size_t *size); + +#undef T #undef G #endif diff --git a/include/display.h b/include/display.h @@ -1,11 +1,10 @@ #ifndef DISPAY_H #define DISPAY_H -#include <pane.h> -#include <widgetList.h> +#include <pane/pane.h> +#include <pane/widgets.h> #include "board.h" -#include "except.h" #define MAX_READ 5 @@ -38,6 +37,8 @@ struct boardStyle_T { int border; int piece; int annotation; + int pass; + int fail; }; typedef struct movesInfo_T *movesInfo_T; diff --git a/include/move.h b/include/move.h @@ -1,17 +0,0 @@ -#ifndef MOVE_H -#define MOVE_H - -#include <stddef.h> - -typedef struct move_T *move_T; -struct move_T { - char turn[10]; - char white[10]; - char black[10]; -}; - -move_T *Move_list(char *pgn, size_t *size); -char *Move_halfmove(move_T *moves, int halfturn); - -#undef Board_T -#endif diff --git a/src/anki.c b/src/anki.c @@ -2,14 +2,14 @@ #include <stdlib.h> #include <string.h> +#include <cii/assert.h> +#include <cii/except.h> +#include <cii/mem.h> #include <curl/curl.h> #include <json-c/json.h> #include "anki.h" -#include "assert.h" #include "display.h" -#include "except.h" -#include "mem.h" #define Move_T card_T diff --git a/src/board.c b/src/board.c @@ -1,18 +1,18 @@ -#include "board.h" -#include "assert.h" -#include "mem.h" - #include <ctype.h> #include <stddef.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include "move.h" +#include <cii/assert.h> +#include <cii/mem.h> + +#include "board.h" #define T Board_T #define G Grave_T -typedef struct G *G; +#define MAX_MOVE 10 #define MAX_PLAY 1024 const char def_board[8][8] = {"rnbqkbnr", "pppppppp", " ", " ", @@ -294,9 +294,9 @@ char Board_atIndex(T self, int i, int j) { /* GAME */ -game_T game_new(size_t moves_size) { - game_T game = ALLOC(sizeof(*game) + moves_size * sizeof(struct move_T)); - game->moves_size = moves_size; +game_T game_new(size_t moves_num) { + game_T game = ALLOC(sizeof(*game) + moves_num * sizeof(struct Board_T)); + game->moves_num = moves_num; game->display_current = 0; game->buffer_crnt = 0; game->pass = 0; @@ -307,4 +307,36 @@ game_T game_new(size_t moves_size) { return game; } +/* MOVE */ + +char **Move_list(char *pgn, size_t *size) { + char *crnt; + size_t moves_size = 1, cnt = 0; + + char **moves = malloc(MAX_PLAY * sizeof(*moves)); + char *buffer = malloc(1000 * sizeof(char)); + strcpy(buffer, pgn); + + moves[0] = "Starting move, empty board!"; + for (crnt = strtok(buffer, " "); crnt; + crnt = strtok(NULL, " "), cnt = (cnt + 1) % 3) { + switch (cnt) { + case 0: + continue; + case 1: + case 2: + if (strcmp(crnt, "*") != 0) { + moves[moves_size] = malloc(MAX_MOVE * sizeof(char)); + strcpy(moves[moves_size], crnt); + moves_size++; + } + } + } + + if (size) + *size = moves_size - 1; + + return moves; +} + #undef G diff --git a/src/display.c b/src/display.c @@ -2,12 +2,11 @@ #include <stddef.h> #include <string.h> -#include <pane.h> -#include <utils.h> +#include <pane/pane.h> +#include <pane/utils.h> #include "anki.h" #include "display.h" -#include "move.h" #define USTART L'\u2654' @@ -28,15 +27,25 @@ void board_display(widget_T widget) { UNUSED(info); - int bg_color, fg_color; + int bg_color, fg_color, dark; size_t x_start = centerHorisontal(pane, 16); size_t y_start = centerVertical(pane, 8); for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { - bg_color = ((i + j) % 2) ? style->square_dark : style->square_light; + dark = style->square_dark; + if (game->pass) + dark = style->pass; + else if (game->fail) + dark = style->fail; + bg_color = ((i + j) % 2) ? dark : style->square_light; fg_color = style->piece; +#ifndef NO_UNICODE tb_set_cell(x_start + 2 * i, y_start + j, convert(Board_atIndex(board, j, i)), fg_color, bg_color); +#else + tb_set_cell(x_start + 2 * i, y_start + j, Board_atIndex(board, j, i), + fg_color, bg_color); +#endif tb_set_cell(x_start + 2 * i + 1, y_start + j, ' ', fg_color, bg_color); } } @@ -104,22 +113,21 @@ int game_handleInput(data_T data, struct tb_event ev) { game->display_current = game->move_current; return 1; case TB_KEY_ENTER: - if (game->move_current == game->boards_size) { + if (game->move_current == game->moves_num) { anki_grade(game->pass); game->review_next(); - return 1; + return INPUT_REFORM; } if (game->buffer_crnt) { - if (strcmp(game->buffer, - Move_halfmove(game->moves, game->move_current)) != 0) { + if (strcmp(game->buffer, game->moves[game->move_current + 1]) != 0) { game->move_fail = game->move_current + 1; - game->move_current = game->boards_size; + game->move_current = game->moves_num; game->fail = 1; } else { game->display_current = ++game->move_current; - if (game->move_current == game->boards_size) + if (game->move_current == game->moves_num) game->pass = 1; memset(game->buffer, '\0', BUFF_SIZE); @@ -134,7 +142,8 @@ int game_handleInput(data_T data, struct tb_event ev) { game->buffer[--game->buffer_crnt] = '\0'; return 1; default: - if (!isalnum(ev.ch) && ev.ch != '+' && ev.ch != '#' && ev.ch != '-') + if (!isalnum(ev.ch) && ev.ch != '+' && ev.ch != '#' && ev.ch != '-' && + ev.ch != '=') break; if (game->buffer_crnt >= BUFF_SIZE) @@ -166,12 +175,12 @@ void moves_display(widget_T widget) { if (!widget->inited) { widget->inited = 1; - info->list = widgetList_new(widget->pane, game->moves_size); + info->list = widgetList_new(widget->pane, game->moves_num / 2 + 1); } widgetList_T list = info->list; - int display_row = - ACLAMP(((int)game->display_current - 1) / 2, 0, ((int)game->moves_size)); + int display_row = ACLAMP(((int)game->display_current - 1) / 2, 0, + ((int)game->moves_num / 2)); widgetList_cacl(list, display_row); pane_clear(pane, 0); @@ -179,11 +188,12 @@ void moves_display(widget_T widget) { size_t index_end = MIN(list->index_start + list->display_num, (game->move_current + 1) / 2); for (i = list->index_start; i < index_end; i++, y++) { - move_T move = game->moves[i]; - move_display(game, style, -1, move->turn, x, y); - move_display(game, style, i * 2 + 1, move->white, x + style->padding, y); + tb_printf(x, y, style->foreground, style->background, "%*d.", + style->padding - 1, i + 1); + move_display(game, style, i * 2 + 1, game->moves[i * 2 + 1], + x + style->padding, y); if (i * 2 + 2 <= game->move_current) - move_display(game, style, i * 2 + 2, move->black, x + 2 * style->padding, - y); + move_display(game, style, i * 2 + 2, game->moves[i * 2 + 2], + x + 2 * style->padding, y); } } diff --git a/src/main.c b/src/main.c @@ -6,24 +6,33 @@ #define TB_IMPL #define TB_OPT_TRUECOLOR -#include <except.h> -#include <mem.h> -#include <menu.h> -#include <pane.h> -#include <utils.h> -#include <widgetList.h> +#include <cii/except.h> +#include <cii/mem.h> +#include <pane/menu.h> +#include <pane/pane.h> +#include <pane/utils.h> +#include <pane/widgets.h> #include "anki.h" #include "board.h" #include "display.h" -#include "move.h" + +/* static char *profile = NULL; */ void set_selectDeck(void); void set_selectProfile(void); +void profile_selected(char *name, int ignore); +void deck_selected(char *name, int ignore); void start(void); void stop(void); +struct widget_T error_widget = { + .pane = NULL, + .callback = widgetCenter_print, + .title = "Error", +}; + struct menuInfo_T mainMenuInfo; struct menuStyle_T mainMenuStyle = { .separator = "<------------->", @@ -57,6 +66,8 @@ struct boardStyle_T boardStyle = { .square_dark = TB_GREEN, .square_light = TB_WHITE, .piece = TB_BLACK, + .pass = TB_BLUE, + .fail = TB_RED, .border = 0, .annotation = 3, }; @@ -118,23 +129,47 @@ struct widget_T title_widget = { .info = &titleInfo, }; -void review_card() { +void done_review(void) { + char message[] = + "You have finished all of the reviews for this deck. Please " + "check back later!"; + struct tb_event ev; + data_T data = data_new(message, NULL); + widget_setData(&error_widget, data); + widget_activate(&error_widget, MAIN); + error_widget.callback(&error_widget); + tb_poll_event(&ev); + if (ev.ch == 'q' || ev.key == TB_KEY_ESC) + stop(); +} + +void review_finished(void) { + + pane_unsplit(MAIN); + pane_clear(MAIN, 0); + + done_review(); + set_selectDeck(); + widget_activate(&mainMenu_widget, MAIN); +} + +void review_card(void) { char *fen; - size_t moves_size, i; + size_t moves_num, i; - card_T card = anki_current_card(); - move_T *moves = Move_list(card_pgn(card), &moves_size); - game_T game = game_new(moves_size); + card_T card = anki_current_card(); - game->boards[0] = (fen = card_fen(card)) ? Board_from_FEN(fen) : Board_new(); - for (i = 0; i < moves_size; i++) { - int base = i * 2; - game->boards[base + 1] = Board_play(game->boards[base], moves[i]->white); - game->boards[base + 2] = - Board_play(game->boards[base + 1], moves[i]->black); + if (card == NULL) { + review_finished(); + return; } - game->boards_size = - moves_size * 2 - (strcmp(moves[moves_size - 1]->black, "*") == 0); + + char **moves = Move_list(card_pgn(card), &moves_num); + game_T game = game_new(moves_num); + + game->boards[0] = (fen = card_fen(card)) ? Board_from_FEN(fen) : Board_new(); + for (i = 1; i <= moves_num; i++) + game->boards[i] = Board_play(game->boards[i - 1], moves[i]); game->card = card; game->review_next = review_card; @@ -157,18 +192,28 @@ void deck_selected(char *name, int ignore) { anki_load_deck(name); - pane_clear(MAIN, 1); - children1 = pane_vsplit(MAIN, 2, -5, 1); - children2 = pane_split(children1[1], 2, -(MOVE_PADDING * 3 + 4), 2); + if (anki_current_card()) { + pane_clear(MAIN, 1); + children1 = pane_vsplit(MAIN, 2, -5, 1); + children2 = pane_split(children1[1], 2, -(MOVE_PADDING * 3 + 4), 2); - review_card(); - widget_activate(&title_widget, children1[0]); - widget_activate(&moves_widget, children2[0]); - widget_activate(&board_widget, children2[1]); + review_card(); + + widget_activate(&title_widget, children1[0]); + widget_activate(&moves_widget, children2[0]); + widget_activate(&board_widget, children2[1]); + } else { + done_review(); + set_selectDeck(); + widget_activate(&mainMenu_widget, MAIN); + } } void profile_selected(char *name, int ignore) { UNUSED(ignore); + /* if (!profile) */ + /* profile = malloc(100 * sizeof(char)); */ + /* strcpy(profile, name); */ anki_load_profile(name); set_selectDeck(); } @@ -203,12 +248,6 @@ void stop(void) { exit(1); } -struct widget_T error_widget = { - .pane = NULL, - .callback = widgetCenter_print, - .title = "Error", -}; - void start(void) { struct tb_event ev; char message[] = "Can't start anki, make sure it's running and try again"; diff --git a/src/move.c b/src/move.c @@ -1,47 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "mem.h" -#include "move.h" - -#define MAX_PLAY 1024 - -move_T Move_new(char *turn, char *white, char *black) { - move_T m; - NEW0(m); - - strcpy(m->turn, turn); - strcpy(m->white, white); - strcpy(m->black, black); - return m; -} - -move_T *Move_list(char *pgn, size_t *size) { - char *turn, *white, *black, *crnt; - char **test[] = {&turn, &white, &black}; - size_t moves_size = 0, cnt = 0; - - move_T *moves = malloc(MAX_PLAY * sizeof(*moves)); - for (crnt = strtok(pgn, " "); crnt; crnt = strtok(NULL, " ")) { - *test[cnt++] = crnt; - if (cnt == 3) { - moves[moves_size++] = Move_new(turn, white, black); - *test[1] = NULL; - cnt = 0; - } - } - - if (*test[1]) - moves[moves_size++] = Move_new(turn, white, ""); - - if (size) - *size = moves_size; - - return moves; -} - -char *Move_halfmove(move_T *moves, int halfturn) { - return (halfturn % 2) ? moves[halfturn / 2]->black - : moves[halfturn / 2]->white; -}