chess

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

display.c (5996B)


      1 #include <ctype.h>
      2 #include <stddef.h>
      3 #include <string.h>
      4 
      5 #include <pane/pane.h>
      6 #include <pane/utils.h>
      7 
      8 #include "anki.h"
      9 #include "display.h"
     10 
     11 #define USTART L'\u2654'
     12 
     13 wchar_t convert(char l) {
     14   if (l == ' ')
     15     return ' ';
     16   int p = piece_get_index(l);
     17   return (p >= 0) ? p + USTART : L'!';
     18 }
     19 
     20 void board_display(widget_T widget) {
     21   size_t       i, j;
     22   Pane_T       pane = widget->pane;
     23   boardInfo_T  info = (boardInfo_T)widget->info;
     24   boardStyle_T style = (boardStyle_T)widget->style;
     25   game_T       game = (game_T)widget->data->payload;
     26   Board_T      board = game->boards[game->display_current];
     27 
     28   UNUSED(info);
     29 
     30   int    bg_color, fg_color, dark;
     31   size_t x_start = centerHorisontal(pane, 16);
     32   size_t y_start = centerVertical(pane, 8);
     33   for (i = 0; i < 8; i++) {
     34     for (j = 0; j < 8; j++) {
     35       dark = style->square_dark;
     36       if (game->pass)
     37         dark = style->pass;
     38       else if (game->fail)
     39         dark = style->fail;
     40       bg_color = ((i + j) % 2) ? dark : style->square_light;
     41       fg_color = style->piece;
     42 #ifndef NO_UNICODE
     43       tb_set_cell(x_start + 2 * i, y_start + j,
     44                   convert(Board_atIndex(board, j, i)), fg_color, bg_color);
     45 #else
     46       tb_set_cell(x_start + 2 * i, y_start + j, Board_atIndex(board, j, i),
     47                   fg_color, bg_color);
     48 #endif
     49       tb_set_cell(x_start + 2 * i + 1, y_start + j, ' ', fg_color, bg_color);
     50     }
     51   }
     52 
     53   /* display_grave(Board_grave(board, 'w'), y++, startx); */
     54   /* display_grave(Board_grave(board, 'b'), y++, startx); */
     55 
     56   if (style->annotation) {
     57     char *files = "A B C D E F G H";
     58     char *ranks = "87654321";
     59     if (style->annotation & 8)
     60       tb_print(x_start, y_start - 1, TB_GREEN, 0, files);
     61     if (style->annotation & 2)
     62       tb_print(x_start, y_start + 8, TB_GREEN, 0, files);
     63     for (i = 0; i < 8; i++) {
     64       if (style->annotation & 1)
     65         tb_printf(x_start - 2, y_start + i, TB_GREEN, 0, "%c", ranks[i]);
     66       if (style->annotation & 4)
     67         tb_printf(x_start + 17, y_start + i, TB_GREEN, 0, "%c", ranks[i]);
     68     }
     69   }
     70 
     71   if (style->border) {
     72     tb_printf(x_start, y_start - 1, 0, style->border, "                ");
     73     tb_printf(x_start, y_start + 8, 0, style->border, "                ");
     74     for (i = y_start - 1; i < y_start + 9; i++) {
     75       tb_printf(x_start - 2, i, 0, style->border, "  ");
     76       tb_printf(x_start + 16, i, 0, style->border, "  ");
     77     }
     78   }
     79 
     80   tb_printf(x_start, pane_y(pane) + pane_height(pane) - 1, TB_GREEN, 0, "%*s",
     81             BUFF_SIZE, game->buffer);
     82 
     83   tb_present();
     84 }
     85 
     86 int game_handleInput(data_T data, struct tb_event ev) {
     87   game_T game = (game_T)data->payload;
     88 
     89   switch (ev.key) {
     90   case TB_KEY_ARROW_LEFT:
     91     if (game->display_current > 0)
     92       game->display_current--;
     93     return INPUT_HANDLED;
     94   case TB_KEY_ARROW_RIGHT:
     95     if (game->display_current < game->move_current)
     96       game->display_current++;
     97     return INPUT_HANDLED;
     98   case TB_KEY_ARROW_UP:
     99     game->display_current = 0;
    100     return INPUT_HANDLED;
    101   case TB_KEY_ARROW_DOWN:
    102     game->display_current = game->move_current;
    103     return INPUT_HANDLED;
    104   case TB_KEY_ENTER:
    105     if (game->move_current == game->moves_num) {
    106       anki_grade(game->pass);
    107       return (game->review_next()) ? INPUT_HANDLED : INPUT_REFORM;
    108     }
    109 
    110     if (game->buffer_crnt) {
    111       if (strcmp(game->buffer, game->moves[game->move_current + 1]) != 0) {
    112         game->move_fail = game->move_current + 1;
    113         game->move_current = game->moves_num;
    114         game->fail = 1;
    115       } else {
    116         game->display_current = ++game->move_current;
    117 
    118         if (game->move_current == game->moves_num)
    119           game->pass = 1;
    120 
    121         memset(game->buffer, '\0', BUFF_SIZE);
    122         game->buffer_crnt = 0;
    123       }
    124     }
    125     return INPUT_HANDLED;
    126   case TB_KEY_BACKSPACE:
    127   case TB_KEY_BACKSPACE2:
    128     CLAMP(game->buffer_crnt, 1, BUFF_SIZE + 1);
    129     game->buffer[--game->buffer_crnt] = '\0';
    130     return INPUT_HANDLED;
    131   default: {
    132     char *valid = "abcdefgh12345678KQRBNPx#+O-!?=";
    133     if (strchr(valid, ev.ch)) {
    134       if (game->buffer_crnt < BUFF_SIZE)
    135         game->buffer[game->buffer_crnt++] = ev.ch;
    136       return INPUT_HANDLED;
    137     }
    138     switch (ev.ch) {
    139     case 'r':
    140     case 'R':
    141       return (game->review_next()) ? INPUT_HANDLED : INPUT_REFORM;
    142     }
    143   }
    144   }
    145 
    146   return INPUT_IGNORED;
    147 }
    148 
    149 void move_display(game_T game, movesStyle_T style, size_t move_index,
    150                   char *move, int x, int y) {
    151   int color, background;
    152   color = (game->move_start == move_index) ? TB_GREEN : style->foreground;
    153   color = (game->move_fail == move_index) ? TB_RED : color;
    154   background =
    155       (game->display_current == move_index) ? style->active : style->background;
    156   tb_printf(x, y, color, background, "%*s", style->move_padding, move);
    157 }
    158 
    159 void moves_display(widget_T widget) {
    160   size_t       i;
    161   Pane_T       pane = widget->pane;
    162   movesInfo_T  info = (movesInfo_T)widget->info;
    163   movesStyle_T style = (movesStyle_T)widget->style;
    164   game_T       game = (game_T)widget->data->payload;
    165 
    166   if (!widget->inited) {
    167     widget->inited = 1;
    168     info->list = widgetList_new(widget->pane, game->moves_num / 2 + 1);
    169   }
    170 
    171   widgetList_T list = info->list;
    172   int          display_row = ACLAMP(((int)game->display_current - 1) / 2, 0,
    173                                     ((int)game->moves_num / 2));
    174   widgetList_cacl(list, display_row);
    175 
    176   pane_clear(pane, 0);
    177   int x = centerHorisontal(pane, 2 * style->move_padding + style->num_padding),
    178       y = pane_y(pane);
    179   size_t index_end =
    180       MIN(list->index_start + list->display_num, (game->move_current + 1) / 2);
    181   for (i = list->index_start; i < index_end; i++, y++) {
    182     tb_printf(x, y, style->foreground, style->background, "%d.", i + 1);
    183     move_display(game, style, i * 2 + 1, game->moves[i * 2 + 1],
    184                  x + style->num_padding, y);
    185     if (i * 2 + 2 <= game->move_current)
    186       move_display(game, style, i * 2 + 2, game->moves[i * 2 + 2],
    187                    x + style->num_padding + style->move_padding, y);
    188   }
    189 }