62 lines
1.7 KiB
Python
62 lines
1.7 KiB
Python
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] |