niklasf / python-chess

A chess library for Python, with move generation and validation, PGN parsing and writing, Polyglot opening book reading, Gaviota tablebase probing, Syzygy tablebase probing, and UCI/XBoard engine communication
https://python-chess.readthedocs.io/en/latest/
GNU General Public License v3.0
2.44k stars 530 forks source link

Incorrect perft(4) with Kiwipete. #1064

Closed 06davber closed 9 months ago

06davber commented 9 months ago

Hi,

I wrote a short program that runs perft() using the move-gen of python-chess. The code can be found below.

The Chessprogramming wiki has several positions available with perft results. Running perft(4) for Kiwipete (https://www.chessprogramming.org/Perft_Results#Position_2) incorrectly returns 4085604, when 4085603 is expected.

Here is the code for perft.py:

import chess
import sys

def do_perft(board, depth):
    if depth == 0 or board.outcome() != None:
        return 1

    moves = list(board.legal_moves)
    if depth == 1:
        return len(moves)

    count = 0
    for move in moves:
        board.push(move)
        count += do_perft(board, depth - 1)
        board.pop()

    return count

def cmd_perft(depth_s, *fen):
    depth = int(depth_s)
    if depth < 1:
        print('Cannot do perft with depth<1!')
        return

    board = chess.Board()
    if len(fen) != 0:
        board.set_fen(' '.join(fen))

    count = 0
    for move in list(board.legal_moves):
        board.push(move)
        num = do_perft(board, depth - 1)
        count += num
        board.pop()
        print(f'{move.uci()}: {num}')

    print('')
    print(f'Nodes searched: {count}')

def main():
    cmd_perft(*sys.argv[1:])

if __name__ == '__main__':
    main()

Here is the program command line: python perft.py 4 r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -

And here is the complete output of the program:

e5f7: 88799
e5d7: 93913
e5g6: 83866
e5c6: 83885
e5g4: 79912
e5c4: 77752
e5d3: 77431
f3f6: 77839
f3h5: 95034
f3f5: 104992
f3g4: 92037
f3f4: 90488
f3h3: 98524
f3g3: 94461
f3e3: 92505
f3d3: 83727
c3b5: 81498
c3a4: 91447
c3d1: 84782
c3b1: 84773
e2a6: 69334
e2b5: 79739
e2c4: 84835
e2d3: 85119
e2f1: 88728
e2d1: 74963
d2h6: 82323
d2g5: 87951
d2f4: 84869
d2e3: 90274
d2c1: 83037
h1g1: 84876
h1f1: 81563
e1f1: 77887
e1d1: 79989
a1d1: 79695
a1c1: 83263
a1b1: 83348
e1g1: 86975
e1c1: 79803
d5e6: 97464
g2h3: 82759
d5d6: 79551
g2g3: 77468
b2b3: 81066
a2a3: 94405
g2g4: 75677
a2a4: 90978

Nodes searched: 4085604
06davber commented 9 months ago

NOTE: Python version used is CPython 3.10.6 on Windows 10.0.19044. python-chess version 1.10.0.

MarkZH commented 9 months ago

@06davber This line is incorrect in the perft script:

if depth == 0 or board.outcome() != None:

End-of-game nodes are not counted. The correct line is

if depth == 0:

This results in correct counts. See the first paragraph in the description of the perft test.

06davber commented 9 months ago

Apologies, my mistake.