introduced game state structure

Mon, 31 Mar 2014 15:03:25 +0200

author
Mike Becker <universe@uap-core.de>
date
Mon, 31 Mar 2014 15:03:25 +0200
changeset 23
824c9522ce66
parent 22
41bbfd4d17a3
child 24
4d030da07c88

introduced game state structure

src/chess/bishop.c file | annotate | diff | comparison | revisions
src/chess/bishop.h file | annotate | diff | comparison | revisions
src/chess/king.c file | annotate | diff | comparison | revisions
src/chess/king.h file | annotate | diff | comparison | revisions
src/chess/knight.c file | annotate | diff | comparison | revisions
src/chess/knight.h file | annotate | diff | comparison | revisions
src/chess/pawn.c file | annotate | diff | comparison | revisions
src/chess/pawn.h file | annotate | diff | comparison | revisions
src/chess/queen.c file | annotate | diff | comparison | revisions
src/chess/queen.h file | annotate | diff | comparison | revisions
src/chess/rook.c file | annotate | diff | comparison | revisions
src/chess/rook.h file | annotate | diff | comparison | revisions
src/chess/rules.c file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
src/game.h file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
     1.1 --- a/src/chess/bishop.c	Mon Mar 31 14:08:00 2014 +0200
     1.2 +++ b/src/chess/bishop.c	Mon Mar 31 15:03:25 2014 +0200
     1.3 @@ -35,7 +35,7 @@
     1.4      return abs(move->torow-move->fromrow) == abs(move->tofile-move->fromfile);
     1.5  }
     1.6  
     1.7 -_Bool bishop_isblocked(Board board, Move *move) {
     1.8 +_Bool bishop_isblocked(GameState *gamestate, Move *move) {
     1.9      int dy = move->torow > move->fromrow ? 1 : -1;
    1.10      int dx = move->tofile > move->fromfile ? 1 : -1;
    1.11      
    1.12 @@ -45,7 +45,7 @@
    1.13      while (x != move->tofile-dx && y != move->torow-dy) {
    1.14          x += dx;
    1.15          y += dy;
    1.16 -        if (board[y][x]) {
    1.17 +        if (gamestate->board[y][x]) {
    1.18              return 1;
    1.19          }
    1.20      }
    1.21 @@ -53,12 +53,12 @@
    1.22      return 0;
    1.23  }
    1.24  
    1.25 -static int bishop_getloc_fixedfile(Board board, Move *move) {
    1.26 +static int bishop_getloc_fixedfile(GameState *gamestate, Move *move) {
    1.27      uint8_t d = abs(move->fromfile - move->tofile);
    1.28 -    if (board[move->torow - d][move->fromfile] == move->piece) {
    1.29 +    if (gamestate->board[move->torow - d][move->fromfile] == move->piece) {
    1.30          move->fromrow = move->torow - d;
    1.31      }
    1.32 -    if (board[move->torow + d][move->fromfile] == move->piece) {
    1.33 +    if (gamestate->board[move->torow + d][move->fromfile] == move->piece) {
    1.34          if (move->fromrow == POS_UNSPECIFIED) {
    1.35              move->fromrow = move->torow + d;
    1.36          } else {
    1.37 @@ -69,12 +69,12 @@
    1.38          INVALID_POSITION : VALID_MOVE_SYNTAX;
    1.39  }
    1.40  
    1.41 -static int bishop_getloc_fixedrow(Board board, Move *move) {
    1.42 +static int bishop_getloc_fixedrow(GameState *gamestate, Move *move) {
    1.43      uint8_t d = abs(move->fromrow - move->torow);
    1.44 -    if (board[move->fromrow][move->tofile - d] == move->piece) {
    1.45 +    if (gamestate->board[move->fromrow][move->tofile - d] == move->piece) {
    1.46          move->fromfile = move->tofile - d;
    1.47      }
    1.48 -    if (board[move->fromrow][move->tofile + d] == move->piece) {
    1.49 +    if (gamestate->board[move->fromrow][move->tofile + d] == move->piece) {
    1.50          if (move->fromfile == POS_UNSPECIFIED) {
    1.51              move->fromfile = move->tofile + d;
    1.52          } else {
    1.53 @@ -85,14 +85,14 @@
    1.54          INVALID_POSITION : VALID_MOVE_SYNTAX;
    1.55  }
    1.56  
    1.57 -int bishop_getlocation(Board board, Move *move) {
    1.58 +int bishop_getlocation(GameState *gamestate, Move *move) {
    1.59      
    1.60      if (move->fromfile != POS_UNSPECIFIED) {
    1.61 -        return bishop_getloc_fixedfile(board, move);
    1.62 +        return bishop_getloc_fixedfile(gamestate, move);
    1.63      }
    1.64      
    1.65      if (move->fromrow != POS_UNSPECIFIED) {
    1.66 -        return bishop_getloc_fixedrow(board, move);
    1.67 +        return bishop_getloc_fixedrow(gamestate, move);
    1.68      }
    1.69      
    1.70      _Bool amb = 0;
    1.71 @@ -100,7 +100,7 @@
    1.72          uint8_t row = move->torow + d;
    1.73          if (isidx(row)) {
    1.74              uint8_t file = move->tofile + d;
    1.75 -            if (isidx(file) && board[row][file] == move->piece) {
    1.76 +            if (isidx(file) && gamestate->board[row][file] == move->piece) {
    1.77                  if (amb) {
    1.78                      return AMBIGUOUS_MOVE;
    1.79                  }
    1.80 @@ -109,7 +109,7 @@
    1.81                  move->fromfile = file;
    1.82              }
    1.83              file = move->tofile - d;
    1.84 -            if (isidx(file) && board[row][file] == move->piece) {
    1.85 +            if (isidx(file) && gamestate->board[row][file] == move->piece) {
    1.86                  if (amb) {
    1.87                      return AMBIGUOUS_MOVE;
    1.88                  }
     2.1 --- a/src/chess/bishop.h	Mon Mar 31 14:08:00 2014 +0200
     2.2 +++ b/src/chess/bishop.h	Mon Mar 31 15:03:25 2014 +0200
     2.3 @@ -37,8 +37,8 @@
     2.4  #endif
     2.5  
     2.6  _Bool bishop_chkrules(Move *move);
     2.7 -_Bool bishop_isblocked(Board board, Move *move);
     2.8 -int bishop_getlocation(Board board, Move *move);
     2.9 +_Bool bishop_isblocked(GameState *gamestate, Move *move);
    2.10 +int bishop_getlocation(GameState *gamestate, Move *move);
    2.11  
    2.12  #ifdef	__cplusplus
    2.13  }
     3.1 --- a/src/chess/king.c	Mon Mar 31 14:08:00 2014 +0200
     3.2 +++ b/src/chess/king.c	Mon Mar 31 15:03:25 2014 +0200
     3.3 @@ -30,17 +30,17 @@
     3.4  #include "rules.h"
     3.5  #include "king.h"
     3.6  
     3.7 -_Bool king_chkrules(Board board, Move* move) {
     3.8 +_Bool king_chkrules(GameState *gamestate, Move* move) {
     3.9      // TODO: implement
    3.10      return 0;
    3.11  }
    3.12  
    3.13 -_Bool king_isblocked(Board board, Move *move) {
    3.14 +_Bool king_isblocked(GameState *gamestate, Move *move) {
    3.15      // TODO: implement
    3.16      return 1;
    3.17  }
    3.18  
    3.19 -int king_getlocation(Board board, Move *move) {
    3.20 +int king_getlocation(GameState *gamestate, Move *move) {
    3.21      // TODO: implement
    3.22      return INVALID_MOVE_SYNTAX;
    3.23  }
     4.1 --- a/src/chess/king.h	Mon Mar 31 14:08:00 2014 +0200
     4.2 +++ b/src/chess/king.h	Mon Mar 31 15:03:25 2014 +0200
     4.3 @@ -37,9 +37,9 @@
     4.4  extern "C" {
     4.5  #endif
     4.6  
     4.7 -_Bool king_chkrules(Board board, Move *move);
     4.8 -_Bool king_isblocked(Board board, Move *move);
     4.9 -int king_getlocation(Board board, Move *move);
    4.10 +_Bool king_chkrules(GameState *gamestate, Move *move);
    4.11 +_Bool king_isblocked(GameState *gamestate, Move *move);
    4.12 +int king_getlocation(GameState *gamestate, Move *move);
    4.13  
    4.14  #ifdef	__cplusplus
    4.15  }
     5.1 --- a/src/chess/knight.c	Mon Mar 31 14:08:00 2014 +0200
     5.2 +++ b/src/chess/knight.c	Mon Mar 31 15:03:25 2014 +0200
     5.3 @@ -38,12 +38,12 @@
     5.4      return (dx == 2 && dy == 1) || (dx == 1 && dy == 2);
     5.5  }
     5.6  
     5.7 -static int knight_getloc_fixedrow(Board board, Move *move) {
     5.8 +static int knight_getloc_fixedrow(GameState *gamestate, Move *move) {
     5.9      int d = 3 - abs(move->fromrow - move->torow);
    5.10      
    5.11      if (d == 1 || d == 2) {
    5.12          if (move->tofile < 6 &&
    5.13 -            board[move->fromrow][move->tofile + d] == move->piece) {
    5.14 +            gamestate->board[move->fromrow][move->tofile + d] == move->piece) {
    5.15              if (move->fromfile == POS_UNSPECIFIED) {
    5.16                  move->fromfile = move->tofile + d;
    5.17                  return VALID_MOVE_SYNTAX;
    5.18 @@ -52,7 +52,7 @@
    5.19              }
    5.20          }
    5.21          if (move->tofile > 1 &&
    5.22 -            board[move->fromrow][move->tofile - d] == move->piece) {
    5.23 +            gamestate->board[move->fromrow][move->tofile - d] == move->piece) {
    5.24              if (move->fromfile == POS_UNSPECIFIED) {
    5.25                  move->fromfile = move->tofile - d;
    5.26                  return VALID_MOVE_SYNTAX;
    5.27 @@ -65,12 +65,12 @@
    5.28      return INVALID_POSITION;
    5.29  }
    5.30  
    5.31 -static int knight_getloc_fixedfile(Board board, Move *move) {
    5.32 +static int knight_getloc_fixedfile(GameState *gamestate, Move *move) {
    5.33      int d = 3 - abs(move->fromfile - move->tofile);
    5.34      
    5.35      if (d == 1 || d == 2) {
    5.36          if (move->torow < 6 &&
    5.37 -            board[move->torow + d][move->fromfile] == move->piece) {
    5.38 +            gamestate->board[move->torow + d][move->fromfile] == move->piece) {
    5.39              if (move->fromrow == POS_UNSPECIFIED) {
    5.40                  move->fromrow = move->torow + d;
    5.41                  return VALID_MOVE_SYNTAX;
    5.42 @@ -79,7 +79,7 @@
    5.43              }
    5.44          }
    5.45          if (move->torow > 1 &&
    5.46 -            board[move->torow - d][move->fromfile] == move->piece) {
    5.47 +            gamestate->board[move->torow - d][move->fromfile] == move->piece) {
    5.48              if (move->fromrow == POS_UNSPECIFIED) {
    5.49                  move->fromrow = move->torow - d;
    5.50                  return VALID_MOVE_SYNTAX;
    5.51 @@ -92,14 +92,14 @@
    5.52      return INVALID_POSITION;
    5.53  }
    5.54  
    5.55 -int knight_getlocation(Board board, Move *move) {
    5.56 +int knight_getlocation(GameState *gamestate, Move *move) {
    5.57      
    5.58      if (move->fromfile != POS_UNSPECIFIED) {
    5.59 -        return knight_getloc_fixedfile(board, move);
    5.60 +        return knight_getloc_fixedfile(gamestate, move);
    5.61      }
    5.62      
    5.63      if (move->fromrow != POS_UNSPECIFIED) {
    5.64 -        return knight_getloc_fixedrow(board, move);
    5.65 +        return knight_getloc_fixedrow(gamestate, move);
    5.66      }
    5.67      
    5.68      for (int x = -2 ; x <= 2 ; x++) {
    5.69 @@ -113,7 +113,8 @@
    5.70              uint8_t cx = move->tofile + x;
    5.71              uint8_t cy = move->torow + y;
    5.72  
    5.73 -            if (isidx(cx) && isidx(cy) && board[cy][cx] == move->piece) {
    5.74 +            if (isidx(cx) && isidx(cy)
    5.75 +                && gamestate->board[cy][cx] == move->piece) {
    5.76                  if (move->fromfile == POS_UNSPECIFIED
    5.77                      && move->fromrow == POS_UNSPECIFIED) {
    5.78                      move->fromfile = cx;
     6.1 --- a/src/chess/knight.h	Mon Mar 31 14:08:00 2014 +0200
     6.2 +++ b/src/chess/knight.h	Mon Mar 31 15:03:25 2014 +0200
     6.3 @@ -37,8 +37,8 @@
     6.4  #endif
     6.5  
     6.6  _Bool knight_chkrules(Move *move);
     6.7 -#define knight_isblocked(b,m) 0
     6.8 -int knight_getlocation(Board board, Move *move);
     6.9 +#define knight_isblocked(gs,m) 0
    6.10 +int knight_getlocation(GameState *gamestate, Move *move);
    6.11  
    6.12  #ifdef	__cplusplus
    6.13  }
     7.1 --- a/src/chess/pawn.c	Mon Mar 31 14:08:00 2014 +0200
     7.2 +++ b/src/chess/pawn.c	Mon Mar 31 15:03:25 2014 +0200
     7.3 @@ -30,7 +30,7 @@
     7.4  #include "pawn.h"
     7.5  #include "rules.h"
     7.6  
     7.7 -_Bool pawn_chkrules(Board board, Move *move) {
     7.8 +_Bool pawn_chkrules(GameState *gamestate, Move *move) {
     7.9      int8_t d = ((move->piece & COLOR_MASK) == WHITE ? -1 : 1);
    7.10      
    7.11      if (move->torow == (d < 0 ? 7 : 0)) {
    7.12 @@ -53,8 +53,9 @@
    7.13              move->fromfile == move->tofile + 1 ||
    7.14              move->fromfile == move->tofile - 1)) {
    7.15  
    7.16 -            return mdst(board,move)
    7.17 -                || (board[move->fromrow][move->tofile] & ENPASSANT_THREAT);
    7.18 +            return mdst(gamestate->board, move) ||
    7.19 +                (gamestate->board[move->fromrow][move->tofile]
    7.20 +                & ENPASSANT_THREAT);
    7.21          } else {
    7.22              return 0;
    7.23          }
    7.24 @@ -69,11 +70,11 @@
    7.25      }
    7.26  }
    7.27  
    7.28 -_Bool pawn_isblocked(Board board, Move *move) {
    7.29 -    return mdst(board,move) && !move->capture;
    7.30 +_Bool pawn_isblocked(GameState *gamestate, Move *move) {
    7.31 +    return mdst(gamestate->board, move) && !move->capture;
    7.32  }
    7.33  
    7.34 -int pawn_getlocation(Board board, Move *move) {
    7.35 +int pawn_getlocation(GameState *gamestate, Move *move) {
    7.36      int8_t d = ((move->piece & COLOR_MASK) == WHITE ? -1 : 1);
    7.37      
    7.38      if (move->fromfile == POS_UNSPECIFIED) {
    7.39 @@ -85,7 +86,7 @@
    7.40      } else {
    7.41          /* advanced first move */
    7.42          if (move->fromrow == (d < 0 ? 2 : 5) &&
    7.43 -            msrc(board,move) != move->piece) {
    7.44 +            msrc(gamestate->board,move) != move->piece) {
    7.45  
    7.46              move->fromrow += d;
    7.47              if (move->fromrow > 6) {
     8.1 --- a/src/chess/pawn.h	Mon Mar 31 14:08:00 2014 +0200
     8.2 +++ b/src/chess/pawn.h	Mon Mar 31 15:03:25 2014 +0200
     8.3 @@ -36,9 +36,9 @@
     8.4  extern "C" {
     8.5  #endif
     8.6  
     8.7 -_Bool pawn_chkrules(Board board, Move *move);
     8.8 -_Bool pawn_isblocked(Board board, Move *move);
     8.9 -int pawn_getlocation(Board board, Move *move);
    8.10 +_Bool pawn_chkrules(GameState *gamestate, Move *move);
    8.11 +_Bool pawn_isblocked(GameState *gamestate, Move *move);
    8.12 +int pawn_getlocation(GameState *gamestate, Move *move);
    8.13  
    8.14  #ifdef	__cplusplus
    8.15  }
     9.1 --- a/src/chess/queen.c	Mon Mar 31 14:08:00 2014 +0200
     9.2 +++ b/src/chess/queen.c	Mon Mar 31 15:03:25 2014 +0200
     9.3 @@ -35,12 +35,12 @@
     9.4      return 0;
     9.5  }
     9.6  
     9.7 -_Bool queen_isblocked(Board board, Move *move) {
     9.8 +_Bool queen_isblocked(GameState *gamestate, Move *move) {
     9.9      // TODO: implement
    9.10      return 1;
    9.11  }
    9.12  
    9.13 -int queen_getlocation(Board board, Move *move) {
    9.14 +int queen_getlocation(GameState *gamestate, Move *move) {
    9.15      // TODO: implement
    9.16      return INVALID_MOVE_SYNTAX;
    9.17  }
    10.1 --- a/src/chess/queen.h	Mon Mar 31 14:08:00 2014 +0200
    10.2 +++ b/src/chess/queen.h	Mon Mar 31 15:03:25 2014 +0200
    10.3 @@ -37,8 +37,8 @@
    10.4  #endif
    10.5  
    10.6  _Bool queen_chkrules(Move *move);
    10.7 -_Bool queen_isblocked(Board board, Move *move);
    10.8 -int queen_getlocation(Board board, Move *move);
    10.9 +_Bool queen_isblocked(GameState *gamestate, Move *move);
   10.10 +int queen_getlocation(GameState *gamestate, Move *move);
   10.11  
   10.12  #ifdef	__cplusplus
   10.13  }
    11.1 --- a/src/chess/rook.c	Mon Mar 31 14:08:00 2014 +0200
    11.2 +++ b/src/chess/rook.c	Mon Mar 31 15:03:25 2014 +0200
    11.3 @@ -34,14 +34,14 @@
    11.4      return move->torow == move->fromrow || move->tofile == move->fromfile;
    11.5  }
    11.6  
    11.7 -_Bool rook_isblocked(Board board, Move *move) {
    11.8 +_Bool rook_isblocked(GameState *gamestate, Move *move) {
    11.9      
   11.10      if (move->torow == move->fromrow) {
   11.11          int d = move->tofile > move->fromfile ? 1 : -1;
   11.12          uint8_t f = move->fromfile;
   11.13          while (f != move->tofile-d) {
   11.14              f += d;
   11.15 -            if (board[move->fromrow][f]) {
   11.16 +            if (gamestate->board[move->fromrow][f]) {
   11.17                  return 1;
   11.18              }
   11.19          }
   11.20 @@ -50,7 +50,7 @@
   11.21          uint8_t r = move->fromrow;
   11.22          while (r != move->torow - d) {
   11.23              r += d;
   11.24 -            if (board[r][move->fromfile]) {
   11.25 +            if (gamestate->board[r][move->fromfile]) {
   11.26                  return 1;
   11.27              }
   11.28          }
   11.29 @@ -59,10 +59,10 @@
   11.30      return 0;
   11.31  }
   11.32  
   11.33 -static int rook_getloc_fixedrow(Board board, Move *move) {
   11.34 +static int rook_getloc_fixedrow(GameState *gamestate, Move *move) {
   11.35      uint8_t file = POS_UNSPECIFIED;
   11.36      for (uint8_t f = 0 ; f < 8 ; f++) {
   11.37 -        if (board[move->fromrow][f] == move->piece) {
   11.38 +        if (gamestate->board[move->fromrow][f] == move->piece) {
   11.39              if (file == POS_UNSPECIFIED) {
   11.40                  file = f;
   11.41              } else {
   11.42 @@ -78,10 +78,10 @@
   11.43      }
   11.44  }
   11.45  
   11.46 -static int rook_getloc_fixedfile(Board board, Move *move) {
   11.47 +static int rook_getloc_fixedfile(GameState *gamestate, Move *move) {
   11.48      uint8_t row = POS_UNSPECIFIED;
   11.49      for (uint8_t r = 0 ; r < 8 ; r++) {
   11.50 -        if (board[r][move->fromfile] == move->piece) {
   11.51 +        if (gamestate->board[r][move->fromfile] == move->piece) {
   11.52              if (row == POS_UNSPECIFIED) {
   11.53                  row = r;
   11.54              } else {
   11.55 @@ -97,13 +97,13 @@
   11.56      }
   11.57  }
   11.58  
   11.59 -int rook_getlocation(Board board, Move *move) {
   11.60 +int rook_getlocation(GameState *gamestate, Move *move) {
   11.61      
   11.62      if (move->fromfile != POS_UNSPECIFIED) {
   11.63          if (move->fromfile == move->tofile) {
   11.64 -            return rook_getloc_fixedfile(board, move);
   11.65 +            return rook_getloc_fixedfile(gamestate, move);
   11.66          } else {
   11.67 -            if (board[move->torow][move->fromfile] == move->piece) {
   11.68 +            if (gamestate->board[move->torow][move->fromfile] == move->piece) {
   11.69                  move->fromrow = move->torow;
   11.70                  return VALID_MOVE_SYNTAX;
   11.71              } else {
   11.72 @@ -114,9 +114,9 @@
   11.73      
   11.74      if (move->fromrow != POS_UNSPECIFIED) {
   11.75          if (move->fromrow == move->torow) {
   11.76 -            return rook_getloc_fixedrow(board, move);
   11.77 +            return rook_getloc_fixedrow(gamestate, move);
   11.78          } else {
   11.79 -            if (board[move->fromrow][move->tofile] == move->piece) {
   11.80 +            if (gamestate->board[move->fromrow][move->tofile] == move->piece) {
   11.81                  move->fromfile = move->tofile;
   11.82                  return VALID_MOVE_SYNTAX;
   11.83              } else {
   11.84 @@ -128,10 +128,10 @@
   11.85      Move chkrowmove = *move, chkfilemove = *move;
   11.86      
   11.87      chkrowmove.fromrow = move->torow;
   11.88 -    int chkrow = rook_getloc_fixedrow(board, &chkrowmove);
   11.89 +    int chkrow = rook_getloc_fixedrow(gamestate, &chkrowmove);
   11.90      
   11.91      chkfilemove.fromfile = move->tofile;
   11.92 -    int chkfile = rook_getloc_fixedfile(board, &chkfilemove);
   11.93 +    int chkfile = rook_getloc_fixedfile(gamestate, &chkfilemove);
   11.94      
   11.95      if ((chkrow == VALID_MOVE_SYNTAX && chkfile == VALID_MOVE_SYNTAX) ||
   11.96          chkrow == AMBIGUOUS_MOVE || chkfile == AMBIGUOUS_MOVE) {
    12.1 --- a/src/chess/rook.h	Mon Mar 31 14:08:00 2014 +0200
    12.2 +++ b/src/chess/rook.h	Mon Mar 31 15:03:25 2014 +0200
    12.3 @@ -37,8 +37,8 @@
    12.4  #endif
    12.5  
    12.6  _Bool rook_chkrules(Move *move);
    12.7 -_Bool rook_isblocked(Board board, Move *move);
    12.8 -int rook_getlocation(Board board, Move *move);
    12.9 +_Bool rook_isblocked(GameState *gamestate, Move *move);
   12.10 +int rook_getlocation(GameState *gamestate, Move *move);
   12.11  
   12.12  #ifdef	__cplusplus
   12.13  }
    13.1 --- a/src/chess/rules.c	Mon Mar 31 14:08:00 2014 +0200
    13.2 +++ b/src/chess/rules.c	Mon Mar 31 15:03:25 2014 +0200
    13.3 @@ -30,6 +30,30 @@
    13.4  #include "rules.h"
    13.5  #include "chess.h"
    13.6  #include <string.h>
    13.7 +#include <stdlib.h>
    13.8 +
    13.9 +void gamestate_cleanup(GameState *gamestate) {
   13.10 +    MoveList *elem;
   13.11 +    elem = gamestate->movelist;
   13.12 +    while (elem) {
   13.13 +        MoveList *cur = elem;
   13.14 +        elem = elem->next;
   13.15 +        free(cur);
   13.16 +    };
   13.17 +}
   13.18 +
   13.19 +static void addmove(GameState* gamestate, Move *move) {
   13.20 +    MoveList *elem = malloc(sizeof(MoveList));
   13.21 +    elem->next = NULL;
   13.22 +    elem->move = *move;
   13.23 +    
   13.24 +    if (gamestate->lastmove) {
   13.25 +        gamestate->lastmove->next = elem;
   13.26 +        gamestate->lastmove = elem;
   13.27 +    } else {
   13.28 +        gamestate->movelist = gamestate->lastmove = elem;
   13.29 +    }
   13.30 +}
   13.31  
   13.32  char getpiecechr(uint8_t piece) {
   13.33      switch (piece & PIECE_MASK) {
   13.34 @@ -53,41 +77,34 @@
   13.35      }
   13.36  }
   13.37  
   13.38 -/**
   13.39 - * Guesses the location of a piece for short algebraic notation.
   13.40 - * 
   13.41 - * @param board the current state of the board
   13.42 - * @param move the move date to operate on
   13.43 - * @return status code (see rules/rules.h for the codes)
   13.44 - */
   13.45 -static int getlocation(Board board, Move *move) {   
   13.46 +static int getlocation(GameState *gamestate, Move *move) {   
   13.47      uint8_t piece = move->piece & PIECE_MASK;
   13.48      switch (piece) {
   13.49 -        case PAWN: return pawn_getlocation(board, move);
   13.50 -        case ROOK: return rook_getlocation(board, move);
   13.51 -        case KNIGHT: return knight_getlocation(board, move);
   13.52 -        case BISHOP: return bishop_getlocation(board, move);
   13.53 -        case QUEEN: return queen_getlocation(board, move);
   13.54 -        case KING: return king_getlocation(board, move);
   13.55 +        case PAWN: return pawn_getlocation(gamestate, move);
   13.56 +        case ROOK: return rook_getlocation(gamestate, move);
   13.57 +        case KNIGHT: return knight_getlocation(gamestate, move);
   13.58 +        case BISHOP: return bishop_getlocation(gamestate, move);
   13.59 +        case QUEEN: return queen_getlocation(gamestate, move);
   13.60 +        case KING: return king_getlocation(gamestate, move);
   13.61          default: return INVALID_MOVE_SYNTAX;
   13.62      }
   13.63  }
   13.64  
   13.65  
   13.66 -void apply_move(Board board, Move *move) {
   13.67 +void apply_move(GameState *gamestate, Move *move) {
   13.68      uint8_t piece = move->piece & PIECE_MASK;
   13.69      uint8_t color = move->piece & COLOR_MASK;
   13.70      
   13.71      /* en passant capture */
   13.72      if (move->capture && piece == PAWN &&
   13.73 -        mdst(board, move) == 0) {
   13.74 -        board[move->fromrow][move->tofile] = 0;
   13.75 +        mdst(gamestate->board, move) == 0) {
   13.76 +        gamestate->board[move->fromrow][move->tofile] = 0;
   13.77      }
   13.78      
   13.79      /* remove old en passant threats */
   13.80      for (uint8_t file = 0 ; file < 8 ; file++) {
   13.81 -        board[3][file] &= ~ENPASSANT_THREAT;
   13.82 -        board[4][file] &= ~ENPASSANT_THREAT;
   13.83 +        gamestate->board[3][file] &= ~ENPASSANT_THREAT;
   13.84 +        gamestate->board[4][file] &= ~ENPASSANT_THREAT;
   13.85      }
   13.86      
   13.87      /* add new en passant threat */
   13.88 @@ -98,11 +115,11 @@
   13.89      }
   13.90      
   13.91      /* move (and maybe capture or promote) */
   13.92 -    msrc(board, move) = 0;
   13.93 +    msrc(gamestate->board, move) = 0;
   13.94      if (move->promotion) {
   13.95 -        mdst(board, move) = move->promotion;
   13.96 +        mdst(gamestate->board, move) = move->promotion;
   13.97      } else {
   13.98 -        mdst(board, move) = move->piece;
   13.99 +        mdst(gamestate->board, move) = move->piece;
  13.100      }
  13.101      
  13.102      /* castling */
  13.103 @@ -110,16 +127,18 @@
  13.104          move->fromfile == fileidx('e')) {
  13.105          
  13.106          if (move->tofile == fileidx('g')) {
  13.107 -            board[move->torow][fileidx('h')] = 0;
  13.108 -            board[move->torow][fileidx('f')] = color|ROOK;
  13.109 +            gamestate->board[move->torow][fileidx('h')] = 0;
  13.110 +            gamestate->board[move->torow][fileidx('f')] = color|ROOK;
  13.111          } else if (move->tofile == fileidx('c')) {
  13.112 -            board[move->torow][fileidx('a')] = 0;
  13.113 -            board[move->torow][fileidx('d')] = color|ROOK;
  13.114 +            gamestate->board[move->torow][fileidx('a')] = 0;
  13.115 +            gamestate->board[move->torow][fileidx('d')] = color|ROOK;
  13.116          }
  13.117      }
  13.118 +    
  13.119 +    addmove(gamestate, move);
  13.120  }
  13.121  
  13.122 -_Bool validate_move(Board board, Move *move) {
  13.123 +_Bool validate_move(GameState *gamestate, Move *move) {
  13.124      _Bool result;
  13.125      
  13.126      /* validate indices (don't trust opponent) */
  13.127 @@ -133,38 +152,39 @@
  13.128      }
  13.129      
  13.130      /* does piece exist */
  13.131 -    result = msrc(board, move) == move->piece;
  13.132 +    result = msrc(gamestate->board, move) == move->piece;
  13.133      
  13.134      /* can't capture own pieces */
  13.135 -    if ((mdst(board, move) & COLOR_MASK) == (move->piece & COLOR_MASK)) {
  13.136 +    if ((mdst(gamestate->board, move) & COLOR_MASK)
  13.137 +        == (move->piece & COLOR_MASK)) {
  13.138          return 0;
  13.139      }
  13.140      
  13.141      /* validate individual rules */
  13.142      switch (move->piece & PIECE_MASK) {
  13.143      case PAWN:
  13.144 -        result = result && pawn_chkrules(board, move);
  13.145 -        result = result && !pawn_isblocked(board, move);
  13.146 +        result = result && pawn_chkrules(gamestate, move);
  13.147 +        result = result && !pawn_isblocked(gamestate, move);
  13.148          break;
  13.149      case ROOK:
  13.150          result = result && rook_chkrules(move);
  13.151 -        result = result && !rook_isblocked(board, move);
  13.152 +        result = result && !rook_isblocked(gamestate, move);
  13.153          break;
  13.154      case KNIGHT:
  13.155          result = result && knight_chkrules(move);
  13.156 -        result = result && !knight_isblocked(board, move);
  13.157 +        result = result && !knight_isblocked(gamestate, move);
  13.158          break;
  13.159      case BISHOP:
  13.160          result = result && bishop_chkrules(move);
  13.161 -        result = result && !bishop_isblocked(board, move);
  13.162 +        result = result && !bishop_isblocked(gamestate, move);
  13.163          break;
  13.164      case QUEEN:
  13.165          result = result && queen_chkrules(move);
  13.166 -        result = result && !queen_isblocked(board, move);
  13.167 +        result = result && !queen_isblocked(gamestate, move);
  13.168          break;
  13.169      case KING:
  13.170 -        result = result && king_chkrules(board, move);
  13.171 -        result = result && !king_isblocked(board, move);
  13.172 +        result = result && king_chkrules(gamestate, move);
  13.173 +        result = result && !king_isblocked(gamestate, move);
  13.174          break;
  13.175      default:
  13.176          result = 0;
  13.177 @@ -179,7 +199,7 @@
  13.178      return result;
  13.179  }
  13.180  
  13.181 -int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move) {
  13.182 +int eval_move(GameState *gamestate, char *mstr, Move *move) {
  13.183      memset(move, 0, sizeof(Move));
  13.184      move->fromfile = POS_UNSPECIFIED;
  13.185      move->fromrow = POS_UNSPECIFIED;
  13.186 @@ -201,7 +221,7 @@
  13.187          if (!move->promotion) {
  13.188              return INVALID_MOVE_SYNTAX;
  13.189          } else {
  13.190 -            move->promotion |= mycolor;
  13.191 +            move->promotion |= gamestate->mycolor;
  13.192              len -= 2;
  13.193              mstr[len] = 0;
  13.194          }
  13.195 @@ -218,7 +238,7 @@
  13.196              move->piece = KING;
  13.197              move->fromfile = fileidx('e');
  13.198              move->tofile = fileidx('g');
  13.199 -            move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
  13.200 +            move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
  13.201          } else {
  13.202              /* move (e.g. "Nf3") */
  13.203              move->piece = getpiece(mstr[0]);
  13.204 @@ -254,7 +274,7 @@
  13.205              move->piece = KING;
  13.206              move->fromfile = fileidx('e');
  13.207              move->tofile = fileidx('c');
  13.208 -            move->fromrow = move->torow = mycolor == WHITE ? 0 : 7;
  13.209 +            move->fromrow = move->torow = gamestate->mycolor == WHITE ? 0 : 7;
  13.210          } else {
  13.211              move->piece = getpiece(mstr[0]);
  13.212              if (mstr[2] == 'x') {
  13.213 @@ -290,15 +310,16 @@
  13.214  
  13.215      
  13.216      if (move->piece) {
  13.217 -        if (move->piece == PAWN && move->torow == (mycolor==WHITE?7:0)
  13.218 +        if (move->piece == PAWN
  13.219 +            && move->torow == (gamestate->mycolor==WHITE?7:0)
  13.220              && !move->promotion) {
  13.221              return NEED_PROMOTION;
  13.222          }
  13.223          
  13.224 -        move->piece |= mycolor;
  13.225 +        move->piece |= gamestate->mycolor;
  13.226          if (move->fromfile == POS_UNSPECIFIED
  13.227              || move->fromrow == POS_UNSPECIFIED) {
  13.228 -            return getlocation(board, move);
  13.229 +            return getlocation(gamestate, move);
  13.230          } else {
  13.231              return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
  13.232          }
    14.1 --- a/src/chess/rules.h	Mon Mar 31 14:08:00 2014 +0200
    14.2 +++ b/src/chess/rules.h	Mon Mar 31 15:03:25 2014 +0200
    14.3 @@ -68,6 +68,7 @@
    14.4  
    14.5  typedef uint8_t Board[8][8];
    14.6  
    14.7 +
    14.8  typedef struct {
    14.9      uint8_t piece;
   14.10      uint8_t fromfile;
   14.11 @@ -80,6 +81,20 @@
   14.12      _Bool capture;
   14.13  } Move;
   14.14  
   14.15 +typedef struct MoveList MoveList;
   14.16 +
   14.17 +struct MoveList {
   14.18 +    Move move;
   14.19 +    MoveList* next;
   14.20 +};
   14.21 +
   14.22 +typedef struct {
   14.23 +    Board board;
   14.24 +    uint8_t mycolor;
   14.25 +    MoveList* movelist;
   14.26 +    MoveList* lastmove;
   14.27 +} GameState;
   14.28 +
   14.29  #define POS_UNSPECIFIED UINT8_MAX
   14.30  #define mdst(b,m) b[(m)->torow][(m)->tofile]
   14.31  #define msrc(b,m) b[(m)->fromrow][(m)->fromfile]
   14.32 @@ -102,6 +117,8 @@
   14.33  #define fileidx_s(c) (isfile(c)?fileidx(c):POS_UNSPECIFIED)
   14.34  #define rowidx_s(c) (isrow(c)?rowidx(c):POS_UNSPECIFIED)
   14.35  
   14.36 +void gamestate_cleanup(GameState *gamestate);
   14.37 +
   14.38  /**
   14.39   * Maps a character to a piece.
   14.40   * 
   14.41 @@ -126,29 +143,28 @@
   14.42   * Evaluates a move syntactically and stores the move data in the specified
   14.43   * object.
   14.44   * 
   14.45 - * @param board the current state of the board
   14.46 - * @param mycolor the color of the current player
   14.47 + * @param gamestate the current game state
   14.48   * @param mstr the input string to parse
   14.49   * @param move a pointer to object where the move data shall be stored
   14.50   * @return status code (see rules/rules.h for the list of codes)
   14.51   */
   14.52 -int eval_move(Board board, uint8_t mycolor, char *mstr, Move *move);
   14.53 +int eval_move(GameState *gamestate, char *mstr, Move *move);
   14.54  
   14.55  /**
   14.56   * Validates move by applying chess rules.
   14.57 - * @param board the current board state
   14.58 + * @param gamestate the current game state
   14.59   * @param move the move to validate
   14.60   * @return TRUE, if the move complies to chess rules, FALSE otherwise
   14.61   */
   14.62 -_Bool validate_move(Board board, Move *move);
   14.63 +_Bool validate_move(GameState *gamestate, Move *move);
   14.64  
   14.65  /**
   14.66   * Applies a move and deletes captured pieces.
   14.67   * 
   14.68 - * @param board the current board state
   14.69 + * @param gamestate the current game state
   14.70   * @param move the move to apply
   14.71   */
   14.72 -void apply_move(Board board, Move *move);
   14.73 +void apply_move(GameState *gamestate, Move *move);
   14.74  
   14.75  #endif	/* RULES_H */
   14.76  
    15.1 --- a/src/game.c	Mon Mar 31 14:08:00 2014 +0200
    15.2 +++ b/src/game.c	Mon Mar 31 15:03:25 2014 +0200
    15.3 @@ -35,12 +35,12 @@
    15.4  
    15.5  static const uint8_t boardx = 10, boardy = 10;
    15.6  
    15.7 -static void draw_board(Board board, MoveListRoot *movelist, uint8_t mycolor) {
    15.8 +static void draw_board(GameState *gamestate) {
    15.9      
   15.10      for (uint8_t y = 0 ; y < 8 ; y++) {
   15.11          for (uint8_t x = 0 ; x < 8 ; x++) {
   15.12 -            uint8_t col = board[y][x] & COLOR_MASK;
   15.13 -            uint8_t piece = board[y][x] & PIECE_MASK;
   15.14 +            uint8_t col = gamestate->board[y][x] & COLOR_MASK;
   15.15 +            uint8_t piece = gamestate->board[y][x] & PIECE_MASK;
   15.16              char piecec;
   15.17              if (piece) {
   15.18                  piecec = piece == PAWN ? 'P' : getpiecechr(piece);
   15.19 @@ -51,8 +51,8 @@
   15.20              attrset((col == WHITE ? A_BOLD : A_DIM) |
   15.21                  COLOR_PAIR((y&1)==(x&1) ? COL_WB : COL_BW));
   15.22              
   15.23 -            int cy = mycolor == WHITE ? boardy-y : boardy-7+y;
   15.24 -            int cx = mycolor == WHITE ? boardx+x*3 : boardx+21-x*3;
   15.25 +            int cy = gamestate->mycolor == WHITE ? boardy-y : boardy-7+y;
   15.26 +            int cx = gamestate->mycolor == WHITE ? boardx+x*3 : boardx+21-x*3;
   15.27              mvaddch(cy, cx, ' ');
   15.28              mvaddch(cy, cx+1, piecec);
   15.29              mvaddch(cy, cx+2, ' ');
   15.30 @@ -61,8 +61,8 @@
   15.31      
   15.32      attrset(A_NORMAL);
   15.33      for (uint8_t i = 0 ; i < 8 ; i++) {
   15.34 -        int x = mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3;
   15.35 -        int y = mycolor == WHITE ? boardy-i : boardy-7+i;
   15.36 +        int x = gamestate->mycolor == WHITE ? boardx+i*3+1 : boardx+22-i*3;
   15.37 +        int y = gamestate->mycolor == WHITE ? boardy-i : boardy-7+i;
   15.38          mvaddch(boardy+1, x, 'a'+i);
   15.39          mvaddch(y, boardx-2, '1'+i);
   15.40      }
   15.41 @@ -72,14 +72,14 @@
   15.42      uint8_t logy = 0;
   15.43      const uint8_t logx = boardx + 30;
   15.44      int logi = 1;
   15.45 -    MoveList *logelem = movelist->first;
   15.46 +    MoveList *logelem = gamestate->movelist;
   15.47      
   15.48      while (logelem) {
   15.49          logi++;
   15.50          if (logi % 2 == 0) {
   15.51              if ((logi - 2) % 4 == 0) {
   15.52                  logy++;
   15.53 -                wmove(tchess_window, logy, logx);
   15.54 +                move(logy, logx);
   15.55              }
   15.56              printw("%d. ", logi / 2);
   15.57          }
   15.58 @@ -108,15 +108,14 @@
   15.59  }
   15.60  
   15.61  
   15.62 -static int sendmove(Board board, MoveListRoot *movelist,
   15.63 -    uint8_t mycolor, int opponent) {
   15.64 +static int sendmove(GameState *gamestate, int opponent) {
   15.65      
   15.66      const size_t buflen = 8;
   15.67      char movestr[buflen];
   15.68      _Bool remisrejected = FALSE;
   15.69      uint8_t code;
   15.70      
   15.71 -    int inputy = getmaxy(tchess_window) - 6;
   15.72 +    int inputy = getmaxy(stdscr) - 6;
   15.73      while (1) {
   15.74          move(inputy, 0);
   15.75          if (remisrejected) {
   15.76 @@ -156,7 +155,7 @@
   15.77              }
   15.78          } else {
   15.79              Move move;
   15.80 -            int eval_result = eval_move(board, mycolor, movestr, &move);
   15.81 +            int eval_result = eval_move(gamestate, movestr, &move);
   15.82              switch (eval_result) {
   15.83              case VALID_MOVE_SYNTAX:
   15.84                  net_send_data(opponent, NETCODE_MOVE, &move, sizeof(Move));
   15.85 @@ -166,8 +165,7 @@
   15.86                  if (code == NETCODE_DECLINE) {
   15.87                      printw("Invalid move.");
   15.88                  } else {
   15.89 -                    apply_move(board, &move);
   15.90 -                    addmove(movelist, &move);
   15.91 +                    apply_move(gamestate, &move);
   15.92                      if (move.checkmate) {
   15.93                          printw("Checkmate!");
   15.94                          clrtoeol();
   15.95 @@ -194,9 +192,9 @@
   15.96      }
   15.97  }
   15.98  
   15.99 -static int recvmove(Board board, MoveListRoot *movelist, int opponent) {
  15.100 +static int recvmove(GameState *gamestate, int opponent) {
  15.101      
  15.102 -    int inputy = getmaxy(tchess_window) - 6;
  15.103 +    int inputy = getmaxy(stdscr) - 6;
  15.104      while (1) {
  15.105          move(inputy, 0);
  15.106          printw("Awaiting opponent move...");
  15.107 @@ -225,9 +223,8 @@
  15.108                  break;
  15.109              case NETCODE_MOVE:
  15.110                  net_recieve_data(opponent, &move, sizeof(Move));
  15.111 -                if (validate_move(board, &move)) {
  15.112 -                    apply_move(board, &move);
  15.113 -                    addmove(movelist, &move);
  15.114 +                if (validate_move(gamestate, &move)) {
  15.115 +                    apply_move(gamestate, &move);
  15.116                      if (move.check) {
  15.117                          net_send_code(opponent, NETCODE_CHECK);
  15.118                      } else if (move.checkmate) {
  15.119 @@ -243,40 +240,12 @@
  15.120      }
  15.121  }
  15.122  
  15.123 -void freemovelist(MoveListRoot* list) {
  15.124 -    MoveList *elem;
  15.125 -    elem = list->first;
  15.126 -    while (elem) {
  15.127 -        MoveList *cur = elem;
  15.128 -        elem = elem->next;
  15.129 -        free(cur);
  15.130 -    };
  15.131 -    free(list);
  15.132 -}
  15.133 -
  15.134 -void addmove(MoveListRoot* list, Move *move) {
  15.135 -    MoveList *elem = malloc(sizeof(MoveList));
  15.136 -    elem->next = NULL;
  15.137 -    elem->move = *move;
  15.138 -    
  15.139 -    if (list->last) {
  15.140 -        list->last->next = elem;
  15.141 -        list->last = elem;
  15.142 -    } else {
  15.143 -        list->first = list->last = elem;
  15.144 -    }
  15.145 -}
  15.146 -
  15.147  void game_start(Settings *settings, int opponent) {
  15.148      _Bool myturn = is_server(settings) ==
  15.149          (settings->gameinfo.servercolor == WHITE);
  15.150 -    uint8_t mycolor = myturn ? WHITE:BLACK;
  15.151      
  15.152 -    _Bool running;
  15.153 -    
  15.154 -    MoveListRoot* movelist = calloc(1, sizeof(MoveListRoot));
  15.155 -    
  15.156 -    Board board = {
  15.157 +    GameState gamestate;
  15.158 +    Board initboard = {
  15.159          {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
  15.160          {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
  15.161          {0,     0,       0,       0,      0,     0,       0,       0},
  15.162 @@ -286,22 +255,26 @@
  15.163          {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
  15.164          {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
  15.165      };
  15.166 +    memcpy(gamestate.board, initboard, sizeof(Board));
  15.167 +    gamestate.mycolor = myturn ? WHITE:BLACK;
  15.168 +    gamestate.movelist = gamestate.lastmove = NULL;
  15.169      
  15.170 +    _Bool running;
  15.171      do {
  15.172          clear();
  15.173 -        draw_board(board, movelist, mycolor);
  15.174 +        draw_board(&gamestate);
  15.175          if (myturn) {
  15.176 -            running = !sendmove(board, movelist, mycolor, opponent);
  15.177 +            running = !sendmove(&gamestate, opponent);
  15.178          } else {
  15.179 -            running = !recvmove(board, movelist, opponent);
  15.180 +            running = !recvmove(&gamestate, opponent);
  15.181              flushinp(); // flush any input the user hacked in while waiting
  15.182          }
  15.183          myturn ^= TRUE;
  15.184      }  while (running);
  15.185      
  15.186 -    freemovelist(movelist);
  15.187 +    gamestate_cleanup(&gamestate);
  15.188      
  15.189 -    mvaddstr(getmaxy(tchess_window)-1, 0,
  15.190 +    mvaddstr(getmaxy(stdscr)-1, 0,
  15.191          "Game has ended. Press any key to leave...");
  15.192      getch();
  15.193  }
    16.1 --- a/src/game.h	Mon Mar 31 14:08:00 2014 +0200
    16.2 +++ b/src/game.h	Mon Mar 31 15:03:25 2014 +0200
    16.3 @@ -37,25 +37,8 @@
    16.4  extern "C" {
    16.5  #endif
    16.6  
    16.7 -typedef struct MoveList MoveList;
    16.8 -typedef struct MoveListRoot MoveListRoot;
    16.9 -
   16.10 -struct MoveListRoot {
   16.11 -    MoveList* first;
   16.12 -    MoveList* last;
   16.13 -};
   16.14 -
   16.15 -struct MoveList {
   16.16 -    Move move;
   16.17 -    MoveList* next;
   16.18 -};
   16.19 -
   16.20 -
   16.21  void game_start(Settings *settings, int opponent);
   16.22  
   16.23 -void freemovelist(MoveListRoot* list);
   16.24 -void addmove(MoveListRoot *movelist, Move *move);
   16.25 -
   16.26  #ifdef	__cplusplus
   16.27  }
   16.28  #endif
    17.1 --- a/src/main.c	Mon Mar 31 14:08:00 2014 +0200
    17.2 +++ b/src/main.c	Mon Mar 31 15:03:25 2014 +0200
    17.3 @@ -160,7 +160,7 @@
    17.4          );
    17.5          return EXIT_SUCCESS;
    17.6      }    
    17.7 -    tchess_window = initscr();
    17.8 +    initscr();
    17.9      cbreak();
   17.10      if (has_colors()) {
   17.11          start_color();
    18.1 --- a/src/terminal-chess.h	Mon Mar 31 14:08:00 2014 +0200
    18.2 +++ b/src/terminal-chess.h	Mon Mar 31 15:03:25 2014 +0200
    18.3 @@ -39,8 +39,6 @@
    18.4  extern "C" {
    18.5  #endif
    18.6  
    18.7 -WINDOW* tchess_window;
    18.8 -
    18.9  #define TIME_MAX UINT16_MAX
   18.10      
   18.11  typedef struct {

mercurial