From c9644213fe606b6b94638133a3f307a14a4d42bf Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Mon, 15 Apr 2024 10:11:50 +0200 Subject: [PATCH 1/3] Remove unnecessary call to updateBoard() --- src/Chess/board.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Chess/board.nim b/src/Chess/board.nim index 48a8776..f876d01 100644 --- a/src/Chess/board.nim +++ b/src/Chess/board.nim @@ -1631,7 +1631,6 @@ proc doMove(self: ChessBoard, move: Move) = # Unreachable discard self.updateAttackedSquares() - self.updateBoard() proc spawnPiece(self: ChessBoard, location: Location, piece: Piece) = From aeaa57aba64f7861969b3b5dc389bc770fe5af9a Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Mon, 15 Apr 2024 17:05:41 +0200 Subject: [PATCH 2/3] Add more positions to the test --- src/Chess/tests/positions.txt | 278 ++++++++++++++++++---------------- 1 file changed, 150 insertions(+), 128 deletions(-) diff --git a/src/Chess/tests/positions.txt b/src/Chess/tests/positions.txt index f281138..b47c93f 100644 --- a/src/Chess/tests/positions.txt +++ b/src/Chess/tests/positions.txt @@ -1,128 +1,150 @@ -rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 -r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 -4k3/8/8/8/8/8/8/4K2R w K - 0 1 -4k3/8/8/8/8/8/8/R3K3 w Q - 0 1 -4k2r/8/8/8/8/8/8/4K3 w k - 0 1 -r3k3/8/8/8/8/8/8/4K3 w q - 0 1 -4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1 -r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1 -8/8/8/8/8/8/6k1/4K2R w K - 0 1 -8/8/8/8/8/8/1k6/R3K3 w Q - 0 1 -4k2r/6K1/8/8/8/8/8/8 w k - 0 1 -r3k3/1K6/8/8/8/8/8/8 w q - 0 1 -r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1 -r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1 -r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1 -r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1 -1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1 -2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1 -r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1 -4k3/8/8/8/8/8/8/4K2R b K - 0 1 -4k3/8/8/8/8/8/8/R3K3 b Q - 0 1 -4k2r/8/8/8/8/8/8/4K3 b k - 0 1 -r3k3/8/8/8/8/8/8/4K3 b q - 0 1 -4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1 -r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1 -8/8/8/8/8/8/6k1/4K2R b K - 0 1 -8/8/8/8/8/8/1k6/R3K3 b Q - 0 1 -4k2r/6K1/8/8/8/8/8/8 b k - 0 1 -r3k3/1K6/8/8/8/8/8/8 b q - 0 1 -r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1 -r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1 -r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1 -r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1 -1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1 -2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1 -r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1 -8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1 -8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1 -8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1 -K7/8/2n5/1n6/8/8/8/k6N w - - 0 1 -k7/8/2N5/1N6/8/8/8/K6n w - - 0 1 -8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1 -8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1 -8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1 -K7/8/2n5/1n6/8/8/8/k6N b - - 0 1 -k7/8/2N5/1N6/8/8/8/K6n b - - 0 1 -B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1 -8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1 -k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1 -K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1 -B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1 -8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1 -k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1 -K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1 -7k/RR6/8/8/8/8/rr6/7K w - - 0 1 -R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1 -7k/RR6/8/8/8/8/rr6/7K b - - 0 1 -R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1 -6kq/8/8/8/8/8/8/7K w - - 0 1 -6KQ/8/8/8/8/8/8/7k b - - 0 1 -K7/8/8/3Q4/4q3/8/8/7k w - - 0 1 -6qk/8/8/8/8/8/8/7K b - - 0 1 -6KQ/8/8/8/8/8/8/7k b - - 0 1 -K7/8/8/3Q4/4q3/8/8/7k b - - 0 1 -8/8/8/8/8/K7/P7/k7 w - - 0 1 -8/8/8/8/8/7K/7P/7k w - - 0 1 -K7/p7/k7/8/8/8/8/8 w - - 0 1 -7K/7p/7k/8/8/8/8/8 w - - 0 1 -8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1 -8/8/8/8/8/K7/P7/k7 b - - 0 1 -8/8/8/8/8/7K/7P/7k b - - 0 1 -K7/p7/k7/8/8/8/8/8 b - - 0 1 -7K/7p/7k/8/8/8/8/8 b - - 0 1 -8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1 -8/8/8/8/8/4k3/4P3/4K3 w - - 0 1 -4k3/4p3/4K3/8/8/8/8/8 b - - 0 1 -8/8/7k/7p/7P/7K/8/8 w - - 0 1 -8/8/k7/p7/P7/K7/8/8 w - - 0 1 -8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1 -8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1 -8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1 -k7/8/3p4/8/3P4/8/8/7K w - - 0 1 -8/8/7k/7p/7P/7K/8/8 b - - 0 1 -8/8/k7/p7/P7/K7/8/8 b - - 0 1 -8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1 -8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1 -8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1 -k7/8/3p4/8/3P4/8/8/7K b - - 0 1 -7k/3p4/8/8/3P4/8/8/K7 w - - 0 1 -7k/8/8/3p4/8/8/3P4/K7 w - - 0 1 -k7/8/8/7p/6P1/8/8/K7 w - - 0 1 -k7/8/7p/8/8/6P1/8/K7 w - - 0 1 -k7/8/8/6p1/7P/8/8/K7 w - - 0 1 -k7/8/6p1/8/8/7P/8/K7 w - - 0 1 -k7/8/8/3p4/4p3/8/8/7K w - - 0 1 -k7/8/3p4/8/8/4P3/8/7K w - - 0 1 -7k/3p4/8/8/3P4/8/8/K7 b - - 0 1 -7k/8/8/3p4/8/8/3P4/K7 b - - 0 1 -k7/8/8/7p/6P1/8/8/K7 b - - 0 1 -k7/8/7p/8/8/6P1/8/K7 b - - 0 1 -k7/8/8/6p1/7P/8/8/K7 b - - 0 1 -k7/8/6p1/8/8/7P/8/K7 b - - 0 1 -k7/8/8/3p4/4p3/8/8/7K b - - 0 1 -k7/8/3p4/8/8/4P3/8/7K b - - 0 1 -7k/8/8/p7/1P6/8/8/7K w - - 0 1 -7k/8/p7/8/8/1P6/8/7K w - - 0 1 -7k/8/8/1p6/P7/8/8/7K w - - 0 1 -7k/8/1p6/8/8/P7/8/7K w - - 0 1 -k7/7p/8/8/8/8/6P1/K7 w - - 0 1 -k7/6p1/8/8/8/8/7P/K7 w - - 0 1 -3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1 -7k/8/8/p7/1P6/8/8/7K b - - 0 1 -7k/8/p7/8/8/1P6/8/7K b - - 0 1 -7k/8/8/1p6/P7/8/8/7K b - - 0 1 -7k/8/1p6/8/8/P7/8/7K b - - 0 1 -k7/7p/8/8/8/8/6P1/K7 b - - 0 1 -k7/6p1/8/8/8/8/7P/K7 b - - 0 1 -3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1 -8/Pk6/8/8/8/8/6Kp/8 w - - 0 1 -n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1 -8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1 -n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1 -8/Pk6/8/8/8/8/6Kp/8 b - - 0 1 -n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1 -8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1 -n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1 -8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1 -rnbqkb1r/ppppp1pp/7n/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3 \ No newline at end of file +1r2k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1 +1r2k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1 +2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1 +2kr3r/p1ppqpb1/bn2Qnp1/3PN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQ - 3 2 +2r1k2r/8/8/8/8/8/8/R3K2R b KQk - 0 1 +2r1k2r/8/8/8/8/8/8/R3K2R w KQk - 0 1 +2r5/3pk3/8/2P5/8/2K5/8/8 w - - 5 4 +3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1 +3k4/3pp3/8/8/8/8/3PP3/3K4 b - - 0 1 +3k4/3pp3/8/8/8/8/3PP3/3K4 w - - 0 1 +3k4/8/8/8/8/8/8/R3K3 w Q - 0 1 +4k2r/6K1/8/8/8/8/8/8 b k - 0 1 +4k2r/6K1/8/8/8/8/8/8 w k - 0 1 +4k2r/8/8/8/8/8/8/4K3 b k - 0 1 +4k2r/8/8/8/8/8/8/4K3 w k - 0 1 +4k3/1P6/8/8/8/8/K7/8 w - - 0 1 +4k3/4p3/4K3/8/8/8/8/8 b - - 0 1 +4k3/8/8/8/8/8/8/4K2R b K - 0 1 +4k3/8/8/8/8/8/8/4K2R w K - 0 1 +4k3/8/8/8/8/8/8/R3K2R b KQ - 0 1 +4k3/8/8/8/8/8/8/R3K2R w KQ - 0 1 +4k3/8/8/8/8/8/8/R3K3 b Q - 0 1 +4k3/8/8/8/8/8/8/R3K3 w Q - 0 1 +5k2/8/8/8/8/8/8/4K2R w K - 0 1 +6KQ/8/8/8/8/8/8/7k b - - 0 1 +6kq/8/8/8/8/8/8/7K w - - 0 1 +6qk/8/8/8/8/8/8/7K b - - 0 1 +7k/3p4/8/8/3P4/8/8/K7 b - - 0 1 +7k/3p4/8/8/3P4/8/8/K7 w - - 0 1 +7K/7p/7k/8/8/8/8/8 b - - 0 1 +7K/7p/7k/8/8/8/8/8 w - - 0 1 +7k/8/1p6/8/8/P7/8/7K b - - 0 1 +7k/8/1p6/8/8/P7/8/7K w - - 0 1 +7k/8/8/1p6/P7/8/8/7K b - - 0 1 +7k/8/8/1p6/P7/8/8/7K w - - 0 1 +7k/8/8/3p4/8/8/3P4/K7 b - - 0 1 +7k/8/8/3p4/8/8/3P4/K7 w - - 0 1 +7k/8/8/p7/1P6/8/8/7K b - - 0 1 +7k/8/8/p7/1P6/8/8/7K w - - 0 1 +7k/8/p7/8/8/1P6/8/7K b - - 0 1 +7k/8/p7/8/8/1P6/8/7K w - - 0 1 +7k/RR6/8/8/8/8/rr6/7K b - - 0 1 +7k/RR6/8/8/8/8/rr6/7K w - - 0 1 +8/1k6/8/5N2/8/4n3/8/2K5 b - - 0 1 +8/1k6/8/5N2/8/4n3/8/2K5 w - - 0 1 +8/1n4N1/2k5/8/8/5K2/1N4n1/8 b - - 0 1 +8/1n4N1/2k5/8/8/5K2/1N4n1/8 w - - 0 1 +8/2k1p3/3pP3/3P2K1/8/8/8/8 b - - 0 1 +8/2k1p3/3pP3/3P2K1/8/8/8/8 w - - 0 1 +8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1 +8/3k4/3p4/8/3P4/3K4/8/8 b - - 0 1 +8/3k4/3p4/8/3P4/3K4/8/8 w - - 0 1 +8/8/1B6/7b/7k/8/2B1b3/7K b - - 0 1 +8/8/1B6/7b/7k/8/2B1b3/7K w - - 0 1 +8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1 +8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1 +8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1 +8/8/3K4/3Nn3/3nN3/4k3/8/8 b - - 0 1 +8/8/3k4/3p4/3P4/3K4/8/8 b - - 0 1 +8/8/3k4/3p4/3P4/3K4/8/8 w - - 0 1 +8/8/3k4/3p4/8/3P4/3K4/8 b - - 0 1 +8/8/3k4/3p4/8/3P4/3K4/8 w - - 0 1 +8/8/4k3/3Nn3/3nN3/4K3/8/8 w - - 0 1 +8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1 +8/8/7k/7p/7P/7K/8/8 b - - 0 1 +8/8/7k/7p/7P/7K/8/8 w - - 0 1 +8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3 +8/8/8/8/8/4k3/4P3/4K3 w - - 0 1 +8/8/8/8/8/7K/7P/7k b - - 0 1 +8/8/8/8/8/7K/7P/7k w - - 0 1 +8/8/8/8/8/8/1k6/R3K3 b Q - 0 1 +8/8/8/8/8/8/1k6/R3K3 w Q - 0 1 +8/8/8/8/8/8/6k1/4K2R b K - 0 1 +8/8/8/8/8/8/6k1/4K2R w K - 0 1 +8/8/8/8/8/K7/P7/k7 b - - 0 1 +8/8/8/8/8/K7/P7/k7 w - - 0 1 +8/8/k7/p7/P7/K7/8/8 b - - 0 1 +8/8/k7/p7/P7/K7/8/8 w - - 0 1 +8/k1P5/8/1K6/8/8/8/8 w - - 0 1 +8/P1k5/K7/8/8/8/8/8 w - - 0 1 +8/Pk6/8/8/8/8/6Kp/8 b - - 0 1 +8/Pk6/8/8/8/8/6Kp/8 w - - 0 1 +8/PPPk4/8/8/8/8/4Kppp/8 b - - 0 1 +8/PPPk4/8/8/8/8/4Kppp/8 w - - 0 1 +B6b/8/8/8/2K5/4k3/8/b6B w - - 0 1 +B6b/8/8/8/2K5/5k2/8/b6B b - - 0 1 +K1k5/8/P7/8/8/8/8/8 w - - 0 1 +k7/6p1/8/8/8/8/7P/K7 b - - 0 1 +k7/6p1/8/8/8/8/7P/K7 w - - 0 1 +k7/7p/8/8/8/8/6P1/K7 b - - 0 1 +k7/7p/8/8/8/8/6P1/K7 w - - 0 1 +K7/8/2n5/1n6/8/8/8/k6N b - - 0 1 +k7/8/2N5/1N6/8/8/8/K6n b - - 0 1 +K7/8/2n5/1n6/8/8/8/k6N w - - 0 1 +k7/8/2N5/1N6/8/8/8/K6n w - - 0 1 +k7/8/3p4/8/3P4/8/8/7K b - - 0 1 +k7/8/3p4/8/3P4/8/8/7K w - - 0 1 +k7/8/3p4/8/8/4P3/8/7K b - - 0 1 +k7/8/3p4/8/8/4P3/8/7K w - - 0 1 +k7/8/6p1/8/8/7P/8/K7 b - - 0 1 +k7/8/6p1/8/8/7P/8/K7 w - - 0 1 +k7/8/7p/8/8/6P1/8/K7 b - - 0 1 +k7/8/7p/8/8/6P1/8/K7 w - - 0 1 +k7/8/8/3p4/4p3/8/8/7K b - - 0 1 +k7/8/8/3p4/4p3/8/8/7K w - - 0 1 +K7/8/8/3Q4/4q3/8/8/7k b - - 0 1 +K7/8/8/3Q4/4q3/8/8/7k w - - 0 1 +k7/8/8/6p1/7P/8/8/K7 b - - 0 1 +k7/8/8/6p1/7P/8/8/K7 w - - 0 1 +k7/8/8/7p/6P1/8/8/K7 b - - 0 1 +k7/8/8/7p/6P1/8/8/K7 w - - 0 1 +k7/B7/1B6/1B6/8/8/8/K6b b - - 0 1 +K7/b7/1b6/1b6/8/8/8/k6B b - - 0 1 +k7/B7/1B6/1B6/8/8/8/K6b w - - 0 1 +K7/b7/1b6/1b6/8/8/8/k6B w - - 0 1 +K7/p7/k7/8/8/8/8/8 b - - 0 1 +K7/p7/k7/8/8/8/8/8 w - - 0 1 +n1n5/1Pk5/8/8/8/8/5Kp1/5N1N b - - 0 1 +n1n5/1Pk5/8/8/8/8/5Kp1/5N1N w - - 0 1 +n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1 +n1n5/PPPk4/8/8/8/8/4Kppp/5N1N w - - 0 1 +r1bqkbnr/pppppppp/n7/8/8/P7/1PPPPPPP/RNBQKBNR w KQkq - 2 2 +r3k1r1/8/8/8/8/8/8/R3K2R b KQq - 0 1 +r3k1r1/8/8/8/8/8/8/R3K2R w KQq - 0 1 +r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1 +r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1 +r3k2r/8/8/8/8/8/8/1R2K2R b Kkq - 0 1 +r3k2r/8/8/8/8/8/8/1R2K2R w Kkq - 0 1 +r3k2r/8/8/8/8/8/8/2R1K2R b Kkq - 0 1 +r3k2r/8/8/8/8/8/8/2R1K2R w Kkq - 0 1 +r3k2r/8/8/8/8/8/8/4K3 b kq - 0 1 +r3k2r/8/8/8/8/8/8/4K3 w kq - 0 1 +r3k2r/8/8/8/8/8/8/R3K1R1 b Qkq - 0 1 +r3k2r/8/8/8/8/8/8/R3K1R1 w Qkq - 0 1 +r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1 +r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1 +r3k2r/p1pp1pb1/bn2Qnp1/2qPN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQkq - 3 2 +r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 +r3k3/1K6/8/8/8/8/8/8 b q - 0 1 +r3k3/1K6/8/8/8/8/8/8 w q - 0 1 +r3k3/8/8/8/8/8/8/4K3 b q - 0 1 +r3k3/8/8/8/8/8/8/4K3 w q - 0 1 +r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10 +r6r/1b2k1bq/8/8/7B/8/8/R3K2R b KQ - 3 2 +R6r/8/8/2K5/5k2/8/8/r6R b - - 0 1 +R6r/8/8/2K5/5k2/8/8/r6R w - - 0 1 +rnb2k1r/pp1Pbppp/2p5/q7/2B5/8/PPPQNnPP/RNB1K2R w KQ - 3 9 +rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8 +rnbqkb1r/ppppp1pp/7n/4Pp2/8/8/PPPP1PPP/RNBQKBNR w KQkq f6 0 3 +rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 \ No newline at end of file From 48e2adddc6f6c0ff66ea3888ba7d22450408e9e8 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Tue, 16 Apr 2024 09:05:35 +0200 Subject: [PATCH 3/3] Switch to static move list and print nps after perft completion --- src/Chess/board.nim | 84 +++++++++++++++++++++++++++------------- src/Chess/tests/suite.py | 2 +- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/Chess/board.nim b/src/Chess/board.nim index f876d01..77432f4 100644 --- a/src/Chess/board.nim +++ b/src/Chess/board.nim @@ -16,6 +16,7 @@ import std/strutils import std/strformat import std/times import std/math +from std/lenientops import `/` # Only needed for perft type @@ -73,6 +74,11 @@ type targetSquare*: Location flags*: uint16 + MoveList* = object + ## A list of moves + data: array[218, Move] + len: int8 + Position* = ref object ## A chess position @@ -112,10 +118,31 @@ type positions: seq[Position] +iterator items(self: MoveList): Move = + var i = 0 + while self.len > i: + yield self.data[i] + inc(i) + + +func add(self: var MoveList, move: Move) {.inline.} = + self.data[self.len] = move + inc(self.len) + +func contains(self: MoveList, move: Move): bool {.inline.} = + for item in self: + if move == item: + return true + return false + + +func len(self: MoveList): int {.inline.} = self.len + + # A bunch of simple utility functions and forward declarations func emptyPiece*: Piece {.inline.} = Piece(kind: Empty, color: None) -func emptyLocation*: Location {.inline.} = (-1 , -1) +func emptyLocation*: Location {.inline.} = (-1, -1) func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White) proc algebraicToLocation*(s: string): Location {.inline.} proc makeMove*(self: ChessBoard, move: Move): Move {.discardable.} @@ -124,7 +151,7 @@ func `+`*(a, b: Location): Location = (a.row + b.row, a.col + b.col) func `-`*(a: Location): Location = (-a.row, -a.col) func `-`*(a, b: Location): Location = (a.row - b.row, a.col - b.col) func isValid*(a: Location): bool {.inline.} = a.row in 0..7 and a.col in 0..7 -proc generateMoves(self: ChessBoard, location: Location): seq[Move] +proc generateMoves(self: ChessBoard, location: Location, moves: var MoveList) proc getAttackers*(self: ChessBoard, loc: Location, color: PieceColor): seq[Location] proc getAttackFor*(self: ChessBoard, source, target: Location): tuple[source, target, direction: Location] proc isAttacked*(self: ChessBoard, loc: Location, color: PieceColor = None): bool @@ -829,7 +856,7 @@ proc getCheckResolutions(self: ChessBoard, color: PieceColor): seq[Location] = result.add(location) -proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] = +proc generatePawnMoves(self: ChessBoard, location: Location, moveList: var MoveList) = ## Generates the possible moves for the pawn in the given ## location var @@ -911,12 +938,12 @@ proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] = if target.row == piece.color.getLastRow(): # Pawn reached the other side of the board: generate all potential piece promotions for promotionType in [PromoteToKnight, PromoteToBishop, PromoteToRook, PromoteToQueen]: - result.add(Move(startSquare: location, targetSquare: target, flags: promotionType.uint16 or flags)) + moveList.add(Move(startSquare: location, targetSquare: target, flags: promotionType.uint16 or flags)) continue - result.add(Move(startSquare: location, targetSquare: target, flags: flags)) + moveList.add(Move(startSquare: location, targetSquare: target, flags: flags)) -proc generateSlidingMoves(self: ChessBoard, location: Location): seq[Move] = +proc generateSlidingMoves(self: ChessBoard, location: Location, moves: var MoveList) = ## Generates moves for the sliding piece in the given location let piece = self.grid[location.row, location.col] assert piece.kind in [Bishop, Rook, Queen], &"generateSlidingMoves called on a {piece.kind}" @@ -972,13 +999,13 @@ proc generateSlidingMoves(self: ChessBoard, location: Location): seq[Move] = # it and stop going any further if otherPiece.kind != King: # Can't capture the king - result.add(Move(startSquare: location, targetSquare: square, flags: Capture.uint16)) + moves.add(Move(startSquare: location, targetSquare: square, flags: Capture.uint16)) break # Target square is empty, keep going - result.add(Move(startSquare: location, targetSquare: square)) + moves.add(Move(startSquare: location, targetSquare: square)) -proc generateKingMoves(self: ChessBoard, location: Location): seq[Move] = +proc generateKingMoves(self: ChessBoard, location: Location, moves: var MoveList) = ## Generates moves for the king in the given location var piece = self.grid[location.row, location.col] @@ -1020,10 +1047,10 @@ proc generateKingMoves(self: ChessBoard, location: Location): seq[Move] = continue # Target square is empty or contains an enemy piece: # All good for us! - result.add(Move(startSquare: location, targetSquare: square, flags: flag.uint16)) + moves.add(Move(startSquare: location, targetSquare: square, flags: flag.uint16)) -proc generateKnightMoves(self: ChessBoard, location: Location): seq[Move] = +proc generateKnightMoves(self: ChessBoard, location: Location, moves: var MoveList) = ## Generates moves for the knight in the given location var piece = self.grid[location.row, location.col] @@ -1039,7 +1066,7 @@ proc generateKnightMoves(self: ChessBoard, location: Location): seq[Move] = let pinned = self.getPinnedDirections(location) if pinned.len() > 0: # Knight is pinned: can't move! - return @[] + return let checked = self.inCheck() let resolutions = if not checked: @[] else: self.getCheckResolutions(piece.color) for direction in directions: @@ -1057,37 +1084,38 @@ proc generateKnightMoves(self: ChessBoard, location: Location): seq[Move] = if otherPiece.color != None: # Target square contains an enemy piece: capture # it - result.add(Move(startSquare: location, targetSquare: square, flags: Capture.uint16)) + moves.add(Move(startSquare: location, targetSquare: square, flags: Capture.uint16)) else: # Target square is empty - result.add(Move(startSquare: location, targetSquare: square)) + moves.add(Move(startSquare: location, targetSquare: square)) -proc generateMoves(self: ChessBoard, location: Location): seq[Move] = +proc generateMoves(self: ChessBoard, location: Location, moves: var MoveList) = ## Returns the list of possible legal chess moves for the ## piece in the given location let piece = self.grid[location.row, location.col] case piece.kind: of Queen, Bishop, Rook: - return self.generateSlidingMoves(location) + self.generateSlidingMoves(location, moves) of Pawn: - return self.generatePawnMoves(location) + self.generatePawnMoves(location, moves) of King: - return self.generateKingMoves(location) + self.generateKingMoves(location, moves) of Knight: - return self.generateKnightMoves(location) + self.generateKnightMoves(location, moves) else: - return @[] + discard -proc generateAllMoves*(self: ChessBoard): seq[Move] = +proc generateAllMoves*(self: ChessBoard): MoveList = ## Returns the list of all possible legal moves ## in the current position + var data: array[218, Move] + result = MoveList(len: 0, data: data) for i in 0..7: for j in 0..7: if self.grid[i, j].color == self.getActiveColor(): - for move in self.generateMoves((int8(i), int8(j))): - result.add(move) + self.generateMoves((int8(i), int8(j)), result) proc isAttacked*(self: ChessBoard, loc: Location, color: PieceColor = None): bool = @@ -1716,7 +1744,9 @@ proc undoLastMove*(self: ChessBoard) = proc isLegal(self: ChessBoard, move: Move): bool {.inline.} = ## Returns whether the given move is legal - return move in self.generateMoves(move.startSquare) + var moves = MoveList() + self.generateMoves(move.startSquare, moves) + return move in moves proc makeMove*(self: ChessBoard, move: Move): Move {.discardable.} = @@ -1999,11 +2029,13 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) = if bulk: let t = cpuTime() let nodes = board.perft(ply, divide=true, bulk=true, verbose=verbose).nodes + let tot = cpuTime() - t echo &"\nNodes searched (bulk-counting: on): {nodes}" - echo &"Time taken: {round(cpuTime() - t, 3)} seconds\n" + echo &"Time taken: {round(tot, 3)} seconds\nNodes per second: {round(nodes / tot).uint64}" else: let t = cpuTime() let data = board.perft(ply, divide=true, verbose=verbose) + let tot = cpuTime() - t echo &"\nNodes searched (bulk-counting: off): {data.nodes}" echo &" - Captures: {data.captures}" echo &" - Checks: {data.checks}" @@ -2012,7 +2044,7 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) = echo &" - Castles: {data.castles}" echo &" - Promotions: {data.promotions}" echo "" - echo &"Time taken: {round(cpuTime() - t, 3)} seconds" + echo &"Time taken: {tot} seconds\nNodes per second: {round(data.nodes / tot).uint64}" except ValueError: echo "Error: go: perft: invalid depth" else: diff --git a/src/Chess/tests/suite.py b/src/Chess/tests/suite.py index 877e9a1..f187b41 100644 --- a/src/Chess/tests/suite.py +++ b/src/Chess/tests/suite.py @@ -26,7 +26,7 @@ def main(args: Namespace) -> int: stop = timeit.default_timer() print(f"\r[S] Ran {len(positions)} tests at depth {args.ply} in {stop - start:.2f} seconds ({len(successful)} successful, {len(failed)} failed)\033[K") if failed and args.show_failures: - print("[S] The following FENs failed to pass the test:", end="") + print("[S] The following FENs failed to pass the test:", end="\n\t") print("\n\t".join(failed))