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); +