From f18c9215e5ea359c1864a0a5633e2b36e118e42f Mon Sep 17 00:00:00 2001 From: Ole Morud Date: Wed, 22 Mar 2023 20:35:43 +0100 Subject: [PATCH] WIP refactor --- .gitignore | 2 +- Makefile | 5 +- chess.c | 435 +---------------------------------------------------- common.c | 0 common.h | 26 ++++ graphics.c | 92 +++++++++++ graphics.h | 8 + pieces.c | 221 +++++++++++++++++++++++++++ pieces.h | 13 ++ util.c | 82 ++++++++++ util.h | 10 ++ 11 files changed, 464 insertions(+), 430 deletions(-) create mode 100644 common.c create mode 100644 common.h create mode 100644 graphics.c create mode 100644 graphics.h create mode 100644 pieces.c create mode 100644 pieces.h create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore index 54ed8d8..0794ce2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ chess -doc/ +docs/ diff --git a/Makefile b/Makefile index 0c553ed..fc844c7 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,13 @@ CC = clang CFLAGS = -Ofast -fsanitize=address -static-libsan -ggdb3 -Wall -Wextra -Werror -.PHONY: all run gdb clean +.PHONY: all run gdb clean docs all: bin/chess +docs: + doxygen doxygen-config + clean: rm bin/* diff --git a/chess.c b/chess.c index 18ae7ab..f8c1a1c 100644 --- a/chess.c +++ b/chess.c @@ -1,73 +1,16 @@ #include /* isalpha, isdigit ... */ #include /* setlocale */ -#include /* true, false */ -#include /* int32_t */ #include /* printf, scanf */ #include /* memcpy */ -/** Type representing piece/tile on a chessboard */ -typedef int32_t tile_t; +#include "common.h" +#include "graphics.h" +#include "pieces.h" -/** Type representing index of a chessboard tile */ -typedef ssize_t index_t; - -#define ROW ((index_t)8) -#define COL ((index_t)1) - -#define BOARD_SIZE ((index_t)(8 * 8)) - -#define E ((tile_t)0) ///< empty tile -#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 - -/** Set background to dark blue */ -#define BG_DARKBLUE() setcolor(0, 100, 100, 150) - -/** Set background to light blue */ -#define BG_LIGHTBLUE() setcolor(0, 150, 150, 200) - -/** Set foreground to black */ -#define FG_BLACK() setcolor(1, 0, 0, 0) - -/** Set foreground to white */ -#define FG_WHITE() setcolor(1, 0xff, 0xff, 0xff) - -#define WHITE 1 -#define BLACK -1 - -/** 0x2659 == ♙ */ -#define UNICODE_CHESS_SYMBOL 0x2659 - -bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool cardinal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool diagonal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool king_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool knight_move_ok(index_t from, index_t to); -bool move_ok(const tile_t board[BOARD_SIZE], - index_t from, - index_t to, - int player); -bool pawn_move_ok(const tile_t board[BOARD_SIZE], - index_t from, - index_t to, - int player); -bool queen_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool rook_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); -bool tile_empty(tile_t t); -index_t abs_pos(index_t p); -index_t column(index_t i); -index_t row(index_t i); -index_t get_piece(char input[2]); -tile_t abs_tile(tile_t t); void do_turn(int turn_no, tile_t board[BOARD_SIZE]); void init_board(tile_t board[BOARD_SIZE]); -void print_board(const tile_t board[BOARD_SIZE]); -void setcolor(int mode, int r, int g, int b); +index_t input_to_index(char input[2]); int main() { @@ -89,75 +32,6 @@ int main() return 0; } -/** - * Sets the foreground or background color for subsequent writes. - * - * Uses Select Graphic Renditions (SGR) to set the color of the terminal output. - * See https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit for more details. - * - * \param mode 0 - change background, 1 - change foreground, 2 - reset colors - * \param r amount of red (0 to 255) - * \param b amount of blue (0 to 255) - * \param g amount of green (0 to 255) - */ -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 - * - * Uses unicode symbols and ANSI escape features to print a chessboard on the - * display. - * - * \param board A pointer to a list of tiles representing the board state - * - * */ -void print_board(const tile_t board[BOARD_SIZE]) -{ - /* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode - - The unicode symbols for the pieces are calculated from adding - 0x2653 (#define'd as UNICODE_CHESS_SYMBOL) with the piece value. */ - - for (size_t i = 0; i < 8; i++) { - printf("\n %zu ", 8 - i); // number coordinates - - for (size_t j = 0; j < 8; j++) { - tile_t t = board[i * 8 + j]; - - if ((i + j) % 2) - BG_DARKBLUE(); - else - BG_LIGHTBLUE(); - - if (tile_empty(t)) { - printf(" "); - continue; - } - - if (t > 0) - FG_WHITE(); - else - FG_BLACK(); - - printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(t)); - } - - setcolor(2, 0, 0, 0); // reset text attributes - } - - /* horizontal letter coordinates */ - printf("\n "); - - for (int i = 0; i < 8; i++) - printf(" %c", 'a' + i); -} - /** * Resets/initializes the board * @@ -199,7 +73,7 @@ void do_turn(int turn_no, tile_t board[BOARD_SIZE]) printf("\nMove piece\nfrom: "); scanf(" %2s", input); - tmp = get_piece(input); + tmp = input_to_index(input); if (tmp == -1) continue; @@ -208,7 +82,7 @@ void do_turn(int turn_no, tile_t board[BOARD_SIZE]) printf("\nto: "); scanf(" %2s", input); - tmp = get_piece(input); + tmp = input_to_index(input); if (tmp == -1) continue; @@ -231,7 +105,7 @@ void do_turn(int turn_no, tile_t board[BOARD_SIZE]) * \param input string of length 2 representing tile, e.g. "A3" * * */ -index_t get_piece(char input[2]) +index_t input_to_index(char input[2]) { int x = -1, y = -1, c; @@ -253,298 +127,3 @@ index_t get_piece(char input[2]) return -1; } -/** - * Returns the absolute value of an index_t value - * - * \param p positive or negative index_t - */ -index_t abs_pos(index_t p) -{ - if (p < 0) - return -1 * p; - - return p; -} - -/** - * Returns the absolute value of a tile_t value - * - * \param t positive or negative tile_t - * */ -tile_t abs_tile(tile_t t) -{ - if (t < 0) - return -1 * t; - - return t; -} - -/** - * Returns true if tile is empty, false otherwise - * - * \param t tile to check if empty - * */ -bool tile_empty(tile_t t) -{ - return t == E; -} - -/** - * Returns row number of 1D board index - * - * \param i index to get row number of - * */ -index_t row(index_t i) -{ - return i / ROW; -} - -/** - * Returns column number of board index - * - * \param i index to get column number of - * */ -index_t column(index_t i) -{ - return i % ROW; -} - -/** - * Returns true if a and b are tiles of opposite player, false otherwise - * - * \param a Tile to compare - * \param b Tile to compare it with - * */ -bool opposite_color(tile_t a, tile_t b) -{ - return a * b < 0; -} - -/** - * Returns true if a and b are pieces of the same color - * - * \param a Tile to compare - * \param b Tile to compare it with - * */ -bool same_color(tile_t a, tile_t b) -{ - return a * b > 0; -} - -/** - * Returns true if a move is valid, false otherwise - * - * \param board Pointer to list of tiles representing board state - * \param from Tile to move piece from - * \param to Tile to move piece to - * \param player The current player to move - * */ -bool move_ok(const tile_t board[BOARD_SIZE], - index_t from, - index_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; - } - - if (tile_empty(board[from])) { - printf("Can't move from empty tile"); - 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])) { - case P: - return pawn_move_ok(board, from, to, player); - - case B: - return bishop_move_ok(board, from, to); - - case R: - return rook_move_ok(board, from, to); - - 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 - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece starts at - * \param to Index of board piece wants to move to - * \param player Player to move - */ -bool pawn_move_ok(const tile_t board[BOARD_SIZE], - index_t from, - index_t to, - int player) -{ - const index_t diff = (to - from) * -player; - - switch (diff) { - default: - return false; - - 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 2 * ROW: /* double move */ - return tile_empty(board[to]) && tile_empty(board[from - ROW * player]) - && (row(from) == 1 || row(from) == 6); - } -} - -/** - * Returns true if `to` is on a diagonal line of `from`, false otherwise - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool diagonal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - const index_t col_diff = column(to) - column(from); - const index_t row_diff = row(to) - row(from); - - const index_t x_step = col_diff / abs_pos(col_diff); - const index_t y_step = ROW * row_diff / abs_pos(row_diff); - const index_t step = x_step + y_step; - - if (abs_pos(col_diff) != abs_pos(row_diff)) { - printf("\nNot a diagonal move"); - return false; - } - - for (index_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 index `to` is on a cardinal line of `from`, false otherwise - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool cardinal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - const index_t col_diff = column(to) - column(from); - const index_t row_diff = row(to) - row(from); - - if (row_diff > 0 && col_diff > 0) - printf("Must move in a straight line"); - - index_t step; - - if (row_diff) - step = ROW * row_diff / abs_pos(row_diff); - else - step = col_diff / abs_pos(col_diff); - - for (index_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 move is a valid bishop move - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - return diagonal_move_ok(board, from, to); -} - -/** - * Returns true if move is a valid rook move - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool rook_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - return cardinal_move_ok(board, from, to); -} - -/** - * Returns true if move is a valid knight move - * - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool knight_move_ok(index_t from, index_t to) -{ - const index_t abs_col_diff = abs_pos(column(to) - column(from)); - const index_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); -} - -/** - * Returns true if move is a valid king move - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool king_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - const index_t abs_col_diff = abs_pos(column(to) - column(from)); - const index_t abs_row_diff = abs_pos(row(to) - row(from)); - - (void)board; - - return abs_col_diff <= 1 && abs_row_diff <= 1; -} - -/** - * Returns true if move is a valid queen move - * - * \param board Array of tiles representing chess board state - * \param from Index of board piece is at - * \param to Index of board piece tries to move to - */ -bool queen_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) -{ - return diagonal_move_ok(board, from, to) - || cardinal_move_ok(board, from, to); -} diff --git a/common.c b/common.c new file mode 100644 index 0000000..e69de29 diff --git a/common.h b/common.h new file mode 100644 index 0000000..60244d3 --- /dev/null +++ b/common.h @@ -0,0 +1,26 @@ + +#include /* int32_t */ +#include /* ptrdiff_t */ +#include /* true, false, bool */ + +/** Type representing piece/tile on a chessboard */ +typedef int32_t tile_t; + +/** Type representing index of a chessboard tile */ +typedef ptrdiff_t index_t; + +#define BOARD_SIZE ((index_t)(8 * 8)) + +#define WHITE 1 +#define BLACK -1 + +#define E ((tile_t)0) ///< empty tile +#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 ROW ((index_t)8) +#define COL ((index_t)1) diff --git a/graphics.c b/graphics.c new file mode 100644 index 0000000..bba6199 --- /dev/null +++ b/graphics.c @@ -0,0 +1,92 @@ + +#include "graphics.h" +#include "common.h" +#include "util.h" + +#include + +/** Set background to dark blue */ +#define BG_DARKBLUE() setcolor(0, 100, 100, 150) + +/** Set background to light blue */ +#define BG_LIGHTBLUE() setcolor(0, 150, 150, 200) + +/** Set foreground to black */ +#define FG_BLACK() setcolor(1, 0, 0, 0) + +/** Set foreground to white */ +#define FG_WHITE() setcolor(1, 0xff, 0xff, 0xff) + +/** 0x2659 == ♙ */ +#define UNICODE_CHESS_SYMBOL 0x2659 + +static inline void setcolor(const int mode, const int r, const int g, const int b); + +/** + * Sets the foreground or background color for subsequent writes. + * + * Uses Select Graphic Renditions (SGR) to set the color of the terminal output. + * See https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit for more details. + * + * \param mode 0 - change background, 1 - change foreground, 2 - reset colors + * \param r amount of red (0 to 255) + * \param b amount of blue (0 to 255) + * \param g amount of green (0 to 255) + */ +static inline 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 + * + * Uses unicode symbols and ANSI escape features to print a chessboard on the + * display. + * + * \param board A pointer to a list of tiles representing the board state + * + * */ +void print_board(const tile_t board[BOARD_SIZE]) +{ + /* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode + + The unicode symbols for the pieces are calculated from adding + 0x2653 (#define'd as UNICODE_CHESS_SYMBOL) with the piece value. */ + + for (size_t i = 0; i < 8; i++) { + printf("\n %zu ", 8 - i); // number coordinates + + for (size_t j = 0; j < 8; j++) { + tile_t t = board[i * 8 + j]; + + if ((i + j) % 2) + BG_DARKBLUE(); + else + BG_LIGHTBLUE(); + + if (tile_empty(t)) { + printf(" "); + continue; + } + + if (t > 0) + FG_WHITE(); + else + FG_BLACK(); + + printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(t)); + } + + setcolor(2, 0, 0, 0); // reset text attributes + } + + /* horizontal letter coordinates */ + printf("\n "); + + for (int i = 0; i < 8; i++) + printf(" %c", 'a' + i); +} diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..f4b2c41 --- /dev/null +++ b/graphics.h @@ -0,0 +1,8 @@ +#ifndef GRAPHICS_H +#define GRAPHICS_H + +#include "common.h" + +void print_board(const tile_t board[BOARD_SIZE]); + +#endif diff --git a/pieces.c b/pieces.c new file mode 100644 index 0000000..a349eb8 --- /dev/null +++ b/pieces.c @@ -0,0 +1,221 @@ + +#include "common.h" +#include "util.h" + + +static bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); +static bool cardinal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); +static bool diagonal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); +static bool king_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); +static bool knight_move_ok(index_t from, index_t to); +static bool pawn_move_ok(const tile_t board[BOARD_SIZE], + index_t from, + index_t to, + int player); +static bool queen_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); +static bool rook_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to); + + +/** + * Returns true if move is a valid pawn move + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece starts at + * \param to Index of board piece wants to move to + * \param player Player to move + */ +bool pawn_move_ok(const tile_t board[BOARD_SIZE], + index_t from, + index_t to, + int player) +{ + const index_t diff = (to - from) * -player; + + switch (diff) { + default: + return false; + + 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 2 * ROW: /* double move */ + return tile_empty(board[to]) && tile_empty(board[from - ROW * player]) + && (row(from) == 1 || row(from) == 6); + } +} + +/** + * Returns true if `to` is on a diagonal line of `from`, false otherwise + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool diagonal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + const index_t col_diff = column(to) - column(from); + const index_t row_diff = row(to) - row(from); + + const index_t x_step = col_diff / abs_pos(col_diff); + const index_t y_step = ROW * row_diff / abs_pos(row_diff); + const index_t step = x_step + y_step; + + if (abs_pos(col_diff) != abs_pos(row_diff)) + return false; + + for (index_t p = from + step; p != to; p += step) { + if (! tile_empty(board[p])) + return false; + } + + return true; +} + +/** + * Returns true if index `to` is on a cardinal line of `from`, false otherwise + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool cardinal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + const index_t col_diff = column(to) - column(from); + const index_t row_diff = row(to) - row(from); + + /* cardinal moves means one direction has to be zero */ + if (row_diff > 0 && col_diff > 0) + return false; + + index_t step = row_diff ? + ROW * row_diff / abs_pos(row_diff) + : col_diff / abs_pos(col_diff); + + for (index_t p = from + step; p != to; p += step) { + if (! tile_empty(board[p])) + return false; + } + + return true; +} + +/** + * Returns true if move is a valid bishop move + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + return diagonal_move_ok(board, from, to); +} + +/** + * Returns true if move is a valid rook move + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool rook_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + return cardinal_move_ok(board, from, to); +} + +/** + * Returns true if move is a valid knight move + * + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool knight_move_ok(index_t from, index_t to) +{ + const index_t c = abs_pos(column(to) - column(from)); + const index_t r = abs_pos(row(to - from)); + + return (c == 1 && r == 2) + || (c == 2 && r == 1); +} + +/** + * Returns true if move is a valid king move + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool king_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + const index_t abs_col_diff = abs_pos(column(to) - column(from)); + const index_t abs_row_diff = abs_pos(row(to) - row(from)); + + (void)board; + + return abs_col_diff <= 1 && abs_row_diff <= 1; +} + +/** + * Returns true if move is a valid queen move + * + * \param board Array of tiles representing chess board state + * \param from Index of board piece is at + * \param to Index of board piece tries to move to + */ +bool queen_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to) +{ + return diagonal_move_ok(board, from, to) + || cardinal_move_ok(board, from, to); +} + +/** + * Returns true if a move is valid, false otherwise + * + * \param board Pointer to list of tiles representing board state + * \param from Tile to move piece from + * \param to Tile to move piece to + * \param player The current player to move + * */ +bool move_ok(const tile_t board[BOARD_SIZE], + index_t from, + index_t to, + int player) +{ + /* player must own piece it moves */ + if (board[from] * player < 0) + return false; + + if (tile_empty(board[from])) + return false; + + /* player can't take own pieces or move piece onto itself*/ + if (same_color(board[from], board[to])) + return false; + + /* check piece specific moves */ + switch (abs_tile(board[from])) { + case P: + return pawn_move_ok(board, from, to, player); + + case B: + return bishop_move_ok(board, from, to); + + case R: + return rook_move_ok(board, from, to); + + 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; +} diff --git a/pieces.h b/pieces.h new file mode 100644 index 0000000..c47a16e --- /dev/null +++ b/pieces.h @@ -0,0 +1,13 @@ + +#ifndef PIECES_H +#define PIECES_H + +#include "common.h" + +bool move_ok(const tile_t board[BOARD_SIZE], + index_t from, + index_t to, + const int player); + + +#endif diff --git a/util.c b/util.c new file mode 100644 index 0000000..e844c24 --- /dev/null +++ b/util.c @@ -0,0 +1,82 @@ + +#include "util.h" + +/** + * Returns the absolute value of an index_t value + * + * \param p positive or negative index_t + */ +index_t abs_pos(index_t p) +{ + if (p < 0) + return -1 * p; + + return p; +} + +/** + * Returns the absolute value of a tile_t value + * + * \param t positive or negative tile_t + * */ +tile_t abs_tile(tile_t t) +{ + if (t < 0) + return -1 * t; + + return t; +} + +/** + * Returns true if tile is empty, false otherwise + * + * \param t tile to check if empty + * */ +bool tile_empty(tile_t t) +{ + return t == E; +} + +/** + * Returns row number of 1D board index + * + * \param i index to get row number of + * */ +index_t row(index_t i) +{ + return i / ROW; +} + +/** + * Returns column number of board index + * + * \param i index to get column number of + * */ +index_t column(index_t i) +{ + return i % ROW; +} + +/** + * Returns true if a and b are tiles of opposite color, false otherwise + * + * \param a Tile to compare + * \param b Tile to compare it with + * */ +bool opposite_color(tile_t a, tile_t b) +{ + return a * b < 0; +} + +/** + * Returns true if a and b are pieces of the same color, false otherwise + * + * \param a Tile to compare + * \param b Tile to compare it with + * */ +bool same_color(tile_t a, tile_t b) +{ + return a * b > 0; +} + + diff --git a/util.h b/util.h new file mode 100644 index 0000000..ea9978b --- /dev/null +++ b/util.h @@ -0,0 +1,10 @@ +#include "common.h" + +bool tile_empty(tile_t t); +index_t abs_pos(index_t p); +index_t column(index_t i); +index_t row(index_t i); +tile_t abs_tile(tile_t t); +bool same_color(tile_t a, tile_t b); +bool opposite_color(tile_t a, tile_t b); +