fixed bishop + added pawn promotion + added move log

Sat, 29 Mar 2014 16:53:58 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 29 Mar 2014 16:53:58 +0100
changeset 18
6008840b859e
parent 17
2aed5418e142
child 19
6a26114297a1

fixed bishop + added pawn promotion + added move log

src/game.c file | annotate | diff | comparison | revisions
src/game.h file | annotate | diff | comparison | revisions
src/network.h file | annotate | diff | comparison | revisions
src/rules/bishop.c file | annotate | diff | comparison | revisions
src/rules/pawn.c file | annotate | diff | comparison | revisions
src/rules/rules.h file | annotate | diff | comparison | revisions
     1.1 --- a/src/game.c	Sat Mar 29 14:46:33 2014 +0100
     1.2 +++ b/src/game.c	Sat Mar 29 16:53:58 2014 +0100
     1.3 @@ -35,20 +35,68 @@
     1.4  
     1.5  static const uint8_t boardx = 10, boardy = 10;
     1.6  
     1.7 -static void draw_board(Board board, uint8_t mycolor) {
     1.8 +static uint8_t getpiecechr(uint8_t piece) {
     1.9 +    switch (piece & PIECE_MASK) {
    1.10 +    case ROOK: return 'R';
    1.11 +    case KNIGHT: return 'N';
    1.12 +    case BISHOP: return 'B';
    1.13 +    case QUEEN: return 'Q';
    1.14 +    case KING: return 'K';
    1.15 +    default: return '\0';
    1.16 +    }
    1.17 +}
    1.18 +
    1.19 +/**
    1.20 + * Maps a character to a piece.
    1.21 + * 
    1.22 + * Does not work for pawns, since they don't have a character.
    1.23 + * 
    1.24 + * @param c one of R,N,B,Q,K
    1.25 + * @return numeric value for the specified piece
    1.26 + */
    1.27 +static uint8_t getpiece(char c) {
    1.28 +    switch (c) {
    1.29 +        case 'R': return ROOK;
    1.30 +        case 'N': return KNIGHT;
    1.31 +        case 'B': return BISHOP;
    1.32 +        case 'Q': return QUEEN;
    1.33 +        case 'K': return KING;
    1.34 +        default: return 0;
    1.35 +    }
    1.36 +}
    1.37 +
    1.38 +/**
    1.39 + * Guesses the location of a piece for short algebraic notation.
    1.40 + * 
    1.41 + * @param board the current state of the board
    1.42 + * @param move the move date to operate on
    1.43 + * @return status code (see rules/rules.h for the codes)
    1.44 + */
    1.45 +static int getlocation(Board board, Move *move) {   
    1.46 +    uint8_t piece = move->piece & PIECE_MASK;
    1.47 +    switch (piece) {
    1.48 +        case PAWN: return pawn_getlocation(board, move);
    1.49 +        case ROOK: return rook_getlocation(board, move);
    1.50 +        case KNIGHT: return knight_getlocation(board, move);
    1.51 +        case BISHOP: return bishop_getlocation(board, move);
    1.52 +        case QUEEN: return queen_getlocation(board, move);
    1.53 +        case KING: return king_getlocation(board, move);
    1.54 +        default: return INVALID_MOVE_SYNTAX;
    1.55 +    }
    1.56 +}
    1.57 +
    1.58 +
    1.59 +static void draw_board(Board board, MoveListRoot *movelist, uint8_t mycolor) {
    1.60      
    1.61      for (uint8_t y = 0 ; y < 8 ; y++) {
    1.62          for (uint8_t x = 0 ; x < 8 ; x++) {
    1.63              uint8_t col = board[y][x] & COLOR_MASK;
    1.64              uint8_t piece = board[y][x] & PIECE_MASK;
    1.65 -            char piecec = ' ';
    1.66 -            switch (piece) {
    1.67 -                case PAWN: piecec = 'P'; break;
    1.68 -                case ROOK: piecec = 'R'; break;
    1.69 -                case KNIGHT: piecec = 'N'; break;
    1.70 -                case BISHOP: piecec = 'B'; break;
    1.71 -                case QUEEN: piecec = 'Q'; break;
    1.72 -                case KING: piecec = 'K'; break;
    1.73 +            char piecec;
    1.74 +            if (piece) {
    1.75 +                piecec = piece == PAWN ? 'P' : getpiecechr(piece);
    1.76 +            } else {
    1.77 +                piecec = ' ';
    1.78              }
    1.79              
    1.80              attrset((col == WHITE ? A_BOLD : A_DIM) |
    1.81 @@ -69,6 +117,45 @@
    1.82          mvaddch(boardy+1, x, 'a'+i);
    1.83          mvaddch(y, boardx-2, '1'+i);
    1.84      }
    1.85 +    
    1.86 +    /* move log */
    1.87 +    // TODO: introduce window to avoid bugs with a long move log
    1.88 +    uint8_t logy = 0;
    1.89 +    const uint8_t logx = boardx + 30;
    1.90 +    int logi = 1;
    1.91 +    MoveList *logelem = movelist->first;
    1.92 +    
    1.93 +    while (logelem) {
    1.94 +        logi++;
    1.95 +        if (logi % 2 == 0) {
    1.96 +            if ((logi - 2) % 4 == 0) {
    1.97 +                logy++;
    1.98 +                wmove(tchess_window, logy, logx);
    1.99 +            }
   1.100 +            printw("%d. ", logi / 2);
   1.101 +        }
   1.102 +
   1.103 +        if (logelem) {
   1.104 +            Move move = logelem->move;
   1.105 +            char logstr[] = {
   1.106 +                getpiecechr(move.piece),
   1.107 +                filechr(move.fromfile), rowchr(move.fromrow),
   1.108 +                move.capture ? 'x':'\0',
   1.109 +                filechr(move.tofile), rowchr(move.torow),
   1.110 +                move.check ? '+' : (move.checkmate ? '#' : 
   1.111 +                    (move.promotion ? '=' : '\0')),
   1.112 +                move.promotion ? getpiecechr(move.promotion) : '\0',
   1.113 +                ' '
   1.114 +            };
   1.115 +            for (int stri = 0 ; stri < sizeof(logstr) ; stri++) {
   1.116 +                if (logstr[stri]) {
   1.117 +                    addch(logstr[stri]);
   1.118 +                }
   1.119 +            }
   1.120 +            
   1.121 +            logelem = logelem->next;
   1.122 +        }
   1.123 +    }
   1.124  }
   1.125  
   1.126  /**
   1.127 @@ -100,9 +187,13 @@
   1.128          move->piece |= ENPASSANT_THREAT;
   1.129      }
   1.130      
   1.131 -    /* move (and maybe capture) */
   1.132 +    /* move (and maybe capture or promote) */
   1.133      msrc(board, move) = 0;
   1.134 -    mdst(board, move) = move->piece;
   1.135 +    if (move->promotion) {
   1.136 +        mdst(board, move) = move->promotion;
   1.137 +    } else {
   1.138 +        mdst(board, move) = move->piece;
   1.139 +    }
   1.140      
   1.141      /* castling */
   1.142      if (piece == KING &&
   1.143 @@ -180,45 +271,6 @@
   1.144  }
   1.145  
   1.146  /**
   1.147 - * Maps a character to a piece.
   1.148 - * 
   1.149 - * Does not work for pawns, since they don't have a character.
   1.150 - * 
   1.151 - * @param c one of R,N,B,Q,K
   1.152 - * @return numeric value for the specified piece
   1.153 - */
   1.154 -static uint8_t getpiece(char c) {
   1.155 -    switch (c) {
   1.156 -        case 'R': return ROOK;
   1.157 -        case 'N': return KNIGHT;
   1.158 -        case 'B': return BISHOP;
   1.159 -        case 'Q': return QUEEN;
   1.160 -        case 'K': return KING;
   1.161 -        default: return 0;
   1.162 -    }
   1.163 -}
   1.164 -
   1.165 -/**
   1.166 - * Guesses the location of a piece for short algebraic notation.
   1.167 - * 
   1.168 - * @param board the current state of the board
   1.169 - * @param move the move date to operate on
   1.170 - * @return status code (see rules/rules.h for the codes)
   1.171 - */
   1.172 -static int getlocation(Board board, Move *move) {   
   1.173 -    uint8_t piece = move->piece & PIECE_MASK;
   1.174 -    switch (piece) {
   1.175 -        case PAWN: return pawn_getlocation(board, move);
   1.176 -        case ROOK: return rook_getlocation(board, move);
   1.177 -        case KNIGHT: return knight_getlocation(board, move);
   1.178 -        case BISHOP: return bishop_getlocation(board, move);
   1.179 -        case QUEEN: return queen_getlocation(board, move);
   1.180 -        case KING: return king_getlocation(board, move);
   1.181 -        default: return INVALID_MOVE_SYNTAX;
   1.182 -    }
   1.183 -}
   1.184 -
   1.185 -/**
   1.186   * Evaluates a move syntactically and stores the move data in the specified
   1.187   * object.
   1.188   * 
   1.189 @@ -232,7 +284,7 @@
   1.190      memset(move, 0, sizeof(Move));
   1.191      move->fromfile = POS_UNSPECIFIED;
   1.192      move->fromrow = POS_UNSPECIFIED;
   1.193 -    // TODO: promotion
   1.194 +
   1.195      size_t len = strlen(mstr);
   1.196      
   1.197      /* evaluate check/checkmate flags */
   1.198 @@ -244,6 +296,18 @@
   1.199          move->checkmate = TRUE;
   1.200      }
   1.201      
   1.202 +    /* evaluate promotion */
   1.203 +    if (len > 3 && mstr[len-2] == '=') {
   1.204 +        move->promotion = getpiece(mstr[len-1]);
   1.205 +        if (!move->promotion) {
   1.206 +            return INVALID_MOVE_SYNTAX;
   1.207 +        } else {
   1.208 +            move->promotion |= mycolor;
   1.209 +            len -= 2;
   1.210 +            mstr[len] = 0;
   1.211 +        }
   1.212 +    }
   1.213 +    
   1.214      if (len == 2) {
   1.215          /* pawn move (e.g. "e4") */
   1.216          move->piece = PAWN;
   1.217 @@ -327,6 +391,11 @@
   1.218  
   1.219      
   1.220      if (move->piece) {
   1.221 +        if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0)
   1.222 +            && !move->promotion) {
   1.223 +            return NEED_PROMOTION;
   1.224 +        }
   1.225 +        
   1.226          move->piece |= mycolor;
   1.227          if (move->fromfile == POS_UNSPECIFIED
   1.228              || move->fromrow == POS_UNSPECIFIED) {
   1.229 @@ -339,14 +408,17 @@
   1.230      }
   1.231  }
   1.232  
   1.233 -static int sendmove(Board board, uint8_t mycolor, int opponent) {
   1.234 +static int sendmove(Board board, MoveListRoot *movelist,
   1.235 +    uint8_t mycolor, int opponent) {
   1.236 +    
   1.237      const size_t buflen = 8;
   1.238      char movestr[buflen];
   1.239      _Bool remisrejected = FALSE;
   1.240      uint8_t code;
   1.241      
   1.242 +    int inputy = getmaxy(tchess_window) - 6;
   1.243      while (1) {
   1.244 -        move(boardy+3, 0);
   1.245 +        move(inputy, 0);
   1.246          if (remisrejected) {
   1.247              printw(
   1.248                  "Use chess notation to enter your move.\n"
   1.249 @@ -386,46 +458,48 @@
   1.250              Move move;
   1.251              int eval_result = eval_move(board, mycolor, movestr, &move);
   1.252              switch (eval_result) {
   1.253 -                case VALID_MOVE_SYNTAX:
   1.254 -                    net_send_code(opponent, NETCODE_MOVE);
   1.255 -                    net_send_data(opponent, &move, sizeof(Move));
   1.256 -                    code = net_recieve_code(opponent);
   1.257 -                    move.check = code == NETCODE_CHECK;
   1.258 -                    move.checkmate = code == NETCODE_CHECKMATE;
   1.259 -                    // TODO: record move
   1.260 -                    if (code == NETCODE_DECLINE) {
   1.261 -                        printw("Invalid move.");
   1.262 +            case VALID_MOVE_SYNTAX:
   1.263 +                net_send_code(opponent, NETCODE_MOVE);
   1.264 +                net_send_data(opponent, &move, sizeof(Move));
   1.265 +                code = net_recieve_code(opponent);
   1.266 +                move.check = code == NETCODE_CHECK;
   1.267 +                move.checkmate = code == NETCODE_CHECKMATE;
   1.268 +                addmove(movelist, &move);
   1.269 +                if (code == NETCODE_DECLINE) {
   1.270 +                    printw("Invalid move.");
   1.271 +                } else {
   1.272 +                    apply_move(board, &move);
   1.273 +                    if (move.checkmate) {
   1.274 +                        printw("Checkmate!");
   1.275 +                        clrtoeol();
   1.276 +                        return 1;
   1.277                      } else {
   1.278 -                        apply_move(board, &move);
   1.279 -                        if (move.checkmate) {
   1.280 -                            printw("Checkmate!");
   1.281 -                            clrtoeol();
   1.282 -                            return 1;
   1.283 -                        } else {
   1.284 -                            return 0;
   1.285 -                        }
   1.286 +                        return 0;
   1.287                      }
   1.288 -                    break;
   1.289 -                case AMBIGUOUS_MOVE:
   1.290 -                    printw("Ambiguous move - "
   1.291 -                        "please specify the piece to move.");
   1.292 -                    break;
   1.293 -                case INVALID_POSITION:
   1.294 -                    printw("Cannot find the piece that shall be moved.");
   1.295 -                    break;
   1.296 -                default:
   1.297 -                    printw("Can't interpret move - "
   1.298 -                        "please use algebraic notation.");
   1.299 +                }
   1.300 +                break;
   1.301 +            case AMBIGUOUS_MOVE:
   1.302 +                printw("Ambiguous move - please specify the piece to move.");
   1.303 +                break;
   1.304 +            case INVALID_POSITION:
   1.305 +                printw("Cannot find the piece that shall be moved.");
   1.306 +                break;
   1.307 +            case NEED_PROMOTION:
   1.308 +                printw("You need to promote the pawn (append \"=Q\" e.g.)!");
   1.309 +                break;
   1.310 +            default:
   1.311 +                printw("Can't interpret move - please use algebraic notation.");
   1.312              }
   1.313              clrtoeol();
   1.314          }
   1.315      }
   1.316  }
   1.317  
   1.318 -static int recvmove(Board board, int opponent) {
   1.319 +static int recvmove(Board board, MoveListRoot *movelist, int opponent) {
   1.320      
   1.321 +    int inputy = getmaxy(tchess_window) - 6;
   1.322      while (1) {
   1.323 -        move(boardy+3, 0);
   1.324 +        move(inputy, 0);
   1.325          printw("Awaiting opponent move...");
   1.326          clrtoeol();
   1.327          refresh();
   1.328 @@ -454,7 +528,7 @@
   1.329                  net_recieve_data(opponent, &move, sizeof(Move));
   1.330                  if (validate_move(board, &move)) {
   1.331                      apply_move(board, &move);
   1.332 -                    // TODO: record move
   1.333 +                    addmove(movelist, &move);
   1.334                      if (move.check) {
   1.335                          net_send_code(opponent, NETCODE_CHECK);
   1.336                      } else if (move.checkmate) {
   1.337 @@ -470,6 +544,30 @@
   1.338      }
   1.339  }
   1.340  
   1.341 +void freemovelist(MoveListRoot* list) {
   1.342 +    MoveList *elem;
   1.343 +    elem = list->first;
   1.344 +    while (elem) {
   1.345 +        MoveList *cur = elem;
   1.346 +        elem = elem->next;
   1.347 +        free(cur);
   1.348 +    };
   1.349 +    free(list);
   1.350 +}
   1.351 +
   1.352 +void addmove(MoveListRoot* list, Move *move) {
   1.353 +    MoveList *elem = malloc(sizeof(MoveList));
   1.354 +    elem->next = NULL;
   1.355 +    elem->move = *move;
   1.356 +    
   1.357 +    if (list->last) {
   1.358 +        list->last->next = elem;
   1.359 +        list->last = elem;
   1.360 +    } else {
   1.361 +        list->first = list->last = elem;
   1.362 +    }
   1.363 +}
   1.364 +
   1.365  void game_start(Settings *settings, int opponent) {
   1.366      _Bool myturn = is_server(settings) ==
   1.367          (settings->gameinfo.servercolor == WHITE);
   1.368 @@ -477,6 +575,8 @@
   1.369      
   1.370      _Bool running;
   1.371      
   1.372 +    MoveListRoot* movelist = calloc(1, sizeof(MoveListRoot));
   1.373 +    
   1.374      Board board = {
   1.375          {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
   1.376          {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
   1.377 @@ -490,16 +590,18 @@
   1.378      
   1.379      do {
   1.380          clear();
   1.381 -        draw_board(board, mycolor);
   1.382 +        draw_board(board, movelist, mycolor);
   1.383          if (myturn) {
   1.384 -            running = !sendmove(board, mycolor, opponent);
   1.385 +            running = !sendmove(board, movelist, mycolor, opponent);
   1.386          } else {
   1.387 -            running = !recvmove(board, opponent);
   1.388 +            running = !recvmove(board, movelist, opponent);
   1.389              flushinp(); // flush any input the user hacked in while waiting
   1.390          }
   1.391          myturn ^= TRUE;
   1.392      }  while (running);
   1.393      
   1.394 +    freemovelist(movelist);
   1.395 +    
   1.396      mvaddstr(getmaxy(tchess_window)-1, 0,
   1.397          "Game has ended. Press any key to leave...");
   1.398      getch();
     2.1 --- a/src/game.h	Sat Mar 29 14:46:33 2014 +0100
     2.2 +++ b/src/game.h	Sat Mar 29 16:53:58 2014 +0100
     2.3 @@ -72,11 +72,25 @@
     2.4      uint8_t fromrow;
     2.5      uint8_t tofile;
     2.6      uint8_t torow;
     2.7 +    uint8_t promotion;
     2.8      _Bool check;
     2.9      _Bool checkmate;
    2.10      _Bool capture;
    2.11  } Move;
    2.12  
    2.13 +typedef struct MoveList MoveList;
    2.14 +typedef struct MoveListRoot MoveListRoot;
    2.15 +
    2.16 +struct MoveListRoot {
    2.17 +    MoveList* first;
    2.18 +    MoveList* last;
    2.19 +};
    2.20 +
    2.21 +struct MoveList {
    2.22 +    Move move;
    2.23 +    MoveList* next;
    2.24 +};
    2.25 +
    2.26  #define POS_UNSPECIFIED UINT8_MAX
    2.27  #define mdst(b,m) b[(m)->torow][(m)->tofile]
    2.28  #define msrc(b,m) b[(m)->fromrow][(m)->fromfile]
    2.29 @@ -89,6 +103,9 @@
    2.30  #define rowidx(row) (row-'1')
    2.31  #define fileidx(file) (file-'a')
    2.32  
    2.33 +#define rowchr(row) (row+'1')
    2.34 +#define filechr(file) (file+'a')
    2.35 +
    2.36  #define chkidx(move) (isidx((move)->fromfile) && isidx((move)->fromrow) && \
    2.37          isidx((move)->tofile) && isidx((move)->torow))
    2.38  
    2.39 @@ -98,6 +115,9 @@
    2.40  
    2.41  void game_start(Settings *settings, int opponent);
    2.42  
    2.43 +void freemovelist(MoveListRoot* list);
    2.44 +void addmove(MoveListRoot *movelist, Move *move);
    2.45 +
    2.46  #ifdef	__cplusplus
    2.47  }
    2.48  #endif
     3.1 --- a/src/network.h	Sat Mar 29 14:46:33 2014 +0100
     3.2 +++ b/src/network.h	Sat Mar 29 16:53:58 2014 +0100
     3.3 @@ -46,7 +46,7 @@
     3.4  #define NETCODE_CHECK 0x23
     3.5  #define NETCODE_CHECKMATE 0x24
     3.6      
     3.7 -#define NETCODE_VERSION 4
     3.8 +#define NETCODE_VERSION 5
     3.9  
    3.10  typedef struct {
    3.11      int fd; /* -1, if we are the client */
     4.1 --- a/src/rules/bishop.c	Sat Mar 29 14:46:33 2014 +0100
     4.2 +++ b/src/rules/bishop.c	Sat Mar 29 16:53:58 2014 +0100
     4.3 @@ -109,7 +109,7 @@
     4.4                  move->fromfile = file;
     4.5              }
     4.6              file = move->tofile - d;
     4.7 -            if (isfile(file) && board[row][file] == move->piece) {
     4.8 +            if (isidx(file) && board[row][file] == move->piece) {
     4.9                  if (amb) {
    4.10                      return AMBIGUOUS_MOVE;
    4.11                  }
     5.1 --- a/src/rules/pawn.c	Sat Mar 29 14:46:33 2014 +0100
     5.2 +++ b/src/rules/pawn.c	Sat Mar 29 16:53:58 2014 +0100
     5.3 @@ -32,6 +32,22 @@
     5.4  
     5.5  _Bool pawn_chkrules(Board board, Move *move) {
     5.6      int8_t d = ((move->piece & COLOR_MASK) == WHITE ? -1 : 1);
     5.7 +    
     5.8 +    if (move->torow == (d < 0 ? 7 : 0)) {
     5.9 +        if (move->promotion) {
    5.10 +            uint8_t promopiece = move->promotion & PIECE_MASK;
    5.11 +            if (!promopiece || promopiece == PAWN || promopiece == KING) {
    5.12 +                return FALSE;
    5.13 +            }
    5.14 +        } else {
    5.15 +            return FALSE;
    5.16 +        }
    5.17 +    } else {
    5.18 +        if (move->promotion) {
    5.19 +            return FALSE;
    5.20 +        }
    5.21 +    }
    5.22 +    
    5.23      if (move->capture) {
    5.24          if (move->fromrow == move->torow + d && (
    5.25              move->fromfile == move->tofile + 1 ||
     6.1 --- a/src/rules/rules.h	Sat Mar 29 14:46:33 2014 +0100
     6.2 +++ b/src/rules/rules.h	Sat Mar 29 16:53:58 2014 +0100
     6.3 @@ -41,6 +41,7 @@
     6.4  #define INVALID_MOVE_SYNTAX 1
     6.5  #define INVALID_POSITION    2
     6.6  #define AMBIGUOUS_MOVE      3
     6.7 +#define NEED_PROMOTION      4
     6.8  
     6.9  #endif	/* RULES_H */
    6.10  

mercurial