diff --git a/chess.c b/chess.c index 9e6a3c3..63d206c 100644 --- a/chess.c +++ b/chess.c @@ -1,72 +1,73 @@ #include /* isalpha, isdigit ... */ #include /* setlocale */ -#include /* memcpy */ -#include /* printf, scanf */ -#include /* int32_t */ #include /* true, false */ +#include /* int32_t */ +#include /* printf, scanf */ +#include /* memcpy */ typedef int32_t tile_t; typedef ssize_t pos_t; -#define ROW ( (pos_t) 8 ) -#define COL ( (pos_t) 1 ) +#define ROW ((pos_t)8) +#define COL ((pos_t)1) -#define BOARD_SIZE ( 8*8*sizeof(tile_t) ) +#define BOARD_SIZE (8 * 8 * sizeof(tile_t)) -#define E ( (tile_t) 0 ) /* empty */ -#define K ( (tile_t) 1 ) /* king */ -#define Q ( (tile_t) 2 ) /* queen */ -#define R ( (tile_t) 3 ) /* rook */ -#define B ( (tile_t) 4 ) /* bishop */ -#define N ( (tile_t) 5 ) /* knight */ -#define P ( (tile_t) 6 ) /* pawn */ +#define E ((tile_t)0) /* empty */ +#define K ((tile_t)1) /* king */ +#define Q ((tile_t)2) /* queen */ +#define R ((tile_t)3) /* rook */ +#define B ((tile_t)4) /* bishop */ +#define N ((tile_t)5) /* knight */ +#define P ((tile_t)6) /* pawn */ #define BG_DARKBLUE() setcolor(0, 100, 100, 150) #define BG_LIGHTBLUE() setcolor(0, 150, 150, 200) #define FG_BLACK() setcolor(1, 0, 0, 0) #define FG_WHITE() setcolor(1, 0xff, 0xff, 0xff) -#define WHITE 1 +#define WHITE 1 #define BLACK -1 #define UNICODE_CHESS_SYMBOL 0x2659 -bool bishop_move_ok(tile_t const* board, pos_t from, pos_t to); -bool cardinal_move_ok(tile_t const *board, pos_t from, pos_t to); -bool diagonal_move_ok(tile_t const *board, pos_t from, pos_t to); -bool king_move_ok(tile_t const *board, pos_t from, pos_t to); +bool bishop_move_ok(const tile_t *board, pos_t from, pos_t to); +bool cardinal_move_ok(const tile_t *board, pos_t from, pos_t to); +bool diagonal_move_ok(const tile_t *board, pos_t from, pos_t to); +bool king_move_ok(const tile_t *board, pos_t from, pos_t to); bool knight_move_ok(pos_t from, pos_t to); -bool move_ok(tile_t* board, pos_t from, pos_t to, int player); -bool pawn_move_ok(tile_t const* board, pos_t from, pos_t to, int direction); -bool queen_move_ok(tile_t const *board, pos_t from, pos_t to); -bool rook_move_ok(tile_t const *board, pos_t from, pos_t to); +bool move_ok(tile_t *board, pos_t from, pos_t to, int player); +bool pawn_move_ok(const tile_t *board, pos_t from, pos_t to, int direction); +bool queen_move_ok(const tile_t *board, pos_t from, pos_t to); +bool rook_move_ok(const tile_t *board, pos_t from, pos_t to); bool tile_empty(tile_t t); -int get_piece(char* input); +int get_piece(char *input); pos_t abs_pos(pos_t p); pos_t column(pos_t t); pos_t row(pos_t t); tile_t abs_tile(tile_t t); void do_turn(int turn_no, tile_t *board); -void init_board(tile_t* board); -void print_board(tile_t* board); +void init_board(tile_t *board); +void print_board(tile_t *board); void setcolor(int mode, int r, int g, int b); -int main(){ - int turn = 0; +int main() +{ + int turn = 0; - setlocale(LC_ALL, "C.UTF-8"); + setlocale(LC_ALL, "C.UTF-8"); - tile_t board[8*8] = { 0 }; + tile_t board[8 * 8] = { 0 }; - init_board(board); + init_board(board); - while(1) { - print_board(board); - do_turn(turn++, board); - } + while (1) { + print_board(board); + do_turn(turn++, board); + } - return 0; + return 0; } /* @@ -76,240 +77,228 @@ int main(){ 1: change foreground 2: reset colors */ -void setcolor(const int mode, const int r, const int g, const int b){ - if( mode == 2 ) - printf("\033[0m"); - else - printf("\033[%i;2;%i;%i;%im", mode?38:48, r, g, b); +void setcolor(const int mode, const int r, const int g, const int b) +{ + if (mode == 2) + printf("\033[0m"); + else + printf("\033[%i;2;%i;%i;%im", mode ? 38 : 48, r, g, b); }; /* Prints the board */ -void print_board(tile_t* board){ - /* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode +void print_board(tile_t *board) +{ + /* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode - The unicode symbol is calculated from adding 0x2653 with the - piece value. */ + The unicode symbol is calculated from adding 0x2653 with the + piece value. */ - for (size_t i=0; i<8; i++) { - printf("\n %zu ", 8-i); // print number coordinates on y-axis + for (size_t i = 0; i < 8; i++) { + printf("\n %zu ", 8 - i); // print number coordinates on y-axis - for (size_t j=0; j<8; j++) { - tile_t p = board[i*8+j]; - - // Make tile dark and light - if ((i+j) % 2) - BG_DARKBLUE(); - else - BG_LIGHTBLUE(); + for (size_t j = 0; j < 8; j++) { + tile_t p = board[i * 8 + j]; - // Print empty space and do nothing if tile is empty - if (tile_empty(p)) { - printf(" "); - continue; - } + // Make tile dark and light + if ((i + j) % 2) + BG_DARKBLUE(); + else + BG_LIGHTBLUE(); - // Set piece color - if (p > 0) - FG_WHITE(); - else - FG_BLACK(); - - printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(p)); - } + // Print empty space and do nothing if tile is empty + if (tile_empty(p)) { + printf(" "); + continue; + } - setcolor(2, 0, 0, 0); // reset text attributes - } - - // Print horizontal letter coordinates - printf("\n "); + // Set piece color + if (p > 0) + FG_WHITE(); + else + FG_BLACK(); - for(int i=0; i<8; i++) - printf(" %c", 'a'+i); + printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(p)); + } + + setcolor(2, 0, 0, 0); // reset text attributes + } + + // Print horizontal letter coordinates + printf("\n "); + + for (int i = 0; i < 8; i++) + printf(" %c", 'a' + i); } - /* * Resets/inits the board */ void init_board(tile_t *board) { + // black pieces are prefixed by a minus (-) + const tile_t start[] + = { -R, -N, -B, -Q, -K, -B, -N, -R, -P, -P, -P, -P, -P, -P, -P, -P, + E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, + E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, + P, P, P, P, P, P, P, P, R, N, B, Q, K, B, N, R }; - // black pieces are prefixed by a minus (-) - const tile_t start[] = { - -R,-N,-B,-Q,-K,-B,-N,-R, - -P,-P,-P,-P,-P,-P,-P,-P, - E, E, E, E, E, E, E, E, - E, E, E, E, E, E, E, E, - E, E, E, E, E, E, E, E, - E, E, E, E, E, E, E, E, - P, P, P, P, P, P, P, P, - R, N, B, Q, K, B, N, R - }; - - memcpy(board, start, sizeof(start)); + memcpy(board, start, sizeof(start)); } - -// TODO: Implement algebaric notation +// TODO: Implement algebaric notation /* Get move, check move and log move for turn */ void do_turn(int turn_no, tile_t *board) { - char input[3] = { 0 }; + char input[3] = { 0 }; - int from = -1, - to = -1, - tmp; + int from = -1, to = -1, tmp; - printf("\nPlayer %i, your turn to move", 1 + turn_no%2); - - /* temporary and ugly solution - read from and to */ - while (from == -1 || to == -1) { - from = -1; - to = -1; + printf("\nPlayer %i, your turn to move", 1 + turn_no % 2); - printf("\nMove piece\nfrom: "); - scanf(" %2s", input); + /* temporary and ugly solution - read from and to */ + while (from == -1 || to == -1) { + from = -1; + to = -1; - tmp = get_piece(input); + printf("\nMove piece\nfrom: "); + scanf(" %2s", input); - if (tmp == -1) - continue; + tmp = get_piece(input); - from = tmp; - - printf("\nto: "); - scanf(" %2s", input); - tmp = get_piece(input); + if (tmp == -1) + continue; - if (tmp == -1) - continue; + from = tmp; - to = tmp; + printf("\nto: "); + scanf(" %2s", input); + tmp = get_piece(input); - if (!move_ok(board, from, to, turn_no % 2 ? BLACK : WHITE )) { - from = -1; - continue; - } - } + if (tmp == -1) + continue; - board[to] = board[from]; - board[from] = E; + to = tmp; + + if (! move_ok(board, from, to, turn_no % 2 ? BLACK : WHITE)) { + from = -1; + continue; + } + } + + board[to] = board[from]; + board[from] = E; } - /* Translates A1, 3B etc. to the 1D index of the board */ int get_piece(char *input) { - int x = -1, - y = -1, - c; + int x = -1, y = -1, c; - for (int i=0; i<2; i++) { - c = input[i]; + for (int i = 0; i < 2; i++) { + c = input[i]; - if (isalpha(c)) - c = toupper(input[0]); + if (isalpha(c)) + c = toupper(input[0]); - if( 'A' <= c && c <= 'H' ) - x = c - 'A'; - else if('1' <= c && c <= '8') - y = c - '1'; - } + if ('A' <= c && c <= 'H') + x = c - 'A'; + else if ('1' <= c && c <= '8') + y = c - '1'; + } - if (x != -1 && y != -1) - return 8*(7-y) + x; - else - return -1; + if (x != -1 && y != -1) + return 8 * (7 - y) + x; + else + return -1; } pos_t abs_pos(pos_t p) { - if(p < 0) - return -1 * p; + if (p < 0) + return -1 * p; - return p; + return p; } tile_t abs_tile(tile_t t) { - if(t < 0) - return -1 * t; + if (t < 0) + return -1 * t; - return t; + return t; } /* Returns true if tile is empty */ bool tile_empty(tile_t t) { - return t == E; + return t == E; } /* Returns row number of board index */ pos_t row(pos_t t) { - return t / ROW; + return t / ROW; } /* Returns column number of board index */ pos_t column(pos_t t) { - return t % ROW; + return t % ROW; } /* Returns true if a and b are tiles of opposite player */ bool opposite_color(tile_t a, tile_t b) { - return a*b < 0; + return a * b < 0; } /* Returns true if a and b are pieces of the same color */ bool same_color(tile_t a, tile_t b) { - return a*b > 0; + return a * b > 0; } /* Returns true if a move is valid, false otherwise */ -bool move_ok(tile_t* board, pos_t from, pos_t to, int const player) +bool move_ok(tile_t *board, pos_t from, pos_t to, const int player) { - /* player must own piece it moves */ - if (board[from] * player < 0) { - printf("\nYou do not own this piece"); - return false; - } + /* player must own piece it moves */ + if (board[from] * player < 0) { + printf("\nYou do not own this piece"); + return false; + } - /* player can't take own pieces or move piece onto itself*/ - if (same_color(board[from], board[to])) { - printf("\nYou can't take your own pieces"); - return false; - } + /* player can't take own pieces or move piece onto itself*/ + if (same_color(board[from], board[to])) { + printf("\nYou can't take your own pieces"); + return false; + } - /* check piece specific moves */ - switch (abs_tile(board[from])) { + /* check piece specific moves */ + switch (abs_tile(board[from])) { + /* PAWNS */ + case P: + return pawn_move_ok(board, from, to, player); - /* PAWNS */ - case P: - return pawn_move_ok(board, from, to, player); - - /* BISHOPS */ - case B: - return bishop_move_ok(board, from, to); - - /* ROOKS */ - case R: - return rook_move_ok(board, from, to); + /* BISHOPS */ + case B: + return bishop_move_ok(board, from, to); - /* KNIGHTS */ - case N: - return knight_move_ok(from, to); - - case K: - return king_move_ok(board, from, to); - - case Q: - return queen_move_ok(board, from, to); - } + /* ROOKS */ + case R: + return rook_move_ok(board, from, to); - return false; + /* KNIGHTS */ + case N: + return knight_move_ok(from, to); + + case K: + return king_move_ok(board, from, to); + + case Q: + return queen_move_ok(board, from, to); + } + + return false; } /* Returns true if move is a valid pawn move @@ -317,102 +306,101 @@ bool move_ok(tile_t* board, pos_t from, pos_t to, int const player) from - index of board piece starts at to - index of board piece wants to move to direction - pawns movement direction */ -bool pawn_move_ok(tile_t const* board, pos_t from, pos_t to, int direction) +bool pawn_move_ok(const tile_t *board, pos_t from, pos_t to, int direction) { - pos_t const diff = (to - from) * -direction; + const pos_t diff = (to - from) * -direction; - switch (diff) { - default: - return false; + switch (diff) { + default: + return false; - case ROW: /* single move */ - return tile_empty(board[to]); + case ROW: /* single move */ + return tile_empty(board[to]); - case ROW - 1: case ROW+1: /* diagonal attack */ - return opposite_color(board[to], board[from]); + case ROW - 1: + case ROW + 1: /* diagonal attack */ + return opposite_color(board[to], board[from]); - case 2 * ROW: /* double move */ - return tile_empty(board[to]) - && tile_empty(board[from - ROW * direction]) - && (row(from) == 1 || row(from) == 6 ); - } + case 2 * ROW: /* double move */ + return tile_empty(board[to]) + && tile_empty(board[from - ROW * direction]) + && (row(from) == 1 || row(from) == 6); + } } /* Returns true if `to` is on a diagonal line of `from` board - array of tiles representing chess board state from - index of board piece is at to - index of board piece tries to move to */ -bool diagonal_move_ok(tile_t const *board, pos_t from, pos_t to) +bool diagonal_move_ok(const tile_t *board, pos_t from, pos_t to) { - pos_t const col_diff = column(to) - column(from); - pos_t const row_diff = row(to) - row(from); + const pos_t col_diff = column(to) - column(from); + const pos_t row_diff = row(to) - row(from); - pos_t const x_step = col_diff / abs_pos(col_diff); - pos_t const y_step = ROW * row_diff / abs_pos(row_diff); - pos_t const step = x_step + y_step; - - if ( abs_pos(col_diff) != abs_pos(row_diff) ) { - printf("\nnot a diagonal move"); - return false; - } + const pos_t x_step = col_diff / abs_pos(col_diff); + const pos_t y_step = ROW * row_diff / abs_pos(row_diff); + const pos_t step = x_step + y_step; - for (pos_t p = from + step; p != to; p += step) { - if (!tile_empty(board[p])) { - printf("\ncan't jump over pieces"); - return false; - } - } + if (abs_pos(col_diff) != abs_pos(row_diff)) { + printf("\nnot a diagonal move"); + return false; + } - return true; + for (pos_t p = from + step; p != to; p += step) { + if (! tile_empty(board[p])) { + printf("\ncan't jump over pieces"); + return false; + } + } + + return true; } /* Returns true if `to` is in a cardinal line of `from` board - array of tiles representing chess board state from - index of board piece is at to - index of board piece tries to move to */ -bool cardinal_move_ok(tile_t const *board, pos_t from, pos_t to) +bool cardinal_move_ok(const tile_t *board, pos_t from, pos_t to) { - pos_t const col_diff = column(to) - column(from); - pos_t const row_diff = row(to) - row(from); + const pos_t col_diff = column(to) - column(from); + const pos_t row_diff = row(to) - row(from); - if (row_diff > 0 && col_diff > 0) { - printf("Must move in a straight line"); - } + if (row_diff > 0 && col_diff > 0) + printf("Must move in a straight line"); - pos_t step; + pos_t step; - if (row_diff) { - step = ROW * row_diff / abs_pos(row_diff); - } else { - step = col_diff / abs_pos(col_diff); - } + if (row_diff) + step = ROW * row_diff / abs_pos(row_diff); + else + step = col_diff / abs_pos(col_diff); - for (pos_t p = from + step; p != to; p += step) { - if (!tile_empty(board[p])) { - printf("\ncan't jump over pieces"); - return false; - } - } + for (pos_t p = from + step; p != to; p += step) { + if (! tile_empty(board[p])) { + printf("\ncan't jump over pieces"); + return false; + } + } - return true; + return true; } /* Returns true if move is a valid bishop move board - array of tiles representing chess board state from - index of board bishop is at to - index of board bishop wants to move to */ -bool bishop_move_ok(tile_t const* board, pos_t from, pos_t to) +bool bishop_move_ok(const tile_t *board, pos_t from, pos_t to) { - return diagonal_move_ok(board, from, to); + return diagonal_move_ok(board, from, to); } /* Returns true if move is a valid rook move board - array of tiles representing chess board state from - index of board rook is at to - index of board rook wants to move to */ -bool rook_move_ok(tile_t const *board, pos_t from, pos_t to) +bool rook_move_ok(const tile_t *board, pos_t from, pos_t to) { - return cardinal_move_ok(board, from, to); + return cardinal_move_ok(board, from, to); } /* Returns true if move is a valid knight move @@ -421,34 +409,33 @@ bool rook_move_ok(tile_t const *board, pos_t from, pos_t to) to - index of board knight wants to move to */ bool knight_move_ok(pos_t from, pos_t to) { - pos_t const abs_col_diff = abs_pos(column(to) - column(from)); - pos_t const abs_row_diff = abs_pos(row(to) - row(from)); + const pos_t abs_col_diff = abs_pos(column(to) - column(from)); + const pos_t abs_row_diff = abs_pos(row(to) - row(from)); - return (abs_col_diff == 1 && abs_row_diff == 2) - || (abs_col_diff == 2 && abs_row_diff == 1); + return (abs_col_diff == 1 && abs_row_diff == 2) + || (abs_col_diff == 2 && abs_row_diff == 1); } /* Returns true if move is a valid king move board - array of tiles representing chess board state from - index of board king is at to - index of board king wants to move to */ -bool king_move_ok(tile_t const *board, pos_t from, pos_t to) +bool king_move_ok(const tile_t *board, pos_t from, pos_t to) { - pos_t const abs_col_diff = abs_pos(column(to) - column(from)); - pos_t const abs_row_diff = abs_pos(row(to) - row(from)); + const pos_t abs_col_diff = abs_pos(column(to) - column(from)); + const pos_t abs_row_diff = abs_pos(row(to) - row(from)); - (void)board; - - return abs_col_diff <= 1 - && abs_row_diff <= 1; + (void)board; + + return abs_col_diff <= 1 && abs_row_diff <= 1; } /* Returns true if move is a valid queen move board - array of tiles representing chess board state from - index of board queen is at to - index of board queen wants to move to */ -bool queen_move_ok(tile_t const *board, pos_t from, pos_t to) +bool queen_move_ok(const tile_t *board, pos_t from, pos_t to) { - return diagonal_move_ok(board, from, to) - || cardinal_move_ok(board, from, to); + return diagonal_move_ok(board, from, to) + || cardinal_move_ok(board, from, to); }