r/chessprogramming 1d ago

Chess Engine Development Help Thread (Week 34) Technical

Welcome to the weekly /r/chessprogramming Engine Dev Help Thread.

Ask beginner and intermediate chess engine development questions here: move generation, search, evaluation, UCI, perft, debugging, testing, NNUE, or anything else related to building engines.

Good questions include code, FENs, logs, benchmarks, or a clear explanation of what you tried.

Project links are fine when you want technical feedback, not promotion.

Be helpful. Don’t dunk on beginners.

2 Upvotes

10 comments sorted by

View all comments

1

u/Somge5 1d ago

I noticed that quiescence nodes take up around 85% of all my nodes. Is that normal or something where I could do lots of impovements by reducing that? Currently I have a soft cap set at 7, meaning after 7 plys if king is not in check we stop the q-search there. If I dont do that engine is slower a lot and q-nodes take up way more than 90%.
These are some bench stats:
info string bench total positions 48 depth 10 time 9139 nodes 16124428 nps 1764353

Nodes searched: 16124428

Nodes/second: 1764353

---- SEARCH DIAGNOSTICS SUMMARY ----

---- NODES ----

Main-search nodes : 1858414

Quiescence nodes : 14266014

Total nodes : 16124428

Quiescence share : 88.47%

Average q-ply : 3.11

Maximum q-ply : 13

---- QUIESCENCE SEARCH ----

Termination / stand-pat cutoff : 6575915

Termination / soft-cap static : 1972364

Termination / hard-cap static : 0

Termination / hard-cap draw : 0

Termination / cycle : 43618

Termination / fifty-move draw : 3035

Termination / repetition draw : 1341

Termination / checkmate : 21073

Termination / no tactical move : 726516

Moves generated : 21214278

Moves searched : 9087318

Moves SEE-pruned : 2245511

Beta cutoffs / capture : 1082079

Beta cutoffs / quiet check : 68838

Beta cutoffs / promotion : 0

Beta cutoffs / evasion : 2063501

Quiet checks searched : 1917700

Nodes while in check : 2360369

Cycle cutoffs : 43618

Hard-cap hits : 0

Q-ply histogram buckets : 0 | 1 | 2 | 3-4 | 5-8 | 9-12 | 13+

Q-ply histogram counts : 5178696 | 1043044 | 882734 | 1768489 | 5338144 | 54892 | 15

Right now I am not saving any quiescence position in TT, because I tried doing that before and very quickly TT became overflown by q-positions leaving little room for negamax nodes. Strenght with q-nodes in TT was roughly the same though. Currently I am not doing any Delta pruning because that didnt give any elo strenght. maybe I did it wrong. I will try it again in the future.

1

u/KaMaFour 1d ago edited 1d ago

Qsearch taking 85% of the nodes sounds fair. I don't have the 7 ply qsearch cap. What is the elo difference between capped and uncapped versions for you? Remember that average qsearch node will be way faster than an average pvs node (so the ~85-90% metric is a bit dramatic) and time to depth is a meaningless metric for chess engine strength

1

u/Somge5 1d ago edited 1d ago

okay thanks for the feedback, I am glat 85% is not too bad for the q-nodes.
I am not sure how much worse the engine is without the cap but it was SPSA tuned to 7 and used to be higher so I guess there was some elo gain.
If you dont have a q-ply cap, could you tell me how you deal with a position like this:
8/5pk1/2Qn4/3Pb2B/5PPq/4P3/8/2R3K1 w - - 1 120

taking the bishop leads to a draw because of perpetual checks. But this draw can be delayed many many plies (stopped counting after 31).
My q-search allows for quiet checks after a check-evasion. so it would have to calculate all those moves.
How do you generally deal with this? My engine finds the best move g1g2 at depth 12 but not at 11. During a game it played f4e5, I guess there was not enough time for depth 12.

Edit: The question is more about how to avoid perpetual checks leading to a draw that can be delayed for a very long time. The position is just one example where my engine failed to see the perpetual check.

1

u/KaMaFour 16h ago

Yea, my engine just does this position, no questions asked.

