Add some basic algorithms and eval functions for an AI
All checks were successful
Python tests (make) / test (push) Successful in 11s

This commit is contained in:
2025-08-23 13:10:05 -04:00
parent 60a987a7a1
commit 4fc982eac2
6 changed files with 409 additions and 21 deletions

62
scripts/evaluation.py Normal file
View File

@@ -0,0 +1,62 @@
import random
import ctypes as C
from binding.python_c_ffi import ChessFFI
from binding.python_c_ffi import Move
class BaseEvaluation:
def __init__(self, chess_ffi=None):
if chess_ffi is None:
chess_ffi = ChessFFI()
self.chess_ffi = chess_ffi
def get_best_move(self, board, legal_moves):
pass
"""
We will use a random move evaluation as our base AI. This
is expected to be the worst performing strategy. We can
play our other AI evaluation methods against this one to
confirm if our other strategies are at least better than
a simplistic approach.
"""
class RandomEval(BaseEvaluation):
def __init__(self, chess_ffi=None):
super().__init__(chess_ffi)
def get_best_move(self, board, legal_moves):
return random.choice(legal_moves)
class NegaMaxEval(BaseEvaluation):
def __init__(self, depth=6, cp_window=20, chess_ffi=None):
super().__init__(chess_ffi)
self.depth = depth
self.window = cp_window
def _same(self, a, b):
return (int(getattr(a, "from")) == int(getattr(b, "from"))
and int(a.to) == int(b.to)
and int(getattr(a, "promo", 0) or 0) == int(getattr(b, "promo", 0) or 0))
def get_best_move(self, board, legal_moves):
if not legal_moves:
raise RuntimeError("No legal moves")
best = Move()
ok = self.chess_ffi._c_ai_find_best_move_with_window(
board,
self.depth,
self.window,
best
)
if ok:
for m in legal_moves:
if self._same(m, best):
return m
return legal_moves[0]