Larp as industry code with doxygen

This commit is contained in:
Ole Morud
2023-03-19 23:07:04 +01:00
parent e5c89cca35
commit 39f9d848b5
3 changed files with 1849 additions and 104 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
chess chess
doc/

316
chess.c
View File

@@ -6,50 +6,67 @@
#include <stdio.h> /* printf, scanf */ #include <stdio.h> /* printf, scanf */
#include <string.h> /* memcpy */ #include <string.h> /* memcpy */
/** Type representing piece/tile on a chessboard */
typedef int32_t tile_t; typedef int32_t tile_t;
/** Type representing index of a chessboard tile */
typedef ssize_t index_t; typedef ssize_t index_t;
#define ROW ((index_t)8) #define ROW ((index_t)8)
#define COL ((index_t)1) #define COL ((index_t)1)
#define BOARD_SIZE (8 * 8 * sizeof(tile_t)) #define BOARD_SIZE ((index_t)(8 * 8))
#define E ((tile_t)0) /* empty */ #define E ((tile_t)0) ///< empty tile
#define K ((tile_t)1) /* king */ #define K ((tile_t)1) ///< king
#define Q ((tile_t)2) /* queen */ #define Q ((tile_t)2) ///< queen
#define R ((tile_t)3) /* rook */ #define R ((tile_t)3) ///< rook
#define B ((tile_t)4) /* bishop */ #define B ((tile_t)4) ///< bishop
#define N ((tile_t)5) /* knight */ #define N ((tile_t)5) ///< knight
#define P ((tile_t)6) /* pawn */ #define P ((tile_t)6) ///< pawn
/** Set background to dark blue */
#define BG_DARKBLUE() setcolor(0, 100, 100, 150) #define BG_DARKBLUE() setcolor(0, 100, 100, 150)
/** Set background to light blue */
#define BG_LIGHTBLUE() setcolor(0, 150, 150, 200) #define BG_LIGHTBLUE() setcolor(0, 150, 150, 200)
/** Set foreground to black */
#define FG_BLACK() setcolor(1, 0, 0, 0) #define FG_BLACK() setcolor(1, 0, 0, 0)
/** Set foreground to white */
#define FG_WHITE() setcolor(1, 0xff, 0xff, 0xff) #define FG_WHITE() setcolor(1, 0xff, 0xff, 0xff)
#define WHITE 1 #define WHITE 1
#define BLACK -1 #define BLACK -1
/** 0x2659 == ♙ */
#define UNICODE_CHESS_SYMBOL 0x2659 #define UNICODE_CHESS_SYMBOL 0x2659
bool bishop_move_ok(const tile_t *board, index_t from, index_t to); bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to);
bool cardinal_move_ok(const tile_t *board, 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, 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, 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 knight_move_ok(index_t from, index_t to);
bool move_ok(tile_t *board, index_t from, index_t to, int player); bool move_ok(const tile_t board[BOARD_SIZE],
bool pawn_move_ok(const tile_t *board, index_t from, index_t to, int direction); index_t from,
bool queen_move_ok(const tile_t *board, index_t from, index_t to); index_t to,
bool rook_move_ok(const tile_t *board, 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); bool tile_empty(tile_t t);
index_t abs_pos(index_t p); index_t abs_pos(index_t p);
index_t column(index_t t); index_t column(index_t i);
index_t row(index_t t); index_t row(index_t i);
int get_piece(char *input); index_t get_piece(char input[2]);
tile_t abs_tile(tile_t t); tile_t abs_tile(tile_t t);
void do_turn(int turn_no, tile_t *board); void do_turn(int turn_no, tile_t board[BOARD_SIZE]);
void init_board(tile_t *board); void init_board(tile_t board[BOARD_SIZE]);
void print_board(tile_t *board); void print_board(const tile_t board[BOARD_SIZE]);
void setcolor(int mode, int r, int g, int b); void setcolor(int mode, int r, int g, int b);
int main() int main()
@@ -62,20 +79,26 @@ int main()
init_board(board); init_board(board);
while (1) { while (true) {
printf("\033[2J"); // clear screen
print_board(board); print_board(board);
do_turn(turn++, board); do_turn(turn, board);
++turn;
} }
return 0; return 0;
} }
/* /**
Sets the foreground or background color for subsequent writes. * Sets the foreground or background color for subsequent writes.
Modes: *
0: change background * Uses Select Graphic Renditions (SGR) to set the color of the terminal output.
1: change foreground * See https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit for more details.
2: reset colors *
* \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) void setcolor(const int mode, const int r, const int g, const int b)
{ {
@@ -85,55 +108,64 @@ void setcolor(const int mode, const int r, const int g, const int b)
printf("\033[%i;2;%i;%i;%im", mode ? 38 : 48, r, g, b); printf("\033[%i;2;%i;%i;%im", mode ? 38 : 48, r, g, b);
}; };
/* Prints the board */ /**
void print_board(tile_t *board) * 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 /* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode
The unicode symbol is calculated from adding 0x2653 with the The unicode symbols for the pieces are calculated from adding
piece value. */ 0x2653 (#define'd as UNICODE_CHESS_SYMBOL) with the piece value. */
for (size_t i = 0; i < 8; i++) { for (size_t i = 0; i < 8; i++) {
printf("\n %zu ", 8 - i); // print number coordinates on y-axis printf("\n %zu ", 8 - i); // number coordinates
for (size_t j = 0; j < 8; j++) { for (size_t j = 0; j < 8; j++) {
tile_t p = board[i * 8 + j]; tile_t t = board[i * 8 + j];
// Make tile dark and light
if ((i + j) % 2) if ((i + j) % 2)
BG_DARKBLUE(); BG_DARKBLUE();
else else
BG_LIGHTBLUE(); BG_LIGHTBLUE();
// Print empty space and do nothing if tile is empty if (tile_empty(t)) {
if (tile_empty(p)) {
printf(" "); printf(" ");
continue; continue;
} }
// Set piece color if (t > 0)
if (p > 0)
FG_WHITE(); FG_WHITE();
else else
FG_BLACK(); FG_BLACK();
printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(p)); printf("%lc ", UNICODE_CHESS_SYMBOL + abs_tile(t));
} }
setcolor(2, 0, 0, 0); // reset text attributes setcolor(2, 0, 0, 0); // reset text attributes
} }
// Print horizontal letter coordinates /* horizontal letter coordinates */
printf("\n "); printf("\n ");
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
printf(" %c", 'a' + i); printf(" %c", 'a' + i);
} }
/* /**
* Resets/inits the board * Resets/initializes the board
*
* Sets all the tiles of the board to match the starting position of chess.
*
* \param board Pointer to list of tiles representing board state
*/ */
void init_board(tile_t *board) void init_board(tile_t board[BOARD_SIZE])
{ {
// black pieces are prefixed by a minus (-) // black pieces are prefixed by a minus (-)
const tile_t start[] const tile_t start[]
@@ -146,8 +178,12 @@ void init_board(tile_t *board)
} }
// TODO: Implement algebaric notation // TODO: Implement algebaric notation
/* Get move, check move and log move for turn <turn_no> */ /** Asks for move, validates move and does move if valid
void do_turn(int turn_no, tile_t *board) *
* \param turn_no Turn number, is increased between every `do_turn` elsewhere
* \param board Pointer to list of tiles representing board state
* */
void do_turn(int turn_no, tile_t board[BOARD_SIZE])
{ {
char input[3] = { 0 }; char input[3] = { 0 };
@@ -189,8 +225,13 @@ void do_turn(int turn_no, tile_t *board)
board[from] = E; board[from] = E;
} }
/* Translates A1, 3B etc. to the 1D index of the board */ /**
int get_piece(char *input) * Translates A1, 3B etc. to the 1D index of the board
*
* \param input string of length 2 representing tile, e.g. "A3"
*
* */
index_t get_piece(char input[2])
{ {
int x = -1, y = -1, c; int x = -1, y = -1, c;
@@ -212,6 +253,11 @@ int get_piece(char *input)
return -1; 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) index_t abs_pos(index_t p)
{ {
if (p < 0) if (p < 0)
@@ -220,6 +266,11 @@ index_t abs_pos(index_t p)
return 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) tile_t abs_tile(tile_t t)
{ {
if (t < 0) if (t < 0)
@@ -228,38 +279,70 @@ tile_t abs_tile(tile_t t)
return t; return t;
} }
/* Returns true if tile is empty */ /**
* Returns true if tile is empty, false otherwise
*
* \param t tile to check if empty
* */
bool tile_empty(tile_t t) bool tile_empty(tile_t t)
{ {
return t == E; return t == E;
} }
/* Returns row number of board index */ /**
index_t row(index_t t) * Returns row number of 1D board index
*
* \param i index to get row number of
* */
index_t row(index_t i)
{ {
return t / ROW; return i / ROW;
} }
/* Returns column number of board index */ /**
index_t column(index_t t) * Returns column number of board index
*
* \param i index to get column number of
* */
index_t column(index_t i)
{ {
return t % ROW; return i % ROW;
} }
/* Returns true if a and b are tiles of opposite player */ /**
* 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) 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 */ /**
* 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) 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, index_t from, index_t to, const int player) * 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 */ /* player must own piece it moves */
if (board[from] * player < 0) { if (board[from] * player < 0) {
@@ -302,14 +385,20 @@ bool move_ok(tile_t *board, index_t from, index_t to, const int player)
return false; return false;
} }
/* Returns true if move is a valid pawn move /**
board - array of tiles representing chess board state * Returns true if move is a valid pawn move
from - index of board piece starts at *
to - index of board piece wants to move to * \param board Array of tiles representing chess board state
direction - pawns movement direction */ * \param from Index of board piece starts at
bool pawn_move_ok(const tile_t *board, index_t from, index_t to, int direction) * \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) * -direction; const index_t diff = (to - from) * -player;
switch (diff) { switch (diff) {
default: default:
@@ -323,17 +412,19 @@ bool pawn_move_ok(const tile_t *board, index_t from, index_t to, int direction)
return opposite_color(board[to], board[from]); return opposite_color(board[to], board[from]);
case 2 * ROW: /* double move */ case 2 * ROW: /* double move */
return tile_empty(board[to]) return tile_empty(board[to]) && tile_empty(board[from - ROW * player])
&& tile_empty(board[from - ROW * direction])
&& (row(from) == 1 || row(from) == 6); && (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 * Returns true if `to` is on a diagonal line of `from`, false otherwise
from - index of board piece is at *
to - index of board piece tries to move to */ * \param board Array of tiles representing chess board state
bool diagonal_move_ok(const tile_t *board, index_t from, index_t to) * \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 col_diff = column(to) - column(from);
const index_t row_diff = row(to) - row(from); const index_t row_diff = row(to) - row(from);
@@ -357,11 +448,14 @@ bool diagonal_move_ok(const tile_t *board, index_t from, index_t to)
return true; return true;
} }
/* Returns true if `to` is in a cardinal line of `from` /**
board - array of tiles representing chess board state * Returns true if index `to` is on a cardinal line of `from`, false otherwise
from - index of board piece is at *
to - index of board piece tries to move to */ * \param board Array of tiles representing chess board state
bool cardinal_move_ok(const tile_t *board, index_t from, index_t to) * \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 col_diff = column(to) - column(from);
const index_t row_diff = row(to) - row(from); const index_t row_diff = row(to) - row(from);
@@ -386,28 +480,36 @@ bool cardinal_move_ok(const tile_t *board, index_t from, index_t to)
return true; return true;
} }
/* Returns true if move is a valid bishop move /**
board - array of tiles representing chess board state * Returns true if move is a valid bishop move
from - index of board bishop is at *
to - index of board bishop wants to move to */ * \param board Array of tiles representing chess board state
bool bishop_move_ok(const tile_t *board, index_t from, index_t to) * \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); return diagonal_move_ok(board, from, to);
} }
/* Returns true if move is a valid rook move /**
board - array of tiles representing chess board state * Returns true if move is a valid rook move
from - index of board rook is at *
to - index of board rook wants to move to */ * \param board Array of tiles representing chess board state
bool rook_move_ok(const tile_t *board, index_t from, index_t to) * \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); return cardinal_move_ok(board, from, to);
} }
/* Returns true if move is a valid knight move /**
board - array of tiles representing chess board state * Returns true if move is a valid knight move
from - index of board knight is at *
to - index of board knight wants to move to */ * \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) 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_col_diff = abs_pos(column(to) - column(from));
@@ -417,11 +519,14 @@ bool knight_move_ok(index_t from, index_t to)
|| (abs_col_diff == 2 && abs_row_diff == 1); || (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 * Returns true if move is a valid king move
from - index of board king is at *
to - index of board king wants to move to */ * \param board Array of tiles representing chess board state
bool king_move_ok(const tile_t *board, index_t from, index_t to) * \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_col_diff = abs_pos(column(to) - column(from));
const index_t abs_row_diff = abs_pos(row(to) - row(from)); const index_t abs_row_diff = abs_pos(row(to) - row(from));
@@ -431,11 +536,14 @@ bool king_move_ok(const tile_t *board, index_t from, index_t to)
return abs_col_diff <= 1 && abs_row_diff <= 1; 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 * Returns true if move is a valid queen move
from - index of board queen is at *
to - index of board queen wants to move to */ * \param board Array of tiles representing chess board state
bool queen_move_ok(const tile_t *board, index_t from, index_t to) * \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) return diagonal_move_ok(board, from, to)
|| cardinal_move_ok(board, from, to); || cardinal_move_ok(board, from, to);

1636
doxygen-config Normal file

File diff suppressed because it is too large Load Diff