Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 81272cbd38 | |||
| edb7409e7f | |||
| d898a9b691 | |||
| 5c162f413e | |||
| 29e5b3c2bb |
34
Makefile
34
Makefile
@@ -1,40 +1,40 @@
|
||||
|
||||
CC = clang
|
||||
LD = ld.lld
|
||||
CFLAGS = -Iinclude
|
||||
CC = gcc
|
||||
#CFLAGS += -O0 -ggdb3
|
||||
CFLAGS += -Ofast -ggdb3
|
||||
CFLAGS += -Wall -Wextra -Werror
|
||||
CFLAGS += -fsanitize=address
|
||||
LDFLAGS = -fuse-ld=lld
|
||||
LDFLAGS = -fsanitize=address
|
||||
CFLAGS += -Wall -Wextra -Wno-unused-function -rdynamic
|
||||
#CFLAGS += -fsanitize=address
|
||||
LDFLAGS = -fuse-ld=lld -rdynamic
|
||||
#LDFLAGS += -fsanitize=address
|
||||
|
||||
_OBJ = chess.o common.o graphics.o pieces.o util.o
|
||||
_OBJ = chess.o
|
||||
OBJ = $(addprefix obj/, $(_OBJ))
|
||||
|
||||
TEST_DIR = testing
|
||||
|
||||
all: bin/chess
|
||||
|
||||
test: $(TEST_DIR)/bin/test_threatmap
|
||||
|
||||
obj:
|
||||
mkdir -p $@
|
||||
|
||||
bin:
|
||||
mkdir -p $@
|
||||
|
||||
docs:
|
||||
doxygen doxygen-config
|
||||
$(TEST_DIR):
|
||||
mkdir -p $@/bin
|
||||
|
||||
clean:
|
||||
rm bin/* obj/*.o
|
||||
|
||||
gdb: bin/chess
|
||||
gdb $<
|
||||
|
||||
run: bin/chess
|
||||
./$<
|
||||
|
||||
obj/%.o: src/%.c
|
||||
$(CC) -o $@ $(CFLAGS) -c $<
|
||||
|
||||
bin/chess: $(OBJ)
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
|
||||
.PHONY: all run gdb clean docs
|
||||
$(TEST_DIR)/bin/test_%: testing/test_%.c obj/%.o obj/util.o
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
|
||||
.PHONY: all clean docs test
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
-Iinclude
|
||||
-Wall
|
||||
-Wextra
|
||||
-Werror
|
||||
|
||||
142
doxygen-config
142
doxygen-config
@@ -1,142 +0,0 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "Terminal Chess"
|
||||
PROJECT_BRIEF = Chess application for ANSI terminals
|
||||
OUTPUT_DIRECTORY = docs
|
||||
CREATE_SUBDIRS = NO
|
||||
ALLOW_UNICODE_NAMES = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
JAVADOC_BANNER = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
PYTHON_DOCSTRING = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
MARKDOWN_SUPPORT = YES
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
AUTOLINK_SUPPORT = YES
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
NUM_PROC_THREADS = 0
|
||||
EXTRACT_ALL = YES
|
||||
CASE_SENSE_NAMES = SYSTEM
|
||||
SHOW_HEADERFILE = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_IF_INCOMPLETE_DOC = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_IF_UNDOC_ENUM_VAL = NO
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LINE_FORMAT = "at line $line of file $file"
|
||||
INPUT = src
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.c *.h
|
||||
RECURSIVE = YES
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
FILTER_SOURCE_FILES = NO
|
||||
USE_MDFILE_AS_MAINPAGE = README.md
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
ALPHABETICAL_INDEX = YES
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_COLORSTYLE = AUTO_LIGHT
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
FULL_SIDEBAR = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
OBFUSCATE_EMAILS = YES
|
||||
HTML_FORMULA_FORMAT = png
|
||||
FORMULA_FONTSIZE = 10
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_VERSION = MathJax_2
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
LATEX_MAKEINDEX_CMD = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
TAGFILES = tags
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
#include <stdbool.h> /* true, false, bool */
|
||||
#include <stddef.h> /* ptrdiff_t */
|
||||
#include <stdint.h> /* int32_t */
|
||||
|
||||
/** 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 ((tile_t)1)
|
||||
#define BLACK ((tile_t)-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)
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef GRAPHICS_H
|
||||
#define GRAPHICS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void print_board(const tile_t board[BOARD_SIZE]);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
#ifndef PIECES_H
|
||||
#define PIECES_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
bool move_ok(const tile_t board[BOARD_SIZE],
|
||||
index_t from,
|
||||
index_t to,
|
||||
int player);
|
||||
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
int64_t get_sign(int64_t n);
|
||||
bool tile_empty(tile_t t);
|
||||
index_t abs_index(index_t i);
|
||||
index_t column(index_t i);
|
||||
index_t row(index_t i);
|
||||
tile_t abs_tile(tile_t t);
|
||||
tile_t get_color(tile_t t);
|
||||
bool same_color(tile_t a, tile_t b);
|
||||
bool opposite_color(tile_t a, tile_t b);
|
||||
149
src/board.h
Normal file
149
src/board.h
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wchar.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef uint64_t bitmap_t;
|
||||
typedef uint64_t index_t;
|
||||
typedef uint64_t piece_t;
|
||||
|
||||
#define TILE_BITS 4ULL
|
||||
|
||||
enum piece : piece_t {
|
||||
EMPTY = 0b0000ULL,
|
||||
|
||||
W_KING = 0b0001ULL,
|
||||
W_QUEEN = 0b0010ULL,
|
||||
W_ROOK = 0b0011ULL,
|
||||
W_BISHOP = 0b0100ULL,
|
||||
W_KNIGHT = 0b0101ULL,
|
||||
W_PAWN = 0b0110ULL,
|
||||
W_PAWN_ENPASSENTABLE = 0b0111ULL,
|
||||
|
||||
B_EMPTY = 0b1000ULL,
|
||||
B_KING = 0b1001ULL,
|
||||
B_QUEEN = 0b1010ULL,
|
||||
B_ROOK = 0b1011ULL,
|
||||
B_BISHOP = 0b1100ULL,
|
||||
B_KNIGHT = 0b1101ULL,
|
||||
B_PAWN = 0b1110ULL,
|
||||
B_PAWN_ENPASSENTABLE = 0b1111ULL,
|
||||
|
||||
BLACK = 0b1000ULL,
|
||||
#define WHITE 0
|
||||
};
|
||||
|
||||
static const char * const piece_str[] = {
|
||||
[EMPTY] = "EMPTY",
|
||||
[W_KING] = "W_KING",
|
||||
[W_QUEEN] = "W_QUEEN",
|
||||
[W_ROOK] = "W_ROOK",
|
||||
[W_BISHOP] = "W_BISHOP",
|
||||
[W_KNIGHT] = "W_KNIGHT",
|
||||
[W_PAWN] = "W_PAWN",
|
||||
[W_PAWN_ENPASSENTABLE] = "W_PAWN (enpassentable)",
|
||||
|
||||
[B_EMPTY] = "EMPTY (BLACK flag set)",
|
||||
[B_KING] = "B_KING",
|
||||
[B_QUEEN] = "B_QUEEN",
|
||||
[B_ROOK] = "B_ROOK",
|
||||
[B_BISHOP] = "B_BISHOP",
|
||||
[B_KNIGHT] = "B_KNIGHT",
|
||||
[B_PAWN] = "B_PAWN",
|
||||
[B_PAWN_ENPASSENTABLE ] = "B_PAWN (enpassentable)",
|
||||
};
|
||||
|
||||
static const wchar_t piece_symbol[] = {
|
||||
[WHITE | 0] = ' ',
|
||||
[W_KING] = 0x265A,
|
||||
[W_QUEEN] = 0x265B,
|
||||
[W_ROOK] = 0x265C,
|
||||
[W_BISHOP] = 0x265D,
|
||||
[W_KNIGHT] = 0x265E,
|
||||
[W_PAWN] = 0x265F,
|
||||
[W_PAWN_ENPASSENTABLE] = 0x265F,
|
||||
[B_KING] = 0x265A,
|
||||
[B_QUEEN] = 0x265B,
|
||||
[B_ROOK] = 0x265C,
|
||||
[B_BISHOP] = 0x265D,
|
||||
[B_KNIGHT] = 0x265E,
|
||||
[B_PAWN] = 0x265F,
|
||||
[B_PAWN_ENPASSENTABLE] = 0x265F,
|
||||
};
|
||||
|
||||
struct board {
|
||||
bitmap_t pieces[4]; // 4 bits correspond to 1 tile
|
||||
};
|
||||
static_assert(sizeof(((struct board*)0)->pieces) * CHAR_BIT == TILE_BITS*64,
|
||||
"pieces must contain enough information to hold a 64 chessboard tiles");
|
||||
static_assert((sizeof(((struct board*)0)->pieces[0]) * CHAR_BIT) % TILE_BITS == 0,
|
||||
"bitmap_t in bits must be divisible by TILE_BITS");
|
||||
|
||||
static inline bitmap_t tile_mask(index_t i)
|
||||
{
|
||||
return 0b1111ULL << (TILE_BITS*i);
|
||||
}
|
||||
|
||||
static inline bool is_white(piece_t piece)
|
||||
{
|
||||
return (piece & BLACK) == 0;
|
||||
}
|
||||
|
||||
static inline bool is_black(piece_t piece)
|
||||
{
|
||||
return (piece & BLACK) == BLACK;
|
||||
}
|
||||
|
||||
static inline piece_t piece_at(struct board* board, index_t tile)
|
||||
{
|
||||
static_assert(sizeof board->pieces[0] * CHAR_BIT == 64, "bad refactor");
|
||||
return (tile_mask(tile % (64/TILE_BITS)) & board->pieces[tile / (64/TILE_BITS)]) >> 4ULL*tile;
|
||||
}
|
||||
|
||||
static void paint_board(struct board* b)
|
||||
{
|
||||
/* 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. */
|
||||
#define BG_RED() printf("\033[48;2;150;150;0m")
|
||||
#define BG_DARKBLUE() printf("\033[48;2;100;100;150m")
|
||||
#define BG_LIGHTBLUE() printf("\033[48;2;150;150;200m")
|
||||
#define FG_BLACK() printf("\033[38;2;0;0;0m")
|
||||
#define FG_WHITE() printf("\033[38;2;255;255;255m")
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
printf("\n %d ", i+1); // number coordinates
|
||||
for (int j = 0; j < 8; j++) {
|
||||
piece_t p = piece_at(b, i*8+j);
|
||||
if ((i + j) % 2) {
|
||||
BG_DARKBLUE();
|
||||
} else {
|
||||
BG_LIGHTBLUE();
|
||||
}
|
||||
|
||||
if (p == EMPTY) {
|
||||
printf(" ");
|
||||
continue;
|
||||
}
|
||||
if (is_white(p)) {
|
||||
FG_WHITE();
|
||||
} else {
|
||||
FG_BLACK();
|
||||
}
|
||||
printf("%lc ", piece_symbol[p]);
|
||||
}
|
||||
printf("\033[0m"); // reset text attributes
|
||||
}
|
||||
/* horizontal letter coordinates */
|
||||
printf("\n ");
|
||||
for (int i = 0; i < 8; i++)
|
||||
printf(" %c", 'a' + i);
|
||||
printf("\n");
|
||||
}
|
||||
1208
src/chess.c
1208
src/chess.c
File diff suppressed because it is too large
Load Diff
45
src/cool_assert.h
Normal file
45
src/cool_assert.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <execinfo.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#undef assert
|
||||
|
||||
#ifdef assert
|
||||
#error "assert is already defined!"
|
||||
#endif
|
||||
|
||||
static void print_backtrace()
|
||||
{
|
||||
void* array[10];
|
||||
char** strings;
|
||||
int size, i;
|
||||
|
||||
size = backtrace(array, 10);
|
||||
strings = backtrace_symbols(array, size);
|
||||
if (strings != NULL)
|
||||
{
|
||||
printf ("Obtained %d stack frames.\n", size);
|
||||
for (i = 0; i < size; i++)
|
||||
printf ("%s\n", strings[i]);
|
||||
}
|
||||
|
||||
free(strings);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int assertion_fail(const char* msg)
|
||||
{
|
||||
fprintf(stderr, "assertion `%s` failed!\n", msg);
|
||||
print_backtrace();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define assert(expr) ((void)((expr) || (assertion_fail(# expr), 0)))
|
||||
#else
|
||||
#define assert(expt) (void)0
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
|
||||
#include "graphics.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/** 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);
|
||||
}
|
||||
14
src/map.h
Normal file
14
src/map.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SET_SIZE 4096
|
||||
#define BOARD_SIZE 64
|
||||
|
||||
typedef int_fast8_t piece_t;
|
||||
typedef piece_t Board[BOARD_SIZE];
|
||||
230
src/pieces.c
230
src/pieces.c
@@ -1,230 +0,0 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
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 pawn_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to);
|
||||
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);
|
||||
|
||||
/**
|
||||
* Check if a move is valid
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
* */
|
||||
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;
|
||||
|
||||
/* empty tiles can't be moved */
|
||||
if (tile_empty(board[from]))
|
||||
return false;
|
||||
|
||||
/* player can't take their own pieces or move a 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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
bool pawn_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to)
|
||||
{
|
||||
const index_t direction = -1 * get_color(board[from]),
|
||||
diff = (to - from) * direction;
|
||||
|
||||
switch (diff) {
|
||||
case ROW: /* single move */
|
||||
return tile_empty(board[to]);
|
||||
|
||||
case ROW - COL: /* diagonal attack */
|
||||
case ROW + COL:
|
||||
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);
|
||||
|
||||
default: /* any other move is illegal */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if `to` is on a diagonal line of `from`
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* \return true if \p to is on a diagonal line of \p from
|
||||
*/
|
||||
bool diagonal_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to)
|
||||
{
|
||||
// clang-format off
|
||||
const index_t col_diff = column(to) - column(from),
|
||||
row_diff = row(to) - row(from),
|
||||
x = get_sign(col_diff),
|
||||
y = get_sign(row_diff) * ROW,
|
||||
step = x + y;
|
||||
// clang-format on
|
||||
|
||||
if (abs_index(col_diff) != abs_index(row_diff))
|
||||
return false;
|
||||
|
||||
for (index_t p = from + step; p != to; p += step)
|
||||
if (! tile_empty(board[p]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if index `to` is on a cardinal line of `from`
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* \return true if \p to and \p from share a column or row
|
||||
*/
|
||||
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),
|
||||
row_diff = row(to - from);
|
||||
|
||||
if (row_diff > 0 && col_diff > 0)
|
||||
return false;
|
||||
|
||||
const index_t step =
|
||||
row_diff ? ROW * get_sign(row_diff) : get_sign(col_diff);
|
||||
|
||||
for (index_t p = from + step; p != to; p += step)
|
||||
if (! tile_empty(board[p]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
bool bishop_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to)
|
||||
{
|
||||
return diagonal_move_ok(board, from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
bool rook_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to)
|
||||
{
|
||||
return cardinal_move_ok(board, from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
bool knight_move_ok(index_t from, index_t to)
|
||||
{
|
||||
const index_t x = abs_index(column(to) - column(from)),
|
||||
y = abs_index(row(to - from));
|
||||
|
||||
return (x == 1 && y == 2) || (x == 2 && y == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
bool king_move_ok(const tile_t board[BOARD_SIZE], index_t from, index_t to)
|
||||
{
|
||||
const index_t abs_x = abs_index(column(to) - column(from)),
|
||||
abs_y = abs_index(row(to) - row(from));
|
||||
|
||||
// TODO: check if move causes check
|
||||
(void)board;
|
||||
|
||||
return abs_x <= 1 && abs_y <= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check 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
|
||||
*
|
||||
* \return true if move is valid, false otherwise
|
||||
*/
|
||||
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);
|
||||
}
|
||||
130
src/util.c
130
src/util.c
@@ -1,130 +0,0 @@
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Get sign of a number
|
||||
*
|
||||
* \param n positive or negative integer
|
||||
*
|
||||
* \return 1 if number is positive
|
||||
* -1 if number is negative
|
||||
* 0 if number is zero
|
||||
*/
|
||||
int64_t get_sign(int64_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
if (n >= 0)
|
||||
return 1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the color of a tile
|
||||
*
|
||||
* \param t tile to check
|
||||
*
|
||||
* \return WHITE (1) if tile is white,
|
||||
* BLACK (-1) if tile is black,
|
||||
* 0 if the tile is empty
|
||||
*/
|
||||
tile_t get_color(tile_t t)
|
||||
{
|
||||
return (tile_t)get_sign(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the absolute value of an index_t value
|
||||
*
|
||||
* \param p positive or negative index_t
|
||||
*
|
||||
* \return the absolute value of p
|
||||
*/
|
||||
index_t abs_index(index_t i)
|
||||
{
|
||||
if (i < 0)
|
||||
return -1 * i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the absolute value of a tile_t value
|
||||
*
|
||||
* \param t positive or negative tile_t
|
||||
*
|
||||
* \return the absolute value of t
|
||||
* */
|
||||
tile_t abs_tile(tile_t t)
|
||||
{
|
||||
if (t < 0)
|
||||
return -1 * t;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tile is has no piece on it
|
||||
*
|
||||
* \param t tile to check if empty
|
||||
*
|
||||
* \return true if tile is empty, false otherwise
|
||||
* */
|
||||
bool tile_empty(tile_t t)
|
||||
{
|
||||
return t == E;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get row of index
|
||||
*
|
||||
* \param i index to get row number of
|
||||
*
|
||||
* \return row number of i
|
||||
* */
|
||||
index_t row(index_t i)
|
||||
{
|
||||
return i / ROW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column of index
|
||||
*
|
||||
* \param i index to get column number of
|
||||
*
|
||||
* \return column number of i
|
||||
* */
|
||||
index_t column(index_t i)
|
||||
{
|
||||
return i % ROW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two tiles have pieces of the opposite color
|
||||
*
|
||||
* \param a Tile to compare
|
||||
* \param b Tile to compare it with
|
||||
*
|
||||
* \return true if a and b are opposite colors, false otherwise
|
||||
* */
|
||||
bool opposite_color(tile_t a, tile_t b)
|
||||
{
|
||||
return a * b < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two tiles have pieces of the same color
|
||||
*
|
||||
* \param a Tile to compare
|
||||
* \param b Tile to compare it with
|
||||
*
|
||||
* \return true if a and b are opposite colors, false otherwise
|
||||
* */
|
||||
bool same_color(tile_t a, tile_t b)
|
||||
{
|
||||
return a * b > 0;
|
||||
}
|
||||
60
testing/test_threatmap.c
Normal file
60
testing/test_threatmap.c
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#include "threatmap.h"
|
||||
|
||||
// uint64_t pawn_threatmap(const tile_t board[BOARD_SIZE], index_t index);
|
||||
// uint64_t bishop_threatmap(const tile_t board[BOARD_SIZE], index_t index);
|
||||
// uint64_t rook_threatmap(const tile_t board[BOARD_SIZE], index_t index);
|
||||
// uint64_t knight_threatmap(index_t index);
|
||||
// uint64_t king_threatmap(const tile_t board[BOARD_SIZE], index_t index);
|
||||
// uint64_t queen_threatmap(const tile_t board[BOARD_SIZE], index_t index);
|
||||
// uint64_t threatmap(const tile_t board[BOARD_SIZE], int color_attacking);
|
||||
// void print_threatmap(uint64_t threatmap);
|
||||
|
||||
void test_threatmap()
|
||||
{
|
||||
const tile_t e4[] = {
|
||||
-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, P, E, E, E, E,
|
||||
E, E, E, E, E, E, E, E,
|
||||
P, P, P, E, P, P, P, P,
|
||||
R, N, B, Q, K, B, N, R
|
||||
};
|
||||
|
||||
const tile_t lonely_bishop[] = {
|
||||
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, B, 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, E, E, E, E,
|
||||
};
|
||||
|
||||
const tile_t lonely_rook[] = {
|
||||
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, R, 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, E, E, E, E,
|
||||
};
|
||||
|
||||
(void)lonely_rook; (void)lonely_bishop; (void)e4;
|
||||
|
||||
//print_threatmap(threatmap(e4, WHITE));
|
||||
print_threatmap(threatmap(lonely_bishop, WHITE));
|
||||
//print_threatmap(threatmap(lonely_rook, WHITE));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_threatmap();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user