bitboard
This commit is contained in:
75
src/bitboard.c
Normal file
75
src/bitboard.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <bits/stdint-least.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
bool bitsetGet(uint_least64_t bitset, uint_least8_t i) {
|
||||||
|
return (bitset >> i) & 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_least64_t bitsetClear(uint_least64_t bitset, uint_least8_t i) {
|
||||||
|
return bitset & ~((uint_least64_t)1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_least64_t bitsetSet(uint_least64_t bitset, uint_least8_t i) {
|
||||||
|
return bitset | ((uint_least64_t)1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_least64_t bitboardGetMask(const uint_least64_t *board, struct piece_t piece) {
|
||||||
|
return board[piece.color * PIECES_LENGTH + piece.type];
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitboardSetMask(uint_least64_t *board, struct piece_t piece, uint_least64_t value) {
|
||||||
|
board[piece.color * PIECES_LENGTH + piece.type] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint_least64_t bitboardMaskAllPieces(const uint_least64_t *board) {
|
||||||
|
const struct piece_t blackPiece = {ALL_PIECES, BLACK};
|
||||||
|
const struct piece_t whitePiece = {ALL_PIECES, WHITE};
|
||||||
|
return bitboardGetMask(board, blackPiece) | bitboardGetMask(board, whitePiece);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bitboardGetAllPieces(const uint_least64_t *board, uint_least8_t i) {
|
||||||
|
return bitsetGet(bitboardMaskAllPieces(board), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bitboardGet(const uint_least64_t *board, struct piece_t piece, uint_least8_t i) {
|
||||||
|
return bitsetGet(bitboardGetMask(board, piece), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bitboardClearHelper(uint_least64_t *board, struct piece_t piece, uint_least8_t i) {
|
||||||
|
const uint_least64_t newMask = bitsetClear(bitboardGetMask(board, piece), i);
|
||||||
|
bitboardSetMask(board, piece, newMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitboardClear(uint_least64_t *board, struct piece_t piece, uint_least8_t i) {
|
||||||
|
const struct piece_t allPiece = {ALL_PIECES, piece.color};
|
||||||
|
bitboardClearHelper(board, allPiece, i);
|
||||||
|
bitboardClearHelper(board, piece, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bitboardSetHelper(uint_least64_t *board, struct piece_t piece, uint_least8_t i) {
|
||||||
|
const uint_least64_t newMask = bitsetSet(bitboardGetMask(board, piece), i);
|
||||||
|
bitboardSetMask(board, piece, newMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitboardSet(uint_least64_t *board, struct piece_t piece, uint_least8_t i) {
|
||||||
|
const struct piece_t allPiece = {ALL_PIECES, piece.color};
|
||||||
|
bitboardSetHelper(board, allPiece, i);
|
||||||
|
bitboardSetHelper(board, piece, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct piece_t pieceAtField(const uint_least64_t *board, uint_least8_t i) {
|
||||||
|
for(uint_least8_t color = BLACK; color <= WHITE; ++color) {
|
||||||
|
for(uint_least8_t pieceType = KING; pieceType < PIECES_LENGTH; ++pieceType) {
|
||||||
|
const struct piece_t piece = {pieceType, color};
|
||||||
|
if(bitboardGet(board, piece, i)) {
|
||||||
|
return piece;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const struct piece_t pieceError = {NOT_SELECTED, BLACK};
|
||||||
|
return pieceError;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/bitboard.h
Normal file
15
src/bitboard.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
bool bitsetGet(uint_least64_t bitset, uint_least8_t i);
|
||||||
|
uint_least64_t bitsetClear(uint_least64_t bitset, uint_least8_t i);
|
||||||
|
uint_least64_t bitsetSet(uint_least64_t bitset, uint_least8_t i);
|
||||||
|
bool bitboardGet(const uint_least64_t *board, struct piece_t piece, uint_least8_t i);
|
||||||
|
uint_least64_t bitboardGetMask(const uint_least64_t *board, struct piece_t piece);
|
||||||
|
void bitboardSetMask(uint_least64_t *board, struct piece_t piece, uint_least64_t value);
|
||||||
|
bool bitboardGetAllPieces(const uint_least64_t *board, uint_least8_t i);
|
||||||
|
uint_least64_t bitboardMaskAllPieces(const uint_least64_t *board);
|
||||||
|
void bitboardClear(uint_least64_t *board, struct piece_t piece, uint_least8_t i);
|
||||||
|
void bitboardSet(uint_least64_t *board, struct piece_t piece, uint_least8_t i);
|
||||||
|
struct piece_t pieceAtField(const uint_least64_t *board, uint_least8_t i);
|
||||||
75
src/main.c
75
src/main.c
@ -10,6 +10,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
|
#include "bitboard.h"
|
||||||
|
|
||||||
#define drawPiece(file, rank, piece) { \
|
#define drawPiece(file, rank, piece) { \
|
||||||
const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\
|
const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\
|
||||||
@ -30,12 +31,10 @@ struct drawData_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const uint_least8_t PROMOTION_PIECES[] = {QUEEN, KNIGHT, BISHOP, ROOK};
|
const uint_least8_t PROMOTION_PIECES[] = {QUEEN, KNIGHT, BISHOP, ROOK};
|
||||||
#ifdef NO_COMPUTER
|
static bool turn = WHITE;
|
||||||
static bool NocTurn = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static uint_least8_t pieceToSvgI(struct piece_t piece) {
|
static uint_least8_t pieceToSvgI(struct piece_t piece) {
|
||||||
return piece.white ? piece.type | 8 : piece.type;
|
return piece.color == WHITE ? piece.type | 8 : piece.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_least8_t field, double radius) {
|
static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_least8_t field, double radius) {
|
||||||
@ -48,9 +47,9 @@ static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_le
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct gameState_t userMove(struct gameState_t gameState, struct move_t move) {
|
static struct gameState_t userMove(struct gameState_t gameState, struct move_t move) {
|
||||||
gameState = makeMove(gameState, move);
|
gameState = makeMove(gameState, turn, move);
|
||||||
#ifdef NO_COMPUTER
|
#ifdef NO_COMPUTER
|
||||||
NocTurn = !NocTurn;
|
turn = !turn;
|
||||||
#else
|
#else
|
||||||
gameState = computerMove(gameState);
|
gameState = computerMove(gameState);
|
||||||
#endif
|
#endif
|
||||||
@ -66,20 +65,21 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
|
|||||||
const double xOffset = (width - fieldSize * BOARD_SIZE) / 2;
|
const double xOffset = (width - fieldSize * BOARD_SIZE) / 2;
|
||||||
const double yOffset = (height - fieldSize * BOARD_SIZE) / 2;
|
const double yOffset = (height - fieldSize * BOARD_SIZE) / 2;
|
||||||
struct drawData_t *drawData = (struct drawData_t*)data;
|
struct drawData_t *drawData = (struct drawData_t*)data;
|
||||||
const struct piece_t *chessboard = drawData->gameState->board;
|
const uint_least64_t *board = drawData->gameState->board;
|
||||||
RsvgHandle **piecesSvg = drawData->piecesSvg;
|
RsvgHandle **piecesSvg = drawData->piecesSvg;
|
||||||
drawData->xOffset = xOffset;
|
drawData->xOffset = xOffset;
|
||||||
drawData->yOffset = yOffset;
|
drawData->yOffset = yOffset;
|
||||||
drawData->fieldSize = fieldSize;
|
drawData->fieldSize = fieldSize;
|
||||||
for(int x = 0; x < 8; ++x) {
|
for(uint_least8_t file = 0; file < BOARD_SIZE; ++file) {
|
||||||
for(int y = 0; y < 8; ++y) {
|
for(uint_least8_t rank = 0; rank < BOARD_SIZE; ++rank) {
|
||||||
cairo_rectangle(cr, xOffset + x * fieldSize, yOffset + y * fieldSize, fieldSize, fieldSize);
|
const uint_least8_t field = rank * BOARD_SIZE + file;
|
||||||
if((x + y) & 1) cairo_set_source_rgb(cr, 0.46274, 0.5882, 0.3373);
|
cairo_rectangle(cr, xOffset + file * fieldSize, yOffset + rank * fieldSize, fieldSize, fieldSize);
|
||||||
|
if((file + rank) & 1) cairo_set_source_rgb(cr, 0.46274, 0.5882, 0.3373);
|
||||||
else cairo_set_source_rgb(cr, 0.9333, 0.9333, 0.8235);
|
else cairo_set_source_rgb(cr, 0.9333, 0.9333, 0.8235);
|
||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
const struct piece_t piece = chessboard[x + y * BOARD_SIZE];
|
if(bitboardGetAllPieces(board, field)) {
|
||||||
if(piece.type) {
|
const struct piece_t piece = pieceAtField(board, rank * BOARD_SIZE + file);
|
||||||
drawPiece(x, y, piece)
|
drawPiece(file, rank, piece);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
|
|||||||
static void on_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) {
|
static void on_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) {
|
||||||
struct drawData_t *drawData = (struct drawData_t*)data;
|
struct drawData_t *drawData = (struct drawData_t*)data;
|
||||||
struct gameState_t *gameState = drawData->gameState;
|
struct gameState_t *gameState = drawData->gameState;
|
||||||
struct piece_t *chessboard = gameState->board;
|
const uint_least64_t *board = gameState->board;
|
||||||
const double fieldSize = drawData->fieldSize;
|
const double fieldSize = drawData->fieldSize;
|
||||||
const double adjustedX = x - drawData->xOffset;
|
const double adjustedX = x - drawData->xOffset;
|
||||||
const double adjustedY = y - drawData->yOffset;
|
const double adjustedY = y - drawData->yOffset;
|
||||||
@ -119,19 +119,17 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|||||||
const uint_least8_t rank = adjustedY / fieldSize;
|
const uint_least8_t rank = adjustedY / fieldSize;
|
||||||
const uint_least8_t field = file + rank * BOARD_SIZE;
|
const uint_least8_t field = file + rank * BOARD_SIZE;
|
||||||
if(drawData->selectDst == NOT_SELECTED) {
|
if(drawData->selectDst == NOT_SELECTED) {
|
||||||
if(chessboard[field].type && chessboard[field].white
|
const struct piece_t allPiece = {ALL_PIECES, turn};
|
||||||
#ifdef NO_COMPUTER
|
if(bitboardGet(board, allPiece, field)) {
|
||||||
== NocTurn
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
// deaktivated piece by clicking on it again
|
// deaktivated piece by clicking on it again
|
||||||
if(field == drawData->clickedPiece) {
|
if(field == drawData->clickedPiece) {
|
||||||
drawData->clickedPiece = NOT_SELECTED;
|
drawData->clickedPiece = NOT_SELECTED;
|
||||||
drawData->movesLength = 0;
|
drawData->movesLength = 0;
|
||||||
}
|
}
|
||||||
else { // clicked on new piece
|
else { // clicked on new piece
|
||||||
|
const struct piece_t piece = pieceAtField(board, field);
|
||||||
drawData->clickedPiece = field;
|
drawData->clickedPiece = field;
|
||||||
drawData->movesLength = pieceValidMoves(*gameState, chessboard[field].white, drawData->moves, field, false);
|
drawData->movesLength = pieceValidMoves(*gameState, piece, field, drawData->moves, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(drawData->clickedPiece != NOT_SELECTED){
|
else if(drawData->clickedPiece != NOT_SELECTED){
|
||||||
@ -143,7 +141,7 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(isValidDst) {
|
if(isValidDst) {
|
||||||
const struct piece_t piece = chessboard[drawData->clickedPiece];
|
const struct piece_t piece = pieceAtField(board, field);
|
||||||
if(piece.type == PAWN && field < BOARD_SIZE) { // promotion
|
if(piece.type == PAWN && field < BOARD_SIZE) { // promotion
|
||||||
drawData->selectDst = field;
|
drawData->selectDst = field;
|
||||||
}
|
}
|
||||||
@ -167,8 +165,9 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|||||||
else {
|
else {
|
||||||
if(rank != 0) return;
|
if(rank != 0) return;
|
||||||
const uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
|
const uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
|
||||||
const struct piece_t piece = {PROMOTION_PIECES[file - uiPos], true};
|
const uint_least8_t dstPiece = PROMOTION_PIECES[file - uiPos];
|
||||||
const struct move_t move = {drawData->clickedPiece, drawData->selectDst, 0, piece};
|
const uint_least8_t capturedPiece = pieceAtField(board, drawData->selectDst).type;
|
||||||
|
const struct move_t move = {drawData->clickedPiece, drawData->selectDst, 0, PAWN, dstPiece};
|
||||||
*gameState = userMove(*gameState, move);
|
*gameState = userMove(*gameState, move);
|
||||||
drawData->selectDst = NOT_SELECTED;
|
drawData->selectDst = NOT_SELECTED;
|
||||||
drawData->clickedPiece = NOT_SELECTED;
|
drawData->clickedPiece = NOT_SELECTED;
|
||||||
@ -179,39 +178,43 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|||||||
static void app_activate(GApplication *app, gpointer data) {
|
static void app_activate(GApplication *app, gpointer data) {
|
||||||
GtkWindow *window = GTK_WINDOW(gtk_window_new());
|
GtkWindow *window = GTK_WINDOW(gtk_window_new());
|
||||||
static RsvgHandle *piecesSvg[16];
|
static RsvgHandle *piecesSvg[16];
|
||||||
static struct piece_t chessboard[TOTAL_BOARD_SIZE] = {};
|
static uint_least64_t board[2 * PIECES_LENGTH] = {};
|
||||||
static struct gameState_t gameState = {chessboard, {{true, true,}, {true, true}}, 0, NOT_SELECTED};
|
static struct gameState_t gameState = {board, {{true, true}, {true, true}}, 0, NOT_SELECTED};
|
||||||
{
|
{
|
||||||
struct piece_t *piece = chessboard;
|
struct piece_t piece;
|
||||||
const char startFEN[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
const char startFEN[] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||||
|
uint_least8_t field = 0;
|
||||||
for(const char *c = startFEN; *c != ' '; ++c) {
|
for(const char *c = startFEN; *c != ' '; ++c) {
|
||||||
switch(tolower(*c)) {
|
switch(tolower(*c)) {
|
||||||
case 'k':
|
case 'k':
|
||||||
piece->type = KING;
|
piece.type = KING;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
piece->type = QUEEN;
|
piece.type = QUEEN;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
piece->type = ROOK;
|
piece.type = ROOK;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
piece->type = KNIGHT;
|
piece.type = KNIGHT;
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
piece->type = BISHOP;
|
piece.type = BISHOP;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
piece->type = PAWN;
|
piece.type = PAWN;
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
if(isdigit(*c)) piece += *c - '0';
|
if(isdigit(*c)) {
|
||||||
|
field += *c - '0';
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(isalpha(*c)) piece->white = isupper(*c);
|
if(isalpha(*c)) piece.color = isupper(*c);
|
||||||
++piece;
|
bitboardSet(board, piece, field);
|
||||||
|
++field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
311
src/move.c
311
src/move.c
@ -3,10 +3,12 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
|
#include "bitboard.h"
|
||||||
|
|
||||||
|
#define trailingBits(num) __builtin_ctzll(num)
|
||||||
|
|
||||||
struct addMoveCtx_t {
|
struct addMoveCtx_t {
|
||||||
struct piece_t *board;
|
uint_least64_t *board;
|
||||||
struct move_t *moves;
|
struct move_t *moves;
|
||||||
uint_least8_t *movesLength;
|
uint_least8_t *movesLength;
|
||||||
};
|
};
|
||||||
@ -20,6 +22,10 @@ const static uint_least8_t MAIN_DIRECTION[] = {NORTH, WEST, EAST, SOUTH};
|
|||||||
static uint_least8_t directionOffset[TOTAL_BOARD_SIZE * DIRECTION_LENGTH];
|
static uint_least8_t directionOffset[TOTAL_BOARD_SIZE * DIRECTION_LENGTH];
|
||||||
static int_least8_t directionModifier[DIRECTION_LENGTH];
|
static int_least8_t directionModifier[DIRECTION_LENGTH];
|
||||||
|
|
||||||
|
static uint_least8_t getDirectionOffset(uint_least8_t field, uint_least8_t direction) {
|
||||||
|
return directionOffset[field * DIRECTION_LENGTH + direction];
|
||||||
|
}
|
||||||
|
|
||||||
static uint_least8_t min(uint_least8_t a, uint_least8_t b) {
|
static uint_least8_t min(uint_least8_t a, uint_least8_t b) {
|
||||||
return a < b ? a : b;
|
return a < b ? a : b;
|
||||||
}
|
}
|
||||||
@ -48,150 +54,178 @@ void genDirectionConsts() {
|
|||||||
directionModifier[NORTHWEST] = directionModifier[NORTH] + directionModifier[WEST];
|
directionModifier[NORTHWEST] = directionModifier[NORTH] + directionModifier[WEST];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addMove(struct addMoveCtx_t ctx, uint_least8_t src, uint_least8_t dst, uint_least8_t spezialMove) {
|
static uint_least8_t getCapturePos(uint_least8_t src, uint_least8_t dst, uint_least8_t spezialMove) {
|
||||||
struct piece_t *board = ctx.board;
|
if(spezialMove != EN_PASSANT) return dst;
|
||||||
|
const uint_least8_t file = dst % 8;
|
||||||
|
const uint_least8_t rank = src / 8;
|
||||||
|
return rank * BOARD_SIZE + file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addMove(struct addMoveCtx_t ctx, struct piece_t movedPiece, uint_least8_t src,
|
||||||
|
uint_least8_t dst, uint_least8_t spezialMove) {
|
||||||
|
uint_least64_t *board = ctx.board;
|
||||||
uint_least8_t *movesLength = ctx.movesLength;
|
uint_least8_t *movesLength = ctx.movesLength;
|
||||||
const struct move_t move = {src, dst, spezialMove, board[src]};
|
uint_least8_t capturedPiece = NOT_SELECTED;
|
||||||
if(board[dst].type && board[src].white == board[dst].white) return;
|
{
|
||||||
|
const struct piece_t pieceAllOtherColor = {ALL_PIECES, !movedPiece.color};
|
||||||
|
const uint_least8_t capturePos = getCapturePos(src, dst, spezialMove);
|
||||||
|
if(bitboardGet(board, pieceAllOtherColor, capturePos)) {
|
||||||
|
for(uint_least8_t pieceType = QUEEN; pieceType < PIECES_LENGTH; ++pieceType) {
|
||||||
|
const struct piece_t piece = {pieceType, !movedPiece.color};
|
||||||
|
if(bitboardGet(board, piece, capturePos)) {
|
||||||
|
capturedPiece = pieceType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const struct move_t move = {src, dst, spezialMove, movedPiece.type, movedPiece.type, capturedPiece};
|
||||||
|
const struct piece_t pieceAll = {ALL_PIECES, movedPiece.color};
|
||||||
|
if(bitboardGet(board, pieceAll, dst)) return;
|
||||||
ctx.moves[*movesLength] = move;
|
ctx.moves[*movesLength] = move;
|
||||||
++*movesLength;
|
++*movesLength;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moveSliding(const uint_least8_t *direction, uint_least8_t directionLength, struct addMoveCtx_t ctx,
|
static void moveSliding(const uint_least8_t *direction, uint_least8_t directionLength, struct addMoveCtx_t ctx,
|
||||||
uint_least8_t field) {
|
uint_least8_t field, struct piece_t movedPiece) {
|
||||||
struct piece_t *board = ctx.board;
|
uint_least64_t *board = ctx.board;
|
||||||
|
|
||||||
for(uint_least8_t j = 0; j < directionLength; ++j) {
|
for(uint_least8_t j = 0; j < directionLength; ++j) {
|
||||||
const int_least8_t modifier = directionModifier[direction[j]];
|
const int_least8_t modifier = directionModifier[direction[j]];
|
||||||
for(uint_least8_t currentField = field + modifier, i = 0;
|
for(uint_least8_t currentField = field + modifier, i = 0;
|
||||||
i < directionOffset[field * DIRECTION_LENGTH + direction[j]]; ++i, currentField += modifier) {
|
i < directionOffset[field * DIRECTION_LENGTH + direction[j]]; ++i, currentField += modifier) {
|
||||||
addMove(ctx, field, currentField, 0);
|
addMove(ctx, movedPiece, field, currentField, 0);
|
||||||
if(board[currentField].type) break;
|
if(bitboardGetAllPieces(board, currentField)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void movePawn(struct addMoveCtx_t ctx, uint_least8_t src, uint_least8_t dst,
|
static void movePawn(struct addMoveCtx_t ctx, bool color, uint_least8_t src, uint_least8_t dst,
|
||||||
bool promotion, uint_least8_t spezialMove) {
|
bool promotion, uint_least8_t spezialMove) {
|
||||||
struct piece_t *board = ctx.board;
|
uint_least64_t *board = ctx.board;
|
||||||
struct move_t *moves = ctx.moves;
|
struct move_t *moves = ctx.moves;
|
||||||
uint_least8_t *movesLength = ctx.movesLength;
|
uint_least8_t *movesLength = ctx.movesLength;
|
||||||
bool whiteToMove = board[src].white;
|
const struct piece_t piece = {PAWN, color};
|
||||||
if(promotion && (whiteToMove && dst < BOARD_SIZE || !whiteToMove && dst >= BOARD_SIZE * (BOARD_SIZE - 1))) {
|
if(promotion && (color == WHITE && dst < BOARD_SIZE || color == BLACK && dst >= BOARD_SIZE * (BOARD_SIZE - 1))) {
|
||||||
for(uint_least8_t promotionPiece = QUEEN; promotionPiece < PAWN; ++promotionPiece) {
|
for(uint_least8_t promotionPiece = QUEEN; promotionPiece < PAWN; ++promotionPiece) {
|
||||||
const struct move_t move = {src, dst, spezialMove, {promotionPiece, board[src].white}};
|
addMove(ctx, piece, src, dst, spezialMove); // always adds new move
|
||||||
moves[*movesLength] = move;
|
moves[*movesLength].dstPiece = promotionPiece;
|
||||||
++*movesLength;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const struct move_t move = {src, dst, spezialMove, {PAWN, board[src].white}};
|
addMove(ctx, piece, src, dst, spezialMove);
|
||||||
moves[*movesLength] = move;
|
|
||||||
++*movesLength;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint_least8_t pieceValidMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves,
|
uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece, uint_least8_t src,
|
||||||
uint_least8_t src, bool promotion) {
|
struct move_t *moves, bool promotion) {
|
||||||
struct piece_t *board = gameState.board;
|
uint_least64_t *board = gameState.board;
|
||||||
uint_least8_t movesLength = 0;
|
uint_least8_t movesLength = 0;
|
||||||
struct addMoveCtx_t addmoveCtx = {board, moves, &movesLength};
|
struct addMoveCtx_t addmoveCtx = {board, moves, &movesLength};
|
||||||
const uint_least8_t *localDirectionOffset = directionOffset + src * DIRECTION_LENGTH;
|
switch(piece.type) {
|
||||||
const struct piece_t piece = board[src];
|
case KING:
|
||||||
if(piece.type && piece.white == whiteToMove) {
|
{ // King
|
||||||
switch(piece.type) {
|
for(uint_least8_t direction = 0; direction < DIRECTION_LENGTH; ++direction) {
|
||||||
case KING:
|
if(getDirectionOffset(src, direction) >= 1) { // if sparen mit pre gen moves
|
||||||
{
|
addMove(addmoveCtx, piece, src, src + directionModifier[direction], 0);
|
||||||
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:
|
const struct castle_t canCastle = gameState.canCastle[piece.color];
|
||||||
moveSliding(MAIN_DIRECTION, LENGTH(MAIN_DIRECTION), addmoveCtx, src);
|
const uint_least64_t allPiecesMask = bitboardMaskAllPieces(board);
|
||||||
|
const uint_least8_t rankShift = piece.color == WHITE ? BOARD_SIZE * (BOARD_SIZE - 1) : 0;
|
||||||
|
const uint_least64_t shortCastleMask = (uint_least64_t)0b11 << (5 + rankShift);
|
||||||
|
const uint_least64_t longCastleMask = (uint_least64_t)0b111 << (1 + rankShift);
|
||||||
|
if(canCastle.shortCastle && !(allPiecesMask & shortCastleMask)) {
|
||||||
|
addMove(addmoveCtx, piece, src, src + 2 * directionModifier[EAST], SHORT_CASTLE);
|
||||||
|
}
|
||||||
|
if(canCastle.longCastle && !(allPiecesMask & longCastleMask)) {
|
||||||
|
addMove(addmoveCtx, piece, src, src + 2 * directionModifier[WEST], LONG_CASTLE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case BISHOP:
|
}
|
||||||
|
case ROOK:
|
||||||
|
moveSliding(MAIN_DIRECTION, LENGTH(MAIN_DIRECTION), addmoveCtx, src, piece);
|
||||||
|
break;
|
||||||
|
case BISHOP:
|
||||||
|
{
|
||||||
|
uint_least8_t direction[] = {NORTHWEST, SOUTHWEST, SOUTHEAST, NORTHEAST};
|
||||||
|
moveSliding(direction, LENGTH(direction), addmoveCtx, src, piece);
|
||||||
|
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, piece);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PAWN:
|
||||||
|
{
|
||||||
|
uint_least8_t pawnDirection = piece.color == WHITE ? NORTH : SOUTH;
|
||||||
{
|
{
|
||||||
uint_least8_t direction[] = {NORTHWEST, SOUTHWEST, SOUTHEAST, NORTHEAST};
|
uint_least8_t directions[] = {EAST, WEST};
|
||||||
moveSliding(direction, LENGTH(direction), addmoveCtx, src);
|
for(uint_least8_t j = 0; j < LENGTH(directions); ++j) {
|
||||||
break;
|
uint_least8_t dst = src + directionModifier[directions[j]] + directionModifier[pawnDirection];
|
||||||
}
|
if(getDirectionOffset(src, directions[j]) >= 1) {
|
||||||
case QUEEN:
|
const struct piece_t pieceOtherColor = {ALL_PIECES, !piece.color};
|
||||||
{
|
if(bitboardGet(board, pieceOtherColor, dst)) {
|
||||||
uint_least8_t direction[DIRECTION_LENGTH];
|
movePawn(addmoveCtx, piece.color, src, dst, promotion, 0);
|
||||||
for(uint_least8_t i = 0; i < DIRECTION_LENGTH; ++i) direction[i] = i;
|
}
|
||||||
moveSliding(direction, LENGTH(direction), addmoveCtx, src);
|
else if(dst == gameState.enPassantTo) {
|
||||||
break;
|
movePawn(addmoveCtx, piece.color, src, dst, promotion, EN_PASSANT);
|
||||||
}
|
|
||||||
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] = {
|
uint_least8_t dst = src + directionModifier[pawnDirection];
|
||||||
{SOUTH, EAST},
|
if(!bitboardGetAllPieces(board, dst)) {
|
||||||
{EAST, SOUTH},
|
movePawn(addmoveCtx, piece.color, src, dst, promotion, 0);
|
||||||
{SOUTH, WEST},
|
if(src / BOARD_SIZE == (piece.color == WHITE ? BOARD_SIZE - 2 : 1)) {
|
||||||
{WEST, SOUTH},
|
dst += directionModifier[pawnDirection];
|
||||||
{NORTH, WEST},
|
movePawn(addmoveCtx, piece.color, src, dst, promotion, FUTURE_EN_PASSANT);
|
||||||
{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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KNIGHT:
|
||||||
|
{
|
||||||
|
const uint_least8_t direction[] = {
|
||||||
|
SOUTH, EAST, // each line is a pair of directions
|
||||||
|
EAST, SOUTH,
|
||||||
|
SOUTH, WEST,
|
||||||
|
WEST, SOUTH,
|
||||||
|
NORTH, WEST,
|
||||||
|
WEST, NORTH,
|
||||||
|
NORTH, EAST,
|
||||||
|
EAST, NORTH
|
||||||
|
};
|
||||||
|
for(uint_least8_t i = 0; i < LENGTH(direction); i += 2) {
|
||||||
|
if(getDirectionOffset(src, direction[i]) >= 2 && getDirectionOffset(src, direction[i + 1])) {
|
||||||
|
addMove(addmoveCtx, piece, src,
|
||||||
|
src + 2 * directionModifier[direction[i]] + directionModifier[direction[i + 1]], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return movesLength;
|
return movesLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint_least8_t validMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves) {
|
uint_least8_t validMoves(struct gameState_t gameState, bool color, struct move_t *moves) {
|
||||||
uint_least8_t movesLength = 0;
|
uint_least8_t movesLength = 0;
|
||||||
for(uint_least8_t src = 0; src < TOTAL_BOARD_SIZE; ++src) {
|
for(uint_least8_t pieceType = KING; pieceType < PIECES_LENGTH; ++pieceType) {
|
||||||
movesLength += pieceValidMoves(gameState, whiteToMove, moves + movesLength, src, true);
|
const struct piece_t piece = {pieceType, color};
|
||||||
|
uint_least8_t field;
|
||||||
|
for(uint_least64_t pieceMask = bitboardGetMask(gameState.board, piece);
|
||||||
|
pieceMask != 0; pieceMask = bitsetClear(pieceMask, field)) {
|
||||||
|
field = trailingBits(pieceMask);
|
||||||
|
movesLength += pieceValidMoves(gameState, piece, field, moves + movesLength, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return movesLength;
|
return movesLength;
|
||||||
}
|
}
|
||||||
@ -207,51 +241,46 @@ static void setCastleInfo(struct castle_t *canCastle, uint_least8_t posOnRank) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gameState_t makeMove(struct gameState_t gameState, struct move_t move) {
|
struct gameState_t makeMove(struct gameState_t gameState, bool color, struct move_t move) {
|
||||||
struct piece_t *board = gameState.board;
|
uint_least64_t *board = gameState.board;
|
||||||
const struct piece_t noPiece = {NOTHING, false};
|
const uint_least8_t castleRankI[2] = {0, (BOARD_SIZE - 1) * BOARD_SIZE};
|
||||||
const bool whiteToMove = board[move.src].white;
|
const struct piece_t srcPiece = {move.srcPiece, color};
|
||||||
const bool otherPlayer = !whiteToMove;
|
const struct piece_t dstPiece = {move.dstPiece, color};
|
||||||
const uint_least8_t pieceType = board[move.src].type;
|
bitboardClear(board, srcPiece, move.src);
|
||||||
const uint_least8_t castleRankI[] = {0, (BOARD_SIZE - 1) * BOARD_SIZE};
|
bitboardSet(board, dstPiece, move.dst);
|
||||||
struct piece_t *castleRankPtr = board + castleRankI[whiteToMove];
|
if(move.capturedPiece != NOT_SELECTED) {
|
||||||
board[move.src] = noPiece;
|
const struct piece_t capturedPiece = {move.capturedPiece, !color};
|
||||||
board[move.dst] = move.dstPiece;
|
bitboardClear(board, capturedPiece, getCapturePos(move.src, move.dst, move.spezialMove));
|
||||||
switch(move.spezialMove) {
|
}
|
||||||
case EN_PASSANT:
|
if(move.spezialMove == SHORT_CASTLE || move.spezialMove == LONG_CASTLE) {
|
||||||
{
|
const uint_least8_t rookSrc = castleRankI[color] + (move.spezialMove == SHORT_CASTLE ? BOARD_SIZE - 1 : 0);
|
||||||
const uint_least8_t file = move.dst % 8;
|
const uint_least8_t rookDst = castleRankI[color] + (move.spezialMove == SHORT_CASTLE ? 5 : 3);
|
||||||
const uint_least8_t rank = move.src / 8;
|
const struct piece_t rook = {ROOK, color};
|
||||||
board[rank * BOARD_SIZE + file] = noPiece;
|
bitboardSet(board, rook, rookDst);
|
||||||
break;
|
bitboardClear(board, rook, rookSrc);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct castle_t *canCastleCurrentPlayer = gameState.canCastle + color;
|
||||||
|
if(canCastleCurrentPlayer->longCastle || canCastleCurrentPlayer->shortCastle) {
|
||||||
|
if(move.dstPiece == KING) {
|
||||||
|
canCastleCurrentPlayer->longCastle = false;
|
||||||
|
canCastleCurrentPlayer->shortCastle = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setCastleInfo(canCastleCurrentPlayer, move.src - castleRankI[color]);
|
||||||
}
|
}
|
||||||
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) {
|
// if the rook is captured
|
||||||
setCastleInfo(canCastle + otherPlayer, move.dst - castleRankI[otherPlayer]);
|
struct castle_t *canCastleOther = gameState.canCastle + !color;
|
||||||
|
if(canCastleOther->longCastle || canCastleOther->shortCastle) {
|
||||||
|
setCastleInfo(canCastleOther, move.dst - castleRankI[!color]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const int_least8_t dist = (int_least8_t)move.dst - (int_least8_t)move.src;
|
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)
|
gameState.enPassantTo = FUTURE_EN_PASSANT ? move.src + dist / 2 : NOT_SELECTED;
|
||||||
? move.src + dist / 2 : NOT_SELECTED;
|
|
||||||
}
|
}
|
||||||
++gameState.halfMoveCounter;
|
++gameState.halfMoveCounter;
|
||||||
return gameState;
|
return gameState;
|
||||||
@ -260,5 +289,5 @@ struct gameState_t makeMove(struct gameState_t gameState, struct move_t move) {
|
|||||||
struct gameState_t computerMove(struct gameState_t gameState) {
|
struct gameState_t computerMove(struct gameState_t gameState) {
|
||||||
struct move_t moves[MAX_VALID_MOVES];
|
struct move_t moves[MAX_VALID_MOVES];
|
||||||
validMoves(gameState, false, moves);
|
validMoves(gameState, false, moves);
|
||||||
return makeMove(gameState, moves[0]);
|
return makeMove(gameState, BLACK, moves[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/move.h
21
src/move.h
@ -9,8 +9,9 @@
|
|||||||
|
|
||||||
enum spezialMoves {
|
enum spezialMoves {
|
||||||
EN_PASSANT = 1,
|
EN_PASSANT = 1,
|
||||||
|
FUTURE_EN_PASSANT,
|
||||||
SHORT_CASTLE,
|
SHORT_CASTLE,
|
||||||
LONG_CASTLE
|
LONG_CASTLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct castle_t {
|
struct castle_t {
|
||||||
@ -19,17 +20,11 @@ struct castle_t {
|
|||||||
|
|
||||||
struct move_t {
|
struct move_t {
|
||||||
uint_least8_t src, dst, spezialMove;
|
uint_least8_t src, dst, spezialMove;
|
||||||
struct piece_t dstPiece;
|
uint_least8_t srcPiece, dstPiece, capturedPiece;
|
||||||
};
|
|
||||||
|
|
||||||
struct moveUndo_t {
|
|
||||||
uint_least8_t src, dst, enPassantTo;
|
|
||||||
struct castle_t canCastle;
|
|
||||||
struct piece_t srcPiece, capturedPiece;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gameState_t {
|
struct gameState_t {
|
||||||
struct piece_t *board;
|
uint_least64_t *board;
|
||||||
struct castle_t canCastle[2];
|
struct castle_t canCastle[2];
|
||||||
|
|
||||||
// The number of halfmoves since the last capture or pawn advance, used for the fifty-move rule.
|
// The number of halfmoves since the last capture or pawn advance, used for the fifty-move rule.
|
||||||
@ -38,11 +33,11 @@ struct gameState_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void genDirectionConsts();
|
void genDirectionConsts();
|
||||||
uint_least8_t validMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves);
|
uint_least8_t validMoves(struct gameState_t gameState, bool color, struct move_t *moves);
|
||||||
uint_least8_t pieceValidMoves(struct gameState_t gameState, bool whiteToMove, struct move_t *moves,
|
uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece, uint_least8_t src,
|
||||||
uint_least8_t src, bool promotion);
|
struct move_t *moves, bool promotion);
|
||||||
|
|
||||||
struct gameState_t makeMove(struct gameState_t gameState, struct move_t move);
|
struct gameState_t makeMove(struct gameState_t gameState, bool color, struct move_t move);
|
||||||
struct gameState_t computerMove(struct gameState_t gameState);
|
struct gameState_t computerMove(struct gameState_t gameState);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
12
src/types.h
12
src/types.h
@ -10,18 +10,24 @@
|
|||||||
#define NOT_SELECTED UINT_LEAST8_MAX
|
#define NOT_SELECTED UINT_LEAST8_MAX
|
||||||
|
|
||||||
enum pieces {
|
enum pieces {
|
||||||
NOTHING,
|
ALL_PIECES,
|
||||||
KING,
|
KING,
|
||||||
QUEEN,
|
QUEEN,
|
||||||
ROOK,
|
ROOK,
|
||||||
BISHOP,
|
BISHOP,
|
||||||
KNIGHT,
|
KNIGHT,
|
||||||
PAWN
|
PAWN,
|
||||||
|
PIECES_LENGTH
|
||||||
|
};
|
||||||
|
|
||||||
|
enum color {
|
||||||
|
BLACK,
|
||||||
|
WHITE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct piece_t {
|
struct piece_t {
|
||||||
uint_least8_t type;
|
uint_least8_t type;
|
||||||
bool white;
|
bool color;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user