evaluation

This commit is contained in:
2024-03-24 16:53:44 +01:00
parent 84fad9abb8
commit 21de797d66
7 changed files with 144 additions and 11 deletions

View File

@ -26,7 +26,7 @@ uint_least8_t pieceValidMoves(struct gameState_t gameState, struct piece_t piece
void undoMove(uint_least64_t *board, struct move_t move, bool color);
struct gameState_t makeMove(struct gameState_t gameState, struct move_t move);
struct gameState_t computerMove(struct gameState_t gameState);
void initMagicTable();
bool kingInCheck(const uint_least64_t *board, const bool color);
#endif

View File

@ -28,3 +28,4 @@ void printerull(FILE *file, unsigned long long num);
void printPieceMask(uint_least64_t mask);
void fieldToString(uint_least8_t field, char *output);
void printMove(const struct move_t move);
void printMoveln(const struct move_t move);

100
src/chess/evaluate.c Normal file
View File

@ -0,0 +1,100 @@
#include "chess/move.h"
#include "chess/types.h"
#include <stdint.h>
#include <chess/bitboard.h>
#include <chess/print.h>
#include <stdio.h>
// These min and max values will not overflow, when negated
#define INT_16_SAFE_MIN (INT_LEAST16_MIN + 1)
#define INT_16_SAFE_MAX (INT_LEAST16_MAX - 1)
#ifdef __GNUC__ // Check if using GCC or compatible compiler
static int_least16_t countOnes(uint_least64_t num) {
return __builtin_popcountll(num); // Use GCC built-in function if available
}
#elif defined(_MSC_VER) // Check if using Microsoft Visual C++
#include <intrin.h>
static int_least16_t countOnes(uint_least64_t num) {
return __popcnt64(num); // Use MSVC intrinsic if available
}
#else
static int_least16_t countOnes(uint_least64_t num) {
int_least16_t count = 0;
while(num) {
count += num & 1;
num >>= 1;
}
return count;
}
#endif
static int_least16_t evaluate(const struct gameState_t gameState) {
int_least16_t value = 0;
const uint_least64_t *board = gameState.board;
int_least16_t pieceValues[PIECES_LENGTH];
pieceValues[PAWN] = 100;
pieceValues[KNIGHT] = 300;
pieceValues[BISHOP] = 310;
pieceValues[QUEEN] = 900;
pieceValues[ROOK] = 500;
for(uint_least8_t pieceType = QUEEN; pieceType < PIECES_LENGTH; ++pieceType) {
for(uint_least8_t color = BLACK; color <= WHITE; ++color) {
const struct piece_t piece = {pieceType, color};
const int_least16_t sign = color == gameState.color ? 1 : -1;
value += sign * countOnes(bitboardGetMask(board, piece)) * pieceValues[pieceType];
}
}
return value;
}
static int_least16_t alphaBeta(const struct gameState_t gameState, int_fast16_t alpha,
int_least16_t beta, uint_least8_t depth) {
if(depth == 0) return evaluate(gameState);
struct move_t moves[MAX_VALID_MOVES];
uint_least8_t movesLength = validMoves(gameState, moves);
if(movesLength == 0) {
if(kingInCheck(gameState.board, gameState.color)) {
return INT_16_SAFE_MIN + 1;
}
return 0;
}
for(uint_least8_t i = 0; i < movesLength; ++i) {
const struct move_t move = moves[i];
const struct gameState_t newGameState = makeMove(gameState, move);
const int_least16_t score = -alphaBeta(newGameState, -beta, -alpha, depth - 1);
undoMove(gameState.board, move, gameState.color);
if(score >= beta) {
return beta; // beta-cutoff
}
if(score > alpha) {
alpha = score; // alpha acts like max in MiniMax
}
}
return alpha;
}
static struct move_t searchRoot(const struct gameState_t gameState, uint_least8_t depth) {
struct move_t moves[MAX_VALID_MOVES];
uint_least8_t movesLength = validMoves(gameState, moves);
int_least16_t alpha = INT_16_SAFE_MIN;
int_least16_t beta = INT_16_SAFE_MAX;
struct move_t selectedMove;
for(uint_least8_t i = 0; i < movesLength; ++i) {
const struct move_t move = moves[i];
const struct gameState_t newGameState = makeMove(gameState, move);
const int_least16_t score = -alphaBeta(newGameState, -beta, -alpha, depth - 1);
undoMove(gameState.board, move, gameState.color);
if(score > alpha) {
alpha = score; // alpha acts like max in MiniMax
selectedMove = move;
}
}
return selectedMove;
}
struct move_t bestMove(const struct gameState_t gameState) {
const uint_least8_t depth = 6;
return searchRoot(gameState, depth);
}

8
src/chess/evaluate.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef CHESS_EVALUATE_H
#define CHESS_EVALUATE_H
#include <chess/types.h>
struct move_t bestMove(const struct gameState_t gameState);
#endif

View File

@ -9,6 +9,7 @@
#include <chess/types.h>
#include <chess/move.h>
#include <chess/bitboard.h>
#include "evaluate.h"
#define drawPiece(file, rank, piece) do { \
const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\
@ -49,7 +50,8 @@ static struct gameState_t userMove(struct gameState_t gameState, struct move_t m
#ifdef NO_COMPUTER
turn = !turn;
#else
gameState = computerMove(gameState);
move = bestMove(gameState);
gameState = makeMove(gameState, move);
#endif
return gameState;
}

View File

@ -10,7 +10,9 @@
#include "magicNumber.h"
#include <chess/magic.h>
#define trailingBits(num) __builtin_ctzll(num)
#ifdef _MSC_VER
#include <intrin.h>
#endif
struct addMoveCtx_t {
struct gameState_t gameState;
@ -20,6 +22,23 @@ struct addMoveCtx_t {
const static uint_least8_t MAIN_DIRECTION[] = {NORTH, WEST, EAST, SOUTH};
static uint_least8_t trailingBits(uint_least64_t num) {
#ifdef __GNUC__
return __builtin_ctzll(num);
#elif defined(_MSC_VER)
unsigned long i;
_BitScanForward(&i, num);
return i;
#elif
uint_least8_t count = 0;
while ((num & 1) == 0) { // Keep shifting num right until the least significant bit is 1
num >>= 1;
count++;
}
return count;
#endif
}
static uint_least8_t getDirectionOffset(uint_least8_t field, uint_least8_t direction) {
defineDirectionOffset;
return DIRECTION_OFFSET[field * DIRECTION_LENGTH + direction];
@ -109,6 +128,11 @@ static bool inCheck(const uint_least64_t *board, const uint_least64_t kingMask,
checkMagic(board, queen, rookMagic, kingMask) || checkMagic(board, queen, bishopMagic, kingMask);
}
bool kingInCheck(const uint_least64_t *board, const bool color) {
const struct piece_t king = {KING, color};
return inCheck(board, bitboardGetMask(board, king), color);
}
static uint_least8_t getCastleRankI(bool color) {
if(color == WHITE) {
return (BOARD_SIZE - 1) * BOARD_SIZE;
@ -163,8 +187,7 @@ static void addMove(struct addMoveCtx_t ctx, struct piece_t movedPiece, uint_lea
makeMove(ctx.gameState, move);
{
const bool color = ctx.gameState.color;
const struct piece_t king = {KING, color};
if(!inCheck(board, bitboardGetMask(board, king), color)) {
if(!kingInCheck(board, color)) {
ctx.moves[*movesLength] = move;
++*movesLength;
}
@ -360,9 +383,3 @@ struct gameState_t makeMove(struct gameState_t gameState, struct move_t move) {
gameState.color = !gameState.color;
return gameState;
}
struct gameState_t computerMove(struct gameState_t gameState) {
struct move_t moves[MAX_VALID_MOVES];
validMoves(gameState, moves);
return makeMove(gameState, moves[0]);
}

View File

@ -53,3 +53,8 @@ void printMove(const struct move_t move) {
printf("%c", piece);
}
}
void printMoveln(const struct move_t move) {
printMove(move);
printf("\n");
}