From 3c31f900eaf249c5c8865b06fe33081de7c09361 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Wed, 11 Jun 2025 08:16:37 -0700 Subject: [PATCH] [perft] A script that checks a list of positions against known node counts A small Python script that reads a JSON list of positions and their known Perft node counts to a certain depth, then invokes the Perft program for each position and validates the output. Peter Ellis Jones shared such a JSON list on GitHub. Import that file. --- .../data/peterellisjones-perft-positions.json | 117 ++++++++++++++++++ perft/scripts/check-positions | 80 ++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 perft/data/peterellisjones-perft-positions.json create mode 100755 perft/scripts/check-positions diff --git a/perft/data/peterellisjones-perft-positions.json b/perft/data/peterellisjones-perft-positions.json new file mode 100644 index 0000000..eb48f34 --- /dev/null +++ b/perft/data/peterellisjones-perft-positions.json @@ -0,0 +1,117 @@ +[ + { + "depth":1, + "nodes":8, + "fen":"r6r/1b2k1bq/8/8/7B/8/8/R3K2R b KQ - 3 2" + }, + { + "depth":1, + "nodes":8, + "fen":"8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3" + }, + { + "depth":1, + "nodes":19, + "fen":"r1bqkbnr/pppppppp/n7/8/8/P7/1PPPPPPP/RNBQKBNR w KQkq - 2 2" + }, + { + "depth":1, + "nodes":5, + "fen":"r3k2r/p1pp1pb1/bn2Qnp1/2qPN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQkq - 3 2" + }, + { + "depth":1, + "nodes":44, + "fen":"2kr3r/p1ppqpb1/bn2Qnp1/3PN3/1p2P3/2N5/PPPBBPPP/R3K2R b KQ - 3 2" + }, + { + "depth":1, + "nodes":39, + "fen":"rnb2k1r/pp1Pbppp/2p5/q7/2B5/8/PPPQNnPP/RNB1K2R w KQ - 3 9" + }, + { + "depth":1, + "nodes":9, + "fen":"2r5/3pk3/8/2P5/8/2K5/8/8 w - - 5 4" + }, + { + "depth":3, + "nodes":62379, + "fen":"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8" + }, + { + "depth":3, + "nodes":89890, + "fen":"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10" + }, + { + "depth":6, + "nodes":1134888, + "fen":"3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1" + }, + { + "depth":6, + "nodes":1015133, + "fen":"8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1" + }, + { + "depth":6, + "nodes":1440467, + "fen":"8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1" + }, + { + "depth":6, + "nodes":661072, + "fen":"5k2/8/8/8/8/8/8/4K2R w K - 0 1" + }, + { + "depth":6, + "nodes":803711, + "fen":"3k4/8/8/8/8/8/8/R3K3 w Q - 0 1" + }, + { + "depth":4, + "nodes":1274206, + "fen":"r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1" + }, + { + "depth":4, + "nodes":1720476, + "fen":"r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1" + }, + { + "depth":6, + "nodes":3821001, + "fen":"2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1" + }, + { + "depth":5, + "nodes":1004658, + "fen":"8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1" + }, + { + "depth":6, + "nodes":217342, + "fen":"4k3/1P6/8/8/8/8/K7/8 w - - 0 1" + }, + { + "depth":6, + "nodes":92683, + "fen":"8/P1k5/K7/8/8/8/8/8 w - - 0 1" + }, + { + "depth":6, + "nodes":2217, + "fen":"K1k5/8/P7/8/8/8/8/8 w - - 0 1" + }, + { + "depth":7, + "nodes":567584, + "fen":"8/k1P5/8/1K6/8/8/8/8 w - - 0 1" + }, + { + "depth":4, + "nodes":23527, + "fen":"8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1" + } +] \ No newline at end of file diff --git a/perft/scripts/check-positions b/perft/scripts/check-positions new file mode 100755 index 0000000..8258567 --- /dev/null +++ b/perft/scripts/check-positions @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# Eryn Wells + +''' +New script. +''' + +import argparse +import json +import subprocess + + +def run_perft(fen, depth, expected_nodes_count): + result = subprocess.run( + [ + 'cargo', + 'run', + '--', + '--fen', fen, + str(depth) + ], + capture_output=True, + check=True, + text=True + ) + + nodes_count = 0 + for line in result.stdout.splitlines(): + if line.startswith('nodes='): + (_, nodes_count) = line.split('=') + nodes_count = int(nodes_count) + + return nodes_count + + +def parse_args(argv, *a, **kw): + parser = argparse.ArgumentParser(*a, **kw) + parser.add_argument('-c', '--continue', dest='should_continue', + action='store_true') + parser.add_argument('file') + args = parser.parse_args(argv) + return args + + +def main(argv): + args = parse_args(argv[1:], prog=argv[0]) + + items = [] + with open(args.file, 'r') as f: + items = json.load(f) + + should_continue = args.should_continue + + for item in items: + fen = item['fen'] + depth = item['depth'] + expected_nodes_count = int(item['nodes']) + + print('---') + print(f'fen={fen}') + print(f'expected-nodes={expected_nodes_count}') + + nodes_count = run_perft(fen, depth, expected_nodes_count) + print(f'nodes={nodes_count}') + + did_pass = nodes_count == expected_nodes_count + if did_pass: + print('result=PASS') + else: + print('result=FAIL') + + if not did_pass and not should_continue: + return -1 + + return 0 + + +if __name__ == '__main__': + import sys + sys.exit(main(sys.argv))