diff --git a/binding/python_c_ffi.py b/binding/python_c_ffi.py index 0394b37..dcc1dc8 100644 --- a/binding/python_c_ffi.py +++ b/binding/python_c_ffi.py @@ -92,6 +92,14 @@ def sq(name): return f + 8 * r +def popcount(x): + return x.bit_count() + + +def get_rank_mask(rank): + return sum(1 << (rank*8 + f) for f in range(8)) + + class ChessFFI: def __init__(self): self.lib_path = "./build/libchess.so" @@ -130,10 +138,6 @@ class ChessFFI: def attackers_to(self, board, sq, by): return self._c_attackers_to(board, sq, by) - - - def popcount(self, x): - return x.bit_count() def _load_lib(self): diff --git a/makefile b/makefile index 4c0d37e..3e21820 100644 --- a/makefile +++ b/makefile @@ -55,4 +55,4 @@ test: @python3 -m unittest -v; \ status=$$?; \ $(MAKE) clean; \ - exit $$status + exit $$status \ No newline at end of file diff --git a/test/base.py b/test/base.py index 9815980..496e6a4 100644 --- a/test/base.py +++ b/test/base.py @@ -1,37 +1,15 @@ import unittest +from binding.python_c_ffi import Board from binding.python_c_ffi import ChessFFI -from test.chess_ffi import Board -from test.chess_ffi import KING_ATTACKS -from test.chess_ffi import KNIGHT_ATTACKS -from test.chess_ffi import PAWN_ATTACKS -from test.chess_ffi import gen_moves -from test.chess_ffi import init_attack_caches -from test.chess_ffi import load_fen class ChessLibTestBase(unittest.TestCase): @classmethod def setUpClass(cls): cls.chess_ffi = ChessFFI() - - - init_attack_caches() - - cls.KNIGHT_ATTACKS = KNIGHT_ATTACKS - cls.KING_ATTACKS = KING_ATTACKS - cls.PAWN_ATTACKS = PAWN_ATTACKS + cls.chess_ffi.init_attack_cache() def setUp(self): # This should be an empty board for each test in the suite. - self.board = Board() - - - def load_fen(self, fen, board=None): - if board: - return self.chess_ffi.load_fen(board, fen) - return self.chess_ffi.load_fen(self.board, fen) - - - def gen(self, captures_only: bool = False, cap: int = 256): - return gen_moves(self.board, captures_only=captures_only, cap=cap) \ No newline at end of file + self.board = Board() \ No newline at end of file diff --git a/test/test_fen_loader.py b/test/test_fen_loader.py index 37620b0..e290c61 100644 --- a/test/test_fen_loader.py +++ b/test/test_fen_loader.py @@ -1,65 +1,64 @@ from test.base import ChessLibTestBase -from test.chess_ffi import Board -from test.chess_ffi import BLACK -from test.chess_ffi import WHITE -from test.chess_ffi import sq -from test.chess_ffi import popcount -from test.chess_ffi import load_fen +from binding.python_c_ffi import Board +from binding.python_c_ffi import BLACK +from binding.python_c_ffi import WHITE +from binding.python_c_ffi import sq +from binding.python_c_ffi import popcount +from binding.python_c_ffi import get_rank_mask class TestFenLoading(ChessLibTestBase): - - - def rank_mask(self, r): - return sum(1 << (r*8 + f) for f in range(8)) - + def test_startpos_fields_and_occupancies(self): + b = Board() fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - rc = self.load_fen(fen) + rc = self.chess_ffi.load_fen(b, fen) self.assertEqual(rc, 0) - self.assertEqual(self.board.side_to_move, WHITE) - self.assertEqual(self.board.castling_rights, 0b1111) - self.assertEqual(self.board.ep_square, -1) - self.assertEqual(self.board.halfmove_clock, 0) - self.assertEqual(self.board.fullmove_number, 1) + self.assertEqual(b.side_to_move, WHITE) + self.assertEqual(b.castling_rights, 0b1111) + self.assertEqual(b.ep_square, -1) + self.assertEqual(b.halfmove_clock, 0) + self.assertEqual(b.fullmove_number, 1) - white_expected = self.rank_mask(0) | self.rank_mask(1) - black_expected = self.rank_mask(6) | self.rank_mask(7) - self.assertEqual(int(self.board.occ[WHITE]), white_expected) - self.assertEqual(int(self.board.occ[BLACK]), black_expected) - self.assertEqual(int(self.board.occ[2]), white_expected | black_expected) - - self.assertEqual(popcount(int(self.board.occ[WHITE])), 16) - self.assertEqual(popcount(int(self.board.occ[BLACK])), 16) + white_expected = get_rank_mask(0) | get_rank_mask(1) + black_expected = get_rank_mask(6) | get_rank_mask(7) + + self.assertEqual(int(b.occ[WHITE]), white_expected) + self.assertEqual(int(b.occ[BLACK]), black_expected) + self.assertEqual(int(b.occ[2]), white_expected | black_expected) + self.assertEqual(popcount(int(b.occ[WHITE])), 16) + self.assertEqual(popcount(int(b.occ[BLACK])), 16) def test_castling_flags_parsing(self): + b = Board() fen = "r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 5 42" - - rc = self.load_fen(fen) - self.assertEqual(self.board.side_to_move, BLACK) - self.assertEqual(self.board.castling_rights, 0b1111) - self.assertEqual(self.board.halfmove_clock, 5) - self.assertEqual(self.board.fullmove_number, 42) + self.chess_ffi.load_fen(b, fen) + + self.assertEqual(b.side_to_move, BLACK) + self.assertEqual(b.castling_rights, 0b1111) + self.assertEqual(b.halfmove_clock, 5) + self.assertEqual(b.fullmove_number, 42) def test_en_passant_targets(self): # EP at e6, black to move + b1 = Board() fen = "8/8/8/3pP3/8/8/8/8 b KQkq e6 0 1" - rc = self.load_fen(fen) + rc = self.chess_ffi.load_fen(b1, fen) self.assertEqual(rc, 0) - self.assertEqual(self.board.side_to_move, BLACK) - self.assertEqual(self.board.ep_square, sq("e6")) + self.assertEqual(b1.side_to_move, BLACK) + self.assertEqual(b1.ep_square, sq("e6")) # EP at d3, white to move — use a fresh Board + b2 = Board() fen = "8/8/8/8/3Pp3/8/8/8 w KQkq d3 12 7" - b = Board() - rc = self.load_fen(fen, board=b) + rc = self.chess_ffi.load_fen(b2, fen) self.assertEqual(rc, 0) - self.assertEqual(b.side_to_move, WHITE) - self.assertEqual(b.ep_square, sq("d3")) + self.assertEqual(b2.side_to_move, WHITE) + self.assertEqual(b2.ep_square, sq("d3")) def test_malformed_piece_field(self): @@ -70,7 +69,7 @@ class TestFenLoading(ChessLibTestBase): "8/8/8/8/8/8/8/8w - - 0 1", ] for fen in bad: - r = self.load_fen(fen, board=Board()) + r = self.chess_ffi.load_fen(Board(), fen) self.assertEqual(r, -1) @@ -82,5 +81,5 @@ class TestFenLoading(ChessLibTestBase): "8/8/8/8/8/8/8/8 w - e4 0 1", # EP not rank 3/6 (your code allows any 1..8; consider tightening) ] for fen in bad: - r = self.load_fen(fen, board=Board()) + r = self.chess_ffi.load_fen(Board(), fen) self.assertEqual(r, -1) \ No newline at end of file