agausmann / perftree

Perft debugger. Compare your chess engine's move generation to Stockfish
MIT License
62 stars 4 forks source link

Hangs with infinite newlines (maybe because of checkmate?) #2

Closed pimlu closed 4 years ago

pimlu commented 4 years ago

Hey, I have been using this for my chess engine and it has been really helpful.

However, in certain situations it seems to get hung in a loop where it outputs newlines to stdout.

I can reproduce with the following input:

fen 5k2/8/5K1R/8/8/8/8/8 w - - 0 1
depth 2
diff

My program outputs a correct (or at least diffable output) for this fen:

./target/debug/stubot-perftree 2 "5k2/8/5K1R/8/8/8/8/8 w - - 0 1"
f6e5 5
f6e6 3
f6f5 5
f6g5 5
f6g6 3
h6g6 1
h6h1 2
h6h2 2
h6h3 2
h6h4 2
h6h5 2
h6h7 2
h6h8 1

35

My instinct is this relates to checkmate (which is what I am debugging right now). There is a mate in 1, so not all leaf nodes are actually of depth 2.

pimlu commented 4 years ago

Okay, my bug was that I was counting a checkmate as a leaf node. So it's actually 34 nodes. But even if I match stockfish, perftree still hangs on this input.

agausmann commented 4 years ago

You're right, it is related to checkmate, which does not count as a node. When Stockfish calculates the perft, the corresponding move has a node count of zero:

$ stockfish
position fen 5k2/8/5K1R/8/8/8/8/8 w - - 0 1
go perft 2
h6h1: 2
h6h2: 2
h6h3: 2
h6h4: 2
h6h5: 2
h6g6: 1
h6h7: 2
h6h8: 0
f6e5: 5
f6f5: 5
f6g5: 5
f6e6: 3
f6g6: 3

Nodes searched: 34

This causes problems with my calculation of the column widths:

let digits = (x as f64).log10().ceil() as usize;

(0 as f64).log10().ceil() is -f64::INFINITY, which is out of bounds for the type usize. Casting an out-of-bounds floating-point value to an integer used to be undefined behavior, and it produced a very large integer value (0x8000000000000000), which perftree used as a column width and then attempted to print that many spaces.

As of rustc 1.45.0, such casts are now defined to saturate at the bounds of the integer type, which means -f64::INFINITY as usize == 0. I'd suggest updating to that version and trying the test case again, and it should work (it does for me).

I've also released v0.1.2 which manually saturates before converting and should fix the problem for previous versions of Rust.

pimlu commented 4 years ago

Yeah I upgraded both, and this works perfectly! perftree is great, I have a cargo package for it it and perftree saved me so much time drilling into where my bugs really were. Thanks again!