sudo legal moves

This commit is contained in:
2024-03-10 17:40:49 +01:00
parent 5964cd7239
commit 5b4dbee026
5 changed files with 462 additions and 51 deletions

View File

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.18)
project(chess C)
#include_directories("lib/acl/include")
#file(GLOB SOURCES "src/*.c" "lib/*/src/*.c")
file(GLOB SOURCES "src/*.c")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(PkgConfig REQUIRED)
@ -11,3 +10,19 @@ pkg_check_modules(LIBRSVG REQUIRED IMPORTED_TARGET librsvg-2.0)
add_executable(${PROJECT_NAME} ${SOURCES})
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG)
# Enable LTO for release build type
if(CMAKE_BUILD_TYPE MATCHES "Release")
include(CheckIPOSupported)
check_ipo_supported(RESULT result OUTPUT output)
if(result)
set_target_properties(${PROJECT_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
message(WARNING "IPO is not supported: ${output}")
endif()
endif()
add_executable(chessNoComputer ${SOURCES})
set_property(TARGET chessNoComputer PROPERTY C_STANDARD 99)
target_link_libraries(chessNoComputer PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG)
target_compile_definitions(chessNoComputer PUBLIC NO_COMPUTER)

View File

@ -1,28 +1,76 @@
#include <bits/stdint-least.h>
#include <ctype.h>
#include <gtk/gtk.h>
#include <cairo.h>
#include <librsvg/rsvg.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#include "move.h"
#define drawPiece(file, rank, piece) { \
const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\
rsvg_handle_render_document(piecesSvg[pieceToSvgI(piece)], cr, &rect, NULL); \
}
struct drawData_t {
RsvgHandle **piecesSvg;
struct piece_t *chessboard;
struct gameState_t *gameState;
uint_least8_t clickedPiece;
struct move_t *moves;
uint_least8_t movesLength;
uint_least8_t selectDst; // only for promotion
GtkWidget *drawArea;
double xOffset;
double yOffset;
double fieldSize;
};
const uint_least8_t PROMOTION_PIECES[] = {QUEEN, KNIGHT, BISHOP, ROOK};
#ifdef NO_COMPUTER
static bool NocTurn = true;
#endif
static uint_least8_t pieceToSvgI(struct piece_t piece) {
return piece.white ? piece.type | 8 : piece.type;
}
static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_least8_t field, double radius) {
uint_least8_t file = field % BOARD_SIZE;
uint_least8_t rank = field / BOARD_SIZE;
double xOffset = drawData->xOffset;
double yOffset = drawData->yOffset;
double fieldSize = drawData->fieldSize;
cairo_arc(cr, xOffset + (file + 0.5) * fieldSize, yOffset + (rank + 0.5) * fieldSize, radius, 0, 2 * M_PI);
}
static struct gameState_t userMove(struct gameState_t gameState, struct move_t move) {
gameState = makeMove(gameState, move);
#ifdef NO_COMPUTER
NocTurn = !NocTurn;
#else
gameState = computerMove(gameState);
#endif
return gameState;
}
static uint_least8_t promotionUiPos(uint_least8_t dst) {
return dst >= 1 ? dst - 1 : 0;
}
static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data) {
const double fieldSize = (double)(width < height ? width : height) / BOARD_SIZE;
const double xOffset = (width - fieldSize * BOARD_SIZE) / 2;
const double yOffset = (height - fieldSize * BOARD_SIZE) / 2;
const struct drawData_t drawData = *(struct drawData_t*)data;
const struct piece_t *chessboard = drawData.chessboard;
RsvgHandle **piecesSvg = drawData.piecesSvg;
struct drawData_t *drawData = (struct drawData_t*)data;
const struct piece_t *chessboard = drawData->gameState->board;
RsvgHandle **piecesSvg = drawData->piecesSvg;
drawData->xOffset = xOffset;
drawData->yOffset = yOffset;
drawData->fieldSize = fieldSize;
for(int x = 0; x < 8; ++x) {
for(int y = 0; y < 8; ++y) {
cairo_rectangle(cr, xOffset + x * fieldSize, yOffset + y * fieldSize, fieldSize, fieldSize);
@ -31,21 +79,108 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
cairo_fill(cr);
const struct piece_t piece = chessboard[x + y * BOARD_SIZE];
if(piece.type) {
const RsvgRectangle rect = {xOffset + x * fieldSize, yOffset + y * fieldSize, fieldSize, fieldSize};
rsvg_handle_render_document(piecesSvg[pieceToSvgI(piece)], cr, &rect, NULL);
drawPiece(x, y, piece)
}
}
}
if(drawData->clickedPiece != NOT_SELECTED && drawData->selectDst == NOT_SELECTED) {
cairo_set_source_rgba(cr, 0.0, 1.0, 0, 0.5);
selectCircle(cr, drawData, drawData->clickedPiece, fieldSize * 0.47);
cairo_set_line_width(cr, fieldSize / 20);
cairo_stroke(cr);
for(uint_least8_t i = 0; i < drawData->movesLength; ++i) {
selectCircle(cr, drawData, drawData->moves[i].dst, fieldSize / 6);
cairo_fill(cr);
}
}
if(drawData->selectDst != NOT_SELECTED) {
uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
if(uiPos + 3 >= BOARD_SIZE) uiPos = BOARD_SIZE - LENGTH(PROMOTION_PIECES);
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
cairo_rectangle(cr, xOffset + uiPos * fieldSize, yOffset, 4 * fieldSize, fieldSize);
cairo_fill(cr);
for(uint_least8_t i = 0; i < LENGTH(PROMOTION_PIECES); ++i) {
const struct piece_t piece = {PROMOTION_PIECES[i], true};
drawPiece(uiPos + i, 0, piece)
}
}
}
static void on_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) {
g_print("Mouse clicked at (%f, %f)\n", x, y);
struct drawData_t *drawData = (struct drawData_t*)data;
struct gameState_t *gameState = drawData->gameState;
struct piece_t *chessboard = gameState->board;
const double fieldSize = drawData->fieldSize;
const double adjustedX = x - drawData->xOffset;
const double adjustedY = y - drawData->yOffset;
if(adjustedY < 0 || adjustedX < 0 ||
adjustedY > BOARD_SIZE * fieldSize || adjustedX > BOARD_SIZE * fieldSize) return;
const uint_least8_t file = adjustedX / fieldSize;
const uint_least8_t rank = adjustedY / fieldSize;
const uint_least8_t field = file + rank * BOARD_SIZE;
if(drawData->selectDst == NOT_SELECTED) {
if(chessboard[field].type && chessboard[field].white
#ifdef NO_COMPUTER
== NocTurn
#endif
) {
// deaktivated piece by clicking on it again
if(field == drawData->clickedPiece) {
drawData->clickedPiece = NOT_SELECTED;
drawData->movesLength = 0;
}
else { // clicked on new piece
drawData->clickedPiece = field;
drawData->movesLength = pieceValidMoves(*gameState, chessboard[field].white, drawData->moves, field, false);
}
}
else if(drawData->clickedPiece != NOT_SELECTED){
bool isValidDst = false;
for(uint_least8_t i = 0; i < drawData->movesLength; ++i) {
if(drawData->moves[i].dst == field) {
isValidDst = true;
break;
}
}
if(isValidDst) {
const struct piece_t piece = chessboard[drawData->clickedPiece];
if(piece.type == PAWN && field < BOARD_SIZE) { // promotion
drawData->selectDst = field;
}
else {
struct move_t move;
for(uint_least8_t i = 0; i < drawData->movesLength; ++i) {
if(drawData->moves[i].dst == field) {
move = drawData->moves[i];
}
}
drawData->clickedPiece = NOT_SELECTED;
*gameState = userMove(*gameState, move);
}
}
else {
drawData->clickedPiece = NOT_SELECTED;
}
drawData->movesLength = 0;
}
}
else {
if(rank != 0) return;
const uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
const struct piece_t piece = {PROMOTION_PIECES[file - uiPos], true};
const struct move_t move = {drawData->clickedPiece, drawData->selectDst, 0, piece};
*gameState = userMove(*gameState, move);
drawData->selectDst = NOT_SELECTED;
drawData->clickedPiece = NOT_SELECTED;
}
gtk_widget_queue_draw(drawData->drawArea);
}
static void app_activate(GApplication *app, gpointer data) {
GtkWindow *window = GTK_WINDOW(gtk_window_new());
static RsvgHandle *piecesSvg[16];
static struct piece_t chessboard[BOARD_SIZE * BOARD_SIZE] = {};
static struct piece_t chessboard[TOTAL_BOARD_SIZE] = {};
static struct gameState_t gameState = {chessboard, {{true, true,}, {true, true}}, 0, NOT_SELECTED};
{
struct piece_t *piece = chessboard;
const char startFEN[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
@ -79,15 +214,17 @@ static void app_activate(GApplication *app, gpointer data) {
++piece;
}
}
static struct drawData_t drawData = {piecesSvg, chessboard};
{
static struct move_t moves[TOTAL_BOARD_SIZE];
static struct drawData_t drawData = {piecesSvg, &gameState, NOT_SELECTED, moves, 0, NOT_SELECTED};
GtkWidget *drawArea = gtk_drawing_area_new();
drawData.drawArea = drawArea;
gtk_window_set_child(window, drawArea);
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawArea), draw_event, &drawData, NULL);
}
{
GtkGesture *gesture = gtk_gesture_click_new();
g_signal_connect(gesture, "pressed", G_CALLBACK(on_click), NULL);
g_signal_connect(gesture, "pressed", G_CALLBACK(on_click), &drawData);
gtk_widget_add_controller(GTK_WIDGET(window), GTK_EVENT_CONTROLLER(gesture));
}
{
@ -123,9 +260,11 @@ int main(int argc, char **argv) {
GtkApplication *app;
int stat;
genDirectionConsts();
app = gtk_application_new("org.zinkel.chess", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK (app_activate), NULL);
stat = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref (app);
g_object_unref(app);
return stat;
}

View File

@ -1,11 +1,9 @@
#include <bits/stdint-least.h>
#include <stdbool.h>
#include <stdint.h>
#include "types.h"
// 218
#include "move.h"
struct move_t {
uint_least8_t src, dst;
};
struct addMoveCtx_t {
struct piece_t *board;
@ -14,48 +12,253 @@ struct addMoveCtx_t {
};
enum directions {
NORTH, WEST, SOUTH, EAST, DIRECTION_LENGTH
NORTH, NORTHWEST, WEST, SOUTHWEST, SOUTH, SOUTHEAST, EAST, NORTHEAST, DIRECTION_LENGTH
};
static int_least8_t directionOffset[BOARD_SIZE * DIRECTION_LENGTH];
const static uint_least8_t MAIN_DIRECTION[] = {NORTH, WEST, EAST, SOUTH};
void genDirectionOffset() {
for(uint_least8_t i = 0; i < TOTAL_BOARD_SIZE; ++i) {
uint_least8_t file = i % BOARD_SIZE;
uint_least8_t rank = i / BOARD_SIZE;
directionOffset[i * DIRECTION_LENGTH + NORTH] = rank;
directionOffset[i * DIRECTION_LENGTH + WEST] = file;
directionOffset[i * DIRECTION_LENGTH + EAST] = BOARD_SIZE - file - 1;
directionOffset[i * DIRECTION_LENGTH + SOUTH] = BOARD_SIZE - rank - 1;
static uint_least8_t directionOffset[TOTAL_BOARD_SIZE * DIRECTION_LENGTH];
static int_least8_t directionModifier[DIRECTION_LENGTH];
static uint_least8_t min(uint_least8_t a, uint_least8_t b) {
return a < b ? a : b;
}
void genDirectionConsts() {
for(uint_least16_t field = 0; field < TOTAL_BOARD_SIZE; ++field) {
uint_least8_t file = field % BOARD_SIZE;
uint_least8_t rank = field / BOARD_SIZE;
uint_least8_t *offsetField = directionOffset + field * DIRECTION_LENGTH;
offsetField[NORTH] = rank;
offsetField[WEST] = file;
offsetField[NORTHWEST] = min(file, rank);
offsetField[EAST] = BOARD_SIZE - file - 1;
offsetField[SOUTH] = BOARD_SIZE - rank - 1;
offsetField[SOUTHEAST] = min(offsetField[SOUTH], offsetField[EAST]);
offsetField[SOUTHWEST] = min(offsetField[SOUTH], file);
offsetField[NORTHEAST] = min(rank, offsetField[EAST]);
}
directionModifier[NORTH] = -BOARD_SIZE;
directionModifier[SOUTH] = BOARD_SIZE;
directionModifier[WEST] = -1;
directionModifier[EAST] = 1;
directionModifier[SOUTHEAST] = directionModifier[SOUTH] + directionModifier[EAST];
directionModifier[SOUTHWEST] = directionModifier[SOUTH] + directionModifier[WEST];
directionModifier[NORTHEAST] = directionModifier[NORTH] + directionModifier[EAST];
directionModifier[NORTHWEST] = directionModifier[NORTH] + directionModifier[WEST];
}
static void addMove(struct addMoveCtx_t ctx, uint_least8_t src, uint_least8_t dst) {
static void addMove(struct addMoveCtx_t ctx, uint_least8_t src, uint_least8_t dst, uint_least8_t spezialMove) {
struct piece_t *board = ctx.board;
struct move_t *moves = ctx.moves;
uint_least8_t *movesLength = ctx.movesLength;
if(board[src].white == board[dst].white) return;
moves[*movesLength].src = src;
moves[*movesLength].dst = dst;
++movesLength;
const struct move_t move = {src, dst, spezialMove, board[src]};
if(board[dst].type && board[src].white == board[dst].white) return;
ctx.moves[*movesLength] = move;
++*movesLength;
return;
}
void validMoves(struct piece_t *board, bool whiteToMove, struct move_t *moves) {
uint_least8_t movesLength = 0;
struct addMoveCtx_t addmoveCtx = {board, moves, &movesLength};
for(uint_least8_t i = 0; i < TOTAL_BOARD_SIZE; ++i) {
const struct piece_t piece = board[i];
if(piece.type && piece.white == whiteToMove) {
uint_least8_t file = i % BOARD_SIZE;
switch(piece.type) {
case KING:
if(i >= BOARD_SIZE) addMove(addmoveCtx, i, i - BOARD_SIZE);
if(i < 7 * BOARD_SIZE) addMove(addmoveCtx, i, i + BOARD_SIZE);
if(file > 0) addMove(addmoveCtx, i, i - 1);
if(file < BOARD_SIZE - 1) addMove(addmoveCtx, i, i + 1);
case ROOK:
}
static void moveSliding(const uint_least8_t *direction, uint_least8_t directionLength, struct addMoveCtx_t ctx,
uint_least8_t field) {
struct piece_t *board = ctx.board;
for(uint_least8_t j = 0; j < directionLength; ++j) {
const int_least8_t modifier = directionModifier[direction[j]];
for(uint_least8_t currentField = field + modifier, i = 0;
i < directionOffset[field * DIRECTION_LENGTH + direction[j]]; ++i, currentField += modifier) {
addMove(ctx, field, currentField, 0);
if(board[currentField].type) break;
}
}
}
static void movePawn(struct addMoveCtx_t ctx, uint_least8_t src, uint_least8_t dst,
bool promotion, uint_least8_t spezialMove) {
struct piece_t *board = ctx.board;
struct move_t *moves = ctx.moves;
uint_least8_t *movesLength = ctx.movesLength;
bool whiteToMove = board[src].white;
if(promotion && (whiteToMove && dst < BOARD_SIZE || !whiteToMove && dst >= BOARD_SIZE * (BOARD_SIZE - 1))) {
for(uint_least8_t promotionPiece = QUEEN; promotionPiece < PAWN; ++promotionPiece) {
const struct move_t move = {src, dst, spezialMove, {promotionPiece, board[src].white}};
moves[*movesLength] = move;
++*movesLength;
}
}
else {
const struct move_t move = {src, dst, spezialMove, {PAWN, board[src].white}};
moves[*movesLength] = move;
++*movesLength;
}
}
uint_least8_t pieceValidMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves,
uint_least8_t src, bool promotion) {
struct piece_t *board = gameState.board;
uint_least8_t movesLength = 0;
struct addMoveCtx_t addmoveCtx = {board, moves, &movesLength};
const uint_least8_t *localDirectionOffset = directionOffset + src * DIRECTION_LENGTH;
const struct piece_t piece = board[src];
if(piece.type && piece.white == whiteToMove) {
switch(piece.type) {
case KING:
{
const struct castle_t canCastle = gameState.canCastle[whiteToMove];
for(uint_least8_t direction = 0; direction < DIRECTION_LENGTH; ++direction) {
if(directionOffset[src * DIRECTION_LENGTH + direction] >= 1) {
addMove(addmoveCtx, src, src + directionModifier[direction], 0);
}
}
if(canCastle.shortCastle && board[src + 1].type == NOTHING && board[src + 2].type == NOTHING) {
addMove(addmoveCtx, src, src + 2, SHORT_CASTLE);
}
if(canCastle.longCastle && board[src - 1].type == NOTHING &&
board[src - 2].type == NOTHING && board[src - 3].type == NOTHING) {
addMove(addmoveCtx, src, src - 2, LONG_CASTLE);
}
break;
}
case ROOK:
moveSliding(MAIN_DIRECTION, LENGTH(MAIN_DIRECTION), addmoveCtx, src);
break;
case BISHOP:
{
uint_least8_t direction[] = {NORTHWEST, SOUTHWEST, SOUTHEAST, NORTHEAST};
moveSliding(direction, LENGTH(direction), addmoveCtx, src);
break;
}
case QUEEN:
{
uint_least8_t direction[DIRECTION_LENGTH];
for(uint_least8_t i = 0; i < DIRECTION_LENGTH; ++i) direction[i] = i;
moveSliding(direction, LENGTH(direction), addmoveCtx, src);
break;
}
case PAWN:
{
uint_least8_t pawnDirection = whiteToMove ? NORTH : SOUTH;
{
uint_least8_t directions[] = {EAST, WEST};
for(uint_least8_t j = 0; j < LENGTH(directions); ++j) {
uint_least8_t dst = src + directionModifier[directions[j]] + directionModifier[pawnDirection];
if(localDirectionOffset[directions[j]] >= 1) {
if(board[dst].type && board[dst].white != whiteToMove) {
movePawn(addmoveCtx, src, dst, promotion, 0);
}
else if(dst == gameState.enPassantTo) {
movePawn(addmoveCtx, src, dst, promotion, EN_PASSANT);
}
}
}
}
{
uint_least8_t dst = src + directionModifier[pawnDirection];
if(board[dst].type == NOTHING) {
movePawn(addmoveCtx, src, dst, promotion, 0);
if(src / BOARD_SIZE == (whiteToMove ? BOARD_SIZE - 2 : 1) && board[dst].type == NOTHING) {
dst += directionModifier[pawnDirection];
movePawn(addmoveCtx, src, dst, promotion, 0);
}
}
}
break;
}
case KNIGHT:
{
uint_least8_t direction[][2] = {
{SOUTH, EAST},
{EAST, SOUTH},
{SOUTH, WEST},
{WEST, SOUTH},
{NORTH, WEST},
{WEST, NORTH},
{NORTH, EAST},
{EAST, NORTH}
};
for(uint_least8_t i = 0; i < LENGTH(direction); ++i) {
if(localDirectionOffset[direction[i][0]] >= 2 && localDirectionOffset[direction[i][1]] >= 1) {
addMove(addmoveCtx, src,
src + 2 * directionModifier[direction[i][0]] + directionModifier[direction[i][1]], 0);
}
}
break;
}
}
}
return movesLength;
}
uint_least8_t validMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves) {
uint_least8_t movesLength = 0;
for(uint_least8_t src = 0; src < TOTAL_BOARD_SIZE; ++src) {
movesLength += pieceValidMoves(gameState, whiteToMove, moves + movesLength, src, true);
}
return movesLength;
}
static void setCastleInfo(struct castle_t *canCastle, uint_least8_t posOnRank) {
switch(posOnRank) {
case 0:
canCastle->longCastle = false;
break;
case BOARD_SIZE - 1:
canCastle->shortCastle = false;
break;
}
}
struct gameState_t makeMove(struct gameState_t gameState, struct move_t move) {
struct piece_t *board = gameState.board;
const struct piece_t noPiece = {NOTHING, false};
const bool whiteToMove = board[move.src].white;
const bool otherPlayer = !whiteToMove;
const uint_least8_t pieceType = board[move.src].type;
const uint_least8_t castleRankI[] = {0, (BOARD_SIZE - 1) * BOARD_SIZE};
struct piece_t *castleRankPtr = board + castleRankI[whiteToMove];
board[move.src] = noPiece;
board[move.dst] = move.dstPiece;
switch(move.spezialMove) {
case EN_PASSANT:
{
const uint_least8_t file = move.dst % 8;
const uint_least8_t rank = move.src / 8;
board[rank * BOARD_SIZE + file] = noPiece;
break;
}
case SHORT_CASTLE:
castleRankPtr[5] = castleRankPtr[BOARD_SIZE - 1];
castleRankPtr[BOARD_SIZE - 1] = noPiece;
break;
case LONG_CASTLE:
castleRankPtr[3] = castleRankPtr[0];
castleRankPtr[0] = noPiece;
break;
}
struct castle_t *canCastle = gameState.canCastle;
if(canCastle[whiteToMove].longCastle || canCastle[whiteToMove].shortCastle) {
if(pieceType == KING) {
canCastle[whiteToMove].longCastle = false;
canCastle[whiteToMove].shortCastle = false;
}
else {
setCastleInfo(canCastle + whiteToMove, move.src - castleRankI[whiteToMove]);
}
}
// if the rook is captured
if(canCastle[otherPlayer].longCastle || canCastle[otherPlayer].shortCastle) {
setCastleInfo(canCastle + otherPlayer, move.dst - castleRankI[otherPlayer]);
}
{
const int_least8_t dist = (int_least8_t)move.dst - (int_least8_t)move.src;
gameState.enPassantTo = pieceType == PAWN && (dist == 2 * BOARD_SIZE || dist == -2 * BOARD_SIZE)
? move.src + dist / 2 : NOT_SELECTED;
}
++gameState.halfMoveCounter;
return gameState;
}
struct gameState_t computerMove(struct gameState_t gameState) {
struct move_t moves[MAX_VALID_MOVES];
validMoves(gameState, false, moves);
return makeMove(gameState, moves[0]);
}

48
src/move.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef CHESS_MOVE_H
#define CHESS_MOVE_H
#include <stdint.h>
#include "types.h"
#include <stdbool.h>
#define MAX_VALID_MOVES 218
enum spezialMoves {
EN_PASSANT = 1,
SHORT_CASTLE,
LONG_CASTLE
};
struct castle_t {
bool shortCastle, longCastle;
};
struct move_t {
uint_least8_t src, dst, spezialMove;
struct piece_t dstPiece;
};
struct moveUndo_t {
uint_least8_t src, dst, enPassantTo;
struct castle_t canCastle;
struct piece_t srcPiece, capturedPiece;
};
struct gameState_t {
struct piece_t *board;
struct castle_t canCastle[2];
// The number of halfmoves since the last capture or pawn advance, used for the fifty-move rule.
uint_least8_t halfMoveCounter;
uint_least8_t enPassantTo; // index of the destination for a possible en passant capture
};
void genDirectionConsts();
uint_least8_t validMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves);
uint_least8_t pieceValidMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves,
uint_least8_t src, bool promotion);
struct gameState_t makeMove(struct gameState_t gameState, struct move_t move);
struct gameState_t computerMove(struct gameState_t gameState);
#endif

View File

@ -1,9 +1,13 @@
#ifndef CHESS_TYPES_H
#define CHESS_TYPES_H
#include <stdbool.h>
#include <stdint.h>
#define BOARD_SIZE 8
#define TOTAL_BOARD_SIZE BOARD_SIZE * BOARD_SIZE
#define LENGTH(array) (sizeof array / sizeof *array)
#define NOT_SELECTED UINT_LEAST8_MAX
enum pieces {
NOTHING,
@ -19,3 +23,5 @@ struct piece_t {
uint_least8_t type;
bool white;
};
#endif