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]