diff --git a/CMakeLists.txt b/CMakeLists.txt index b31f680..f97b3d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,21 +2,26 @@ cmake_minimum_required(VERSION 3.18) project(chess C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include_directories(include) +file(GLOB SOURCES "src/chess/*.c") +file(GLOB LIB_SOURCES "lib/chess/*.c") -add_executable(genDirectionConsts src/generateCode/directionConsts.c) +add_executable(genMoveConsts src/generateCode/moveConsts.c ${LIB_SOURCES}) add_custom_command( - OUTPUT directionConsts.h # Output file from code generation - COMMAND genDirectionConsts > src/chess/generated/directionConsts.h - DEPENDS genDirectionConsts # Depends on the code generation executable + OUTPUT moveConsts.h # Output file from code generation + COMMAND genMoveConsts > src/chess/generated/moveConsts.h + DEPENDS genMoveConsts # Depends on the code generation executable ) -add_custom_target(generateCode DEPENDS directionConsts.h) +add_custom_target(generateCode DEPENDS moveConsts.h) find_package(PkgConfig REQUIRED) pkg_check_modules(GTK4 REQUIRED IMPORTED_TARGET gtk4) pkg_check_modules(LIBRSVG REQUIRED IMPORTED_TARGET librsvg-2.0) -file(GLOB SOURCES "src/chess/*.c") -add_executable(${PROJECT_NAME} ${SOURCES}) +add_executable(findMagicNumber src/findMagicNumber.c ${LIB_SOURCES}) +add_dependencies(findMagicNumber generateCode) + +add_executable(${PROJECT_NAME} ${SOURCES} ${LIB_SOURCES}) +set_property(TARGET findMagicNumber PROPERTY C_STANDARD 99) set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG) add_dependencies(${PROJECT_NAME} generateCode) @@ -32,7 +37,7 @@ if(CMAKE_BUILD_TYPE MATCHES "Release") endif() endif() -add_executable(chessNoComputer ${SOURCES}) +add_executable(chessNoComputer ${SOURCES} ${LIB_SOURCES}) set_property(TARGET chessNoComputer PROPERTY C_STANDARD 99) target_link_libraries(chessNoComputer PRIVATE PkgConfig::GTK4 PkgConfig::LIBRSVG) add_dependencies(chessNoComputer generateCode) diff --git a/README.md b/README.md index f82f3d3..d936efd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ # chess -A chess engine \ No newline at end of file +A chess engine + +# sources + +https://www.chessprogramming.org/Magic_Bitboards +https://www.chessprogramming.org/Looking_for_Magics diff --git a/src/chess/bitboard.h b/include/chess/bitboard.h similarity index 100% rename from src/chess/bitboard.h rename to include/chess/bitboard.h diff --git a/include/chess/print.h b/include/chess/print.h new file mode 100644 index 0000000..95e8d6f --- /dev/null +++ b/include/chess/print.h @@ -0,0 +1,25 @@ +#include + +#define fprintArray(file, printer, arr) \ + do { \ + fprintf(file, "{"); \ + for(size_t i = 0; i < LENGTH(arr); ++i) { \ + printer(file, arr[i]); \ + if (i < LENGTH(arr) - 1) { \ + fprintf(file, ", "); \ + } \ + } \ + fprintf(file, " }"); \ + } while(0) + +#define fdefineArray(file, declaration, printer, arr) \ + do { \ + fprintf(file, "%s[%zu] = ", declaration, LENGTH(arr)); \ + fprintArray(file, printer, arr); \ + fprintf(file, ";\n"); \ + } while(0) + +#define defineArray(declaration, printer, arr) fdefineArray(stdout, declaration, printer, arr) + +void printerll(FILE *file, long long num); +void printerull(FILE *file, unsigned long long num); diff --git a/include/chess/types.h b/include/chess/types.h index f0c68a9..c27a3c5 100644 --- a/include/chess/types.h +++ b/include/chess/types.h @@ -34,4 +34,16 @@ enum directions { NORTH, NORTHWEST, WEST, SOUTHWEST, SOUTH, SOUTHEAST, EAST, NORTHEAST, DIRECTION_LENGTH }; +struct moveDst_t { + uint_least8_t length; + uint_least8_t dst[8]; +}; + +struct magic_t { + uint_least64_t *attackTable; + uint_least64_t mask; // mask for relvant squares + uint_least64_t magicNumber; + uint_least8_t shift; +}; + #endif diff --git a/lib/acl b/lib/acl deleted file mode 160000 index a83de1b..0000000 --- a/lib/acl +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a83de1b97b4c58b09696c62a53d446763b21bb50 diff --git a/src/chess/bitboard.c b/lib/chess/bitboard.c similarity index 100% rename from src/chess/bitboard.c rename to lib/chess/bitboard.c diff --git a/lib/chess/print.c b/lib/chess/print.c new file mode 100644 index 0000000..0db07b4 --- /dev/null +++ b/lib/chess/print.c @@ -0,0 +1,9 @@ +#include + +void printerll(FILE *file, long long num) { + fprintf(file, "%lld", num); +} + +void printerull(FILE *file, unsigned long long num) { + fprintf(file, "%lluu", num); +} diff --git a/src/chess/main.c b/src/chess/main.c index 6744213..fa3471a 100644 --- a/src/chess/main.c +++ b/src/chess/main.c @@ -10,12 +10,12 @@ #include #include #include "move.h" -#include "bitboard.h" +#include -#define drawPiece(file, rank, piece) { \ +#define drawPiece(file, rank, piece) do { \ const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\ rsvg_handle_render_document(piecesSvg[pieceToSvgI(piece)], cr, &rect, NULL); \ -} +} while(0) struct drawData_t { RsvgHandle **piecesSvg; @@ -101,7 +101,7 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height, 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) + drawPiece(uiPos + i, 0, piece); } } } diff --git a/src/chess/move.c b/src/chess/move.c index 4579d3d..4b3d192 100644 --- a/src/chess/move.c +++ b/src/chess/move.c @@ -3,8 +3,8 @@ #include #include #include "move.h" -#include "bitboard.h" -#include "generated/directionConsts.h" +#include +#include "generated/moveConsts.h" #define trailingBits(num) __builtin_ctzll(num) @@ -17,7 +17,8 @@ struct addMoveCtx_t { const static uint_least8_t MAIN_DIRECTION[] = {NORTH, WEST, EAST, SOUTH}; static uint_least8_t getDirectionOffset(uint_least8_t field, uint_least8_t direction) { - return directionOffset[field * DIRECTION_LENGTH + direction]; + defineDirectionOffset; + return DIRECTION_OFFSET[field * DIRECTION_LENGTH + direction]; } static uint_least8_t getCapturePos(uint_least8_t src, uint_least8_t dst, uint_least8_t spezialMove) { @@ -27,7 +28,16 @@ static uint_least8_t getCapturePos(uint_least8_t src, uint_least8_t dst, uint_le return rank * BOARD_SIZE + file; } -static bool inCheck(uint_least64_t *board, uint_least8_t field) { +static bool inCheck(uint_least64_t *board, uint_least8_t field, bool color) { + defineKnightCheck; + defineKingCheck; + definePawnCheck; + const struct piece_t knight = {KNIGHT, !color}; + const struct piece_t pawn = {PAWN, !color}; + const struct piece_t king = {KING, !color}; + return bitboardGetMask(board, knight) & KNIGHT_CHECK[field] || + bitboardGetMask(board, pawn) & PAWN_CHECK[2 * field + color] || + bitboardGetMask(board, king) & KING_CHECK[field]; } static void addMove(struct addMoveCtx_t ctx, struct piece_t movedPiece, uint_least8_t src, @@ -35,6 +45,8 @@ static void addMove(struct addMoveCtx_t ctx, struct piece_t movedPiece, uint_lea uint_least64_t *board = ctx.board; uint_least8_t *movesLength = ctx.movesLength; uint_least8_t capturedPiece = NOT_SELECTED; + const struct piece_t pieceAll = {ALL_PIECES, movedPiece.color}; + if(bitboardGet(board, pieceAll, dst)) return; { const struct piece_t pieceAllOtherColor = {ALL_PIECES, !movedPiece.color}; const uint_least8_t capturePos = getCapturePos(src, dst, spezialMove); @@ -49,21 +61,27 @@ static void addMove(struct addMoveCtx_t ctx, struct piece_t movedPiece, uint_lea } } 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; ++*movesLength; return; } +static void addPreGenMoves(struct addMoveCtx_t ctx, const struct moveDst_t *moveDst, + uint_least8_t src, struct piece_t piece) { + const struct moveDst_t moveDstField = moveDst[src]; + for(uint_least8_t i = 0; i < moveDstField.length; ++i) { + addMove(ctx, piece, src, moveDstField.dst[i], 0); + } +} + static void moveSliding(const uint_least8_t *direction, uint_least8_t directionLength, struct addMoveCtx_t ctx, uint_least8_t field, struct piece_t movedPiece) { uint_least64_t *board = ctx.board; for(uint_least8_t j = 0; j < directionLength; ++j) { - const int_least8_t modifier = directionModifier[direction[j]]; + const int_least8_t modifier = DIRECTION_MODIFIER[direction[j]]; for(uint_least8_t currentField = field + modifier, i = 0; - i < directionOffset[field * DIRECTION_LENGTH + direction[j]]; ++i, currentField += modifier) { + i < getDirectionOffset(field, direction[j]); ++i, currentField += modifier) { addMove(ctx, movedPiece, field, currentField, 0); if(bitboardGetAllPieces(board, currentField)) { // ziehe die info wo das nächste piece steht // über bit ops? @@ -97,22 +115,19 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece struct addMoveCtx_t addmoveCtx = {board, moves, &movesLength}; switch(piece.type) { case KING: - { // King - for(uint_least8_t direction = 0; direction < DIRECTION_LENGTH; ++direction) { - if(getDirectionOffset(src, direction) >= 1) { // if sparen mit pre gen moves - addMove(addmoveCtx, piece, src, src + directionModifier[direction], 0); - } - } + { + defineKingMoves; + addPreGenMoves(addmoveCtx, KING_MOVES, src, piece); const struct castle_t canCastle = gameState.canCastle[piece.color]; 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); + addMove(addmoveCtx, piece, src, src + 2 * DIRECTION_MODIFIER[EAST], SHORT_CASTLE); } if(canCastle.longCastle && !(allPiecesMask & longCastleMask)) { - addMove(addmoveCtx, piece, src, src + 2 * directionModifier[WEST], LONG_CASTLE); + addMove(addmoveCtx, piece, src, src + 2 * DIRECTION_MODIFIER[WEST], LONG_CASTLE); } break; } @@ -138,7 +153,7 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece { 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]; + uint_least8_t dst = src + DIRECTION_MODIFIER[directions[j]] + DIRECTION_MODIFIER[pawnDirection]; if(getDirectionOffset(src, directions[j]) >= 1) { const struct piece_t pieceOtherColor = {ALL_PIECES, !piece.color}; if(bitboardGet(board, pieceOtherColor, dst)) { @@ -151,11 +166,11 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece } } { - uint_least8_t dst = src + directionModifier[pawnDirection]; + uint_least8_t dst = src + DIRECTION_MODIFIER[pawnDirection]; if(!bitboardGetAllPieces(board, dst)) { movePawn(addmoveCtx, piece.color, src, dst, promotion, 0); if(src / BOARD_SIZE == (piece.color == WHITE ? BOARD_SIZE - 2 : 1)) { - dst += directionModifier[pawnDirection]; + dst += DIRECTION_MODIFIER[pawnDirection]; movePawn(addmoveCtx, piece.color, src, dst, promotion, FUTURE_EN_PASSANT); } } @@ -164,22 +179,8 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece } 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); - } - } + defineKnightMoves; + addPreGenMoves(addmoveCtx, KNIGHT_MOVES, src, piece); break; } } diff --git a/src/findMagicNumber.c b/src/findMagicNumber.c new file mode 100644 index 0000000..78464f1 --- /dev/null +++ b/src/findMagicNumber.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include "chess/generated/moveConsts.h" +#include +#include +#include + +#define MAX_BITS 12 +#define MAX_SIZE (1 << MAX_BITS) +#define ATTACK_TABLE_LENGTH (2 * MAX_SIZE * TOTAL_BOARD_SIZE) + +static uint_least64_t rand_64() { + uint_least64_t u1, u2, u3, u4; + u1 = (uint_least64_t)(rand()) & 0xFFFF; u2 = (uint_least64_t)(rand()) & 0xFFFF; + u3 = (uint_least64_t)(rand()) & 0xFFFF; u4 = (uint_least64_t)(rand()) & 0xFFFF; + return u1 | (u2 << 16) | (u3 << 32) | (u4 << 48); +} + +static uint_least64_t randFewBits() { + return rand_64() & rand_64() & rand_64(); +} + +static uint_least8_t countOnes(uint_least64_t n) { + int count = 0; + while (n != 0) { + n = n & (n - 1); + count++; + } + return count; +} + +static void printerMagic(FILE *file, struct magic_t magic) { + fprintf(file, "{ NULL, %" PRIuLEAST64 ", %" PRIuLEAST64 ", %" PRIuLEAST8 "}", magic.mask, magic.magicNumber, magic.shift); +} + +static uint_least64_t slidingMovementMask(const uint_least8_t *direction, uint_least8_t directionLength, + uint_least8_t field, uint_least64_t blockMask) { + defineDirectionOffset; + const uint_least8_t *localDirectionOffset = DIRECTION_OFFSET + field * DIRECTION_LENGTH; + uint_least64_t movementMask = 0; + for(uint_least8_t j = 0; j < directionLength; ++j) { + const int_least8_t modifier = DIRECTION_MODIFIER[direction[j]]; + for(uint_least8_t currentField = field + modifier, i = 0; + i < localDirectionOffset[direction[j]]; ++i, currentField += modifier) { + movementMask = bitsetSet(movementMask, currentField); + if(bitsetGet(blockMask, currentField)) break; + } + } + return movementMask; +} + +static bool tryMagicNum(uint_least8_t field, struct magic_t *magic, uint_least64_t magicNumber, + const uint_least64_t *preClacAttack) { + preClacAttack += field * MAX_SIZE; + bool usedMagic = false; + if(countOnes((magic->mask * magicNumber) & 0xFF00000000000000ULL) < 6) return false; + for(uint_least8_t shift = magic->shift + 1;; ++shift) { + uint_least64_t attackTable[MAX_SIZE]; + for(size_t i = 0; i < LENGTH(attackTable); ++i) { + attackTable[i] = UINT_LEAST64_MAX; + } + bool validMagic = true; + uint_least64_t pieceArangement = 0; + size_t j = 0; + do { + const uint_least32_t i = (pieceArangement * magicNumber) >> shift; + const uint_least64_t storedAttack = attackTable[i]; + const uint_least64_t calcAttack = preClacAttack[j]; + if(storedAttack != UINT_LEAST64_MAX && storedAttack != calcAttack) { + validMagic = false; + break; + } + attackTable[i] = calcAttack; + pieceArangement = (pieceArangement - magic->mask) & magic->mask; + ++j; + } while(pieceArangement != 0); + if(validMagic) { + magic->shift = shift; + magic->magicNumber = magicNumber; + usedMagic = true; + } + else break; + } + return usedMagic; +} + +static void initMagicField(uint_least64_t *attackMask, struct magic_t *magicTable, uint_least8_t field, + const uint_least8_t *direction, uint_least8_t directionLength) { + struct magic_t *magic = magicTable + field; + attackMask += field * MAX_SIZE; + magic->mask = slidingMovementMask(direction, directionLength, field, 0); + magic->shift = 64 - MAX_BITS - 1; + uint_least64_t pieceArangement = 0; + size_t i = 0; + do { + attackMask[i] = slidingMovementMask(direction, directionLength, field, pieceArangement); + pieceArangement = (pieceArangement - magic->mask) & magic->mask; + ++i; + } while(pieceArangement != 0); +} + +int main() { + const uint_least8_t rookDirection[] = {NORTH, SOUTH, EAST, WEST}; + const uint_least8_t bishopDirection[] = {NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST}; + struct magic_t rookMagicTable[TOTAL_BOARD_SIZE] = {}; + struct magic_t bishopMagicTable[TOTAL_BOARD_SIZE] = {}; + uint_least64_t *attackMask = malloc(ATTACK_TABLE_LENGTH * sizeof *attackMask); + uint_least64_t *rookAttackMask = attackMask; + uint_least64_t *bishopAttackMask = attackMask + TOTAL_BOARD_SIZE * MAX_SIZE; + for(uint_least8_t field = 0; field < TOTAL_BOARD_SIZE; ++field) { + initMagicField(rookAttackMask, rookMagicTable, field, rookDirection, LENGTH(rookDirection)); + initMagicField(bishopAttackMask, bishopMagicTable, field, bishopDirection, LENGTH(bishopDirection)); + } + srand(time(NULL)); + for(;;) { + uint_least64_t magicNumber = randFewBits(); + bool isMagic = false; + for(uint_least8_t field = 0; field < TOTAL_BOARD_SIZE; ++field) { + { + struct magic_t *magic = rookMagicTable + field; + isMagic |= tryMagicNum(field, magic, magicNumber, rookAttackMask); + } + { + struct magic_t *magic = bishopMagicTable + field; + isMagic |= tryMagicNum(field, magic, magicNumber, bishopAttackMask); + } + } + if(isMagic) { + FILE *file = fopen("src/chess/magicNumber.h", "w"); + if (file == NULL) { + perror("Error opening file"); + return 1; + } + fprintf(file, "#include \n"); + fdefineArray(file, "static struct magic_t rookMagic", printerMagic, rookMagicTable); + fdefineArray(file, "static struct magic_t bishopMagic", printerMagic, bishopMagicTable); + fclose(file); + } + } +} diff --git a/src/generateCode/directionConsts.c b/src/generateCode/directionConsts.c deleted file mode 100644 index b187bb7..0000000 --- a/src/generateCode/directionConsts.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include - -static void defineArray(const char *declaration, long long arr[], size_t size) { - printf("%s[%zu] = { ", declaration, size); - for (int i = 0; i < size; ++i) { - printf("%lld", arr[i]); - if (i < size - 1) { - printf(", "); - } - } - printf(" };\n"); -} - -static long long min(long long a, long long b) { - return a < b ? a : b; -} - -int main() { - printf("#ifndef CHESS_GENERATED_DIRECTION_CONSTS_H\n" - "#define CHESS_GENERATED_DIRECTION_CONSTS_H\n" - "#include \n"); - { - long long directionOffset[TOTAL_BOARD_SIZE * DIRECTION_LENGTH]; - 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; - long long *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]); - } - defineArray("const static uint_least8_t directionOffset", directionOffset, LENGTH(directionOffset)); - } - { - long long directionModifier[DIRECTION_LENGTH]; - 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]; - defineArray("const static uint_least8_t directionModifier", directionModifier, LENGTH(directionModifier)); - } - printf("#endif\n"); -} diff --git a/src/generateCode/moveConsts.c b/src/generateCode/moveConsts.c new file mode 100644 index 0000000..9854dcd --- /dev/null +++ b/src/generateCode/moveConsts.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include + +static void printerMoveDst(FILE *file, struct moveDst_t moveDst) { + fprintf(file, "{ %" PRIuLEAST8 ", ", moveDst.length); + fprintArray(file, printerull, moveDst.dst); + fprintf(file, "}"); +} + +static long long min(long long a, long long b) { + return a < b ? a : b; +} + +static void genCheckMask(const struct moveDst_t *moveDst, uint_least64_t *checkMask) { + for(uint_least8_t i = 0; i < TOTAL_BOARD_SIZE; ++i) { + uint_least64_t mask = 0; + const uint_least8_t *dst = moveDst[i].dst; + for(uint_least8_t j = 0; j < moveDst[i].length; ++j) { + mask = bitsetSet(mask, j); + } + checkMask[i] = mask; + } +} + +int main() { + printf("#ifndef CHESS_GENERATED_MOVE_CONSTS_H\n" + "#define CHESS_GENERATED_MOVE_CONSTS_H\n" + "#include \n" + "#include \n"); + uint_least8_t directionOffset[TOTAL_BOARD_SIZE * DIRECTION_LENGTH]; + 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]); + } + defineArray("#define defineDirectionOffset const uint_least8_t DIRECTION_OFFSET", printerull, directionOffset); + int_least8_t directionModifier[DIRECTION_LENGTH]; + 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]; + defineArray("const int_least8_t DIRECTION_MODIFIER", printerll, directionModifier); + { + uint_least64_t knightCheck[TOTAL_BOARD_SIZE]; + struct moveDst_t knightMoves[TOTAL_BOARD_SIZE] = {}; + for(uint_least8_t file = 0; file < BOARD_SIZE; ++file) { + for(uint_least8_t rank = 0; rank < BOARD_SIZE; ++rank) { + uint_least8_t field = rank * BOARD_SIZE + file; + const uint_least8_t *offsetField = directionOffset + field * DIRECTION_LENGTH; + 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 + }; + struct moveDst_t *moveDst = knightMoves + field; + for(uint_least8_t i = 0; i < LENGTH(direction); i += 2) { + if(offsetField[direction[i]] >= 2 && offsetField[direction[i + 1]] >= 1) { + const uint_least8_t dst = field + 2 * directionModifier[direction[i]] + directionModifier[direction[i + 1]]; + moveDst->dst[moveDst->length++] = dst; + } + } + } + } + genCheckMask(knightMoves, knightCheck); + defineArray("#define defineKnightCheck const uint_least64_t KNIGHT_CHECK", printerull, knightCheck); + defineArray("#define defineKnightMoves const struct moveDst_t KNIGHT_MOVES", printerMoveDst, knightMoves); + } + { + uint_least64_t kingCheck[TOTAL_BOARD_SIZE]; + struct moveDst_t kingMoves[TOTAL_BOARD_SIZE] = {}; + for(uint_least8_t field = 0; field < TOTAL_BOARD_SIZE; ++field) { + struct moveDst_t *moveDst = kingMoves + field; + for(uint_least8_t direction = 0; direction < DIRECTION_LENGTH; ++direction) { + if(directionOffset[field * DIRECTION_LENGTH + direction] >= 1) { + moveDst->dst[moveDst->length++] = field + directionModifier[direction]; + } + } + } + genCheckMask(kingMoves, kingCheck); + defineArray("#define defineKingCheck const uint_least64_t KING_CHECK", printerull, kingCheck); + defineArray("#define defineKingMoves const struct moveDst_t KING_MOVES", printerMoveDst, kingMoves); + } + { + uint_least64_t pawnCheck[2 * TOTAL_BOARD_SIZE]; + for(uint_least8_t field = 0; field < TOTAL_BOARD_SIZE; ++field) { + for(uint_least8_t color = BLACK; color <= WHITE; ++color) { + const uint_least8_t pawnDirection = color == WHITE ? NORTH : SOUTH; + const uint_least8_t *fieldDirectionOffset = directionOffset + field * DIRECTION_LENGTH; + uint_least64_t checkMask = 0; + if(fieldDirectionOffset[pawnDirection] == 0) continue; + const uint_least8_t directions[] = {EAST, WEST}; + for(uint_least8_t j = 0; j < LENGTH(directions); ++j) { + uint_least8_t dst = field + directionModifier[directions[j]] + directionModifier[pawnDirection]; + if(fieldDirectionOffset[directions[j]] >= 1) { + checkMask = bitsetSet(checkMask, dst); + } + } + pawnCheck[2 * field + color] = checkMask; + } + } + defineArray("#define definePawnCheck const uint_least64_t PAWN_CHECK", printerull, pawnCheck); + } + printf("#endif\n"); +}