132 lines
4.4 KiB
C
132 lines
4.4 KiB
C
#include <chess/types.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <stdint.h>
|
|
#include <chess/print.h>
|
|
#include <inttypes.h>
|
|
#include <assert.h>
|
|
#include <chess/magic.h>
|
|
#include <chess/generated/moveConsts.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, "{ 0, %" PRIuLEAST64 "u, %" PRIuLEAST64 "u, %" PRIuLEAST8 "}", magic.mask, magic.magicNumber, magic.shift);
|
|
}
|
|
|
|
|
|
static bool tryMagicNum(uint_least8_t field, struct magic_t *magic, uint_least64_t magicNumber,
|
|
const uint_least64_t *preClacAttack, const uint_least8_t *direction) {
|
|
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 pieceArrangement = 0;
|
|
size_t j = 0;
|
|
do {
|
|
const uint_least64_t i = (pieceArrangement * 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;
|
|
pieceArrangement = (pieceArrangement - magic->mask) & magic->mask;
|
|
++j;
|
|
} while(pieceArrangement != 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;
|
|
|
|
/* & 0x7e... because we dont care about the outer ring of pieces, because the pieces are threated as
|
|
enemy pieces. */
|
|
magic->mask = slidingMovementMask(direction, directionLength, field, 0) & 0x7e7e7e7e7e7e7e7e;
|
|
magic->shift = 64 - MAX_BITS - 1;
|
|
uint_least64_t pieceArrangement = 0;
|
|
size_t i = 0;
|
|
do {
|
|
attackMask[i] = slidingMovementMask(direction, directionLength, field, pieceArrangement);
|
|
pieceArrangement = (pieceArrangement - magic->mask) & magic->mask;
|
|
++i;
|
|
} while(pieceArrangement != 0);
|
|
}
|
|
|
|
int main() {
|
|
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, ROOK_DIRECTION, LENGTH(ROOK_DIRECTION));
|
|
initMagicField(bishopAttackMask, bishopMagicTable, field, BISHOP_DIRECTION, LENGTH(BISHOP_DIRECTION));
|
|
}
|
|
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, ROOK_DIRECTION);
|
|
}
|
|
{
|
|
struct magic_t *magic = bishopMagicTable + field;
|
|
isMagic |= tryMagicNum(field, magic, magicNumber, bishopAttackMask, BISHOP_DIRECTION);
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|