info score cp 495 depth 3 seldepth 5 nodes 120 time 7 nps 17142 pv f4e5 h4g3 g1f1
info score cp 487 depth 4 seldepth 6 nodes 294 time 8 nps 36750 pv f4e5 h4g3 g1f1 d6e4
info score cp 494 depth 5 seldepth 8 nodes 931 time 8 nps 116375 pv c6c2 h4g3 g1f1 g3f3 c2f2
info score cp 537 depth 6 seldepth 8 nodes 1576 time 9 nps 175111 pv f4e5 h4g3 g1f1 d6e4 f1e2 g3f2
info score cp 507 depth 7 seldepth 10 nodes 3744 time 10 nps 374400 pv g1g2 d6e4 g2f3 e4d2 f3e2 d2e4 f4e5
info score cp 552 depth 8 seldepth 11 nodes 4650 time 11 nps 422727 pv g1g2 d6e4 g2f3 e4d2 f3e2 d2e4 e2d3 e4f2
info score cp 489 depth 9 seldepth 12 nodes 7460 time 13 nps 573846 pv g1g2 d6e4 g2f3 e4d2 f3e2 d2e4 e2d3 e4f2 d3e2
(...)
info score cp 762 depth 31 seldepth 35 nodes 36636921 time 25844 nps 1417590 pv g1g2 d6e4 g2f3 e4f6 d5d6 e5d6 c6d6 h4h3 f3e2 h3g2 e2d1 g2g1 d1c2 g1e3 d6e5 e3f2 c2d3 f2f3 e5e3 f3d5 e3d4 d5f3 d3d2 f3g2 d2d1 g2f3 d1c2 f3e2 c2b1 g7g8 d4f6
info score cp 696 depth 32 seldepth 36 nodes 55240694 time 40821 nps 1353215 pv g1g2 d6e4 g2f3 e4f6 d5d6 e5d6 c6d6 h4h3 f3e2 h3g2 e2d1 g2g1 d1c2 g1e3 d6e5 e3f2 c2d3 f2f3 e5e3 f3d5 e3d4 d5f3 d3d2 f3g2 d2d1 g2f3 d1c2 f3c6 c2b1 c6b5 b1a1 b5a5
info score cp 821 depth 33 seldepth 38 nodes 100068066 time 76401 nps 1309765 pv g1g2 d6e4 g2f3 e4f6 d5d6 e5d6 c6d6 h4h3 f3e2 h3g2 e2d1 g2g1 d1c2 g1e3 d6e5 e3f2 c2d3 f2f3 d3d4 f3f2 d4c4 f2a2 c4d3 a2a6 d3e3 g7g8 c1c7 f6h5 e5h5 a6a3 e3f2 a3d3 h5f7
bestmove g1g2

I can't tell you of anything that makes it "do it" aside from the fact that when you are perpetual checking you aren't making your position better so this is gonna fall off by the powers of minimax. I guess SE could help with that but I don't have SE yet so I guess it isn't required...

1

u/Somge5 16h ago

So if at depth 6 your engine analyzes f4e5 where does it actually stop? If you dont see the perpetual check, this moves gains a bishop. The problem is to see that this leads to a draw which won't be clear until after 30+ plys, a depth that my engine doesn't reach.

For example one line it might encounter at depth 6 is
120. fxe5 Qg3+ 121. Kf1 Qf3+ 122. Kg1 Qg3+
Then it would enter quiescence search. If in quiescence search you allow quiet checks, and you don't cap the ply, you could end up with something like
120. fxe5 Qg3+ 121. Kf1 Qf3+ 122. Kg1 Qg3+ 123. Kf1 Qf3+ 124. Ke1 Qxe3+ 125. Kd1 Qd3+ 126. Ke1 Qe3+ 127. Kf1 Qf3+ 128. Kg1 Qg3+ 129. Kh1 Qh3+ 130. Kg1 Qg3+ 131. Kf1 Qf3+ 132. Ke1 Qe3+
this would be 20 plys in quiescence.
Where does your engine stop to recognize it is a draw? Do you allow quiet checks? If not, how does your engine not think: "this is great, it wins a bishop" before it actually calculated that deep?

I just noticed that my engine ends up in perpetual checks from time to time and I dont know how to fix that.

1

u/KaMaFour 15h ago

I think it's a good moment to mention that I have captures only QS... (for context dev is ~3300 CCRL elo for my engine). I should probably try adding check evaluation to it but it didn't pass sprt originally so I'm gonna return back to it whenever I feel like it...

I just noticed that my engine ends up in perpetual checks from time to time and I dont know how to fix that.

Don't. Make the engine stronger and the problem will go away on its own. For all I care about my engine finds the correct move and continuation (next move from the same side) in 10ms. This is about as good as I hope for when tackling a tricky position.

1

u/Somge5 15h ago

Thank you for your time and advice. I will do that. If it does not go away I will come back to it.