gen magic Number
This commit is contained in:
@ -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)
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
# chess
|
||||
|
||||
A chess engine
|
||||
A chess engine
|
||||
|
||||
# sources
|
||||
|
||||
https://www.chessprogramming.org/Magic_Bitboards
|
||||
https://www.chessprogramming.org/Looking_for_Magics
|
||||
|
||||
25
include/chess/print.h
Normal file
25
include/chess/print.h
Normal file
@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
@ -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
|
||||
|
||||
1
lib/acl
1
lib/acl
Submodule lib/acl deleted from a83de1b97b
9
lib/chess/print.c
Normal file
9
lib/chess/print.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void printerll(FILE *file, long long num) {
|
||||
fprintf(file, "%lld", num);
|
||||
}
|
||||
|
||||
void printerull(FILE *file, unsigned long long num) {
|
||||
fprintf(file, "%lluu", num);
|
||||
}
|
||||
@ -10,12 +10,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <chess/types.h>
|
||||
#include "move.h"
|
||||
#include "bitboard.h"
|
||||
#include <chess/bitboard.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
#include <stdint.h>
|
||||
#include <chess/types.h>
|
||||
#include "move.h"
|
||||
#include "bitboard.h"
|
||||
#include "generated/directionConsts.h"
|
||||
#include <chess/bitboard.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
145
src/findMagicNumber.c
Normal file
145
src/findMagicNumber.c
Normal file
@ -0,0 +1,145 @@
|
||||
#include <chess/types.h>
|
||||
#include <bits/stdint-least.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include "chess/generated/moveConsts.h"
|
||||
#include <chess/bitboard.h>
|
||||
#include <chess/print.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 <chess/types.h>\n");
|
||||
fdefineArray(file, "static struct magic_t rookMagic", printerMagic, rookMagicTable);
|
||||
fdefineArray(file, "static struct magic_t bishopMagic", printerMagic, bishopMagicTable);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <chess/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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 <stdint.h>\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");
|
||||
}
|
||||
126
src/generateCode/moveConsts.c
Normal file
126
src/generateCode/moveConsts.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include <stdio.h>
|
||||
#include <chess/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <chess/bitboard.h>
|
||||
#include <chess/print.h>
|
||||
|
||||
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 <stdint.h>\n"
|
||||
"#include <chess/types.h>\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");
|
||||
}
|
||||
Reference in New Issue
Block a user