fairy-stockfish / Fairy-Stockfish

chess variant engine supporting Xiangqi, Shogi, Janggi, Makruk, S-Chess, Crazyhouse, Bughouse, and many more
https://fairy-stockfish.github.io/
GNU General Public License v3.0
594 stars 186 forks source link

Control virtual piece drops #812

Open amatveiakin opened 3 weeks ago

amatveiakin commented 3 weeks ago

Is it possible to add control over virtual piece drops (https://github.com/fairy-stockfish/Fairy-Stockfish/issues/122)?

I have been experimenting with FSF for bughouse game analysis, and I found that the current implementation has some drawbacks.

First, it doesn't take time difference into account AFAICT. Whereas time is crucial when making these decisions: if a team has less time, their opponents could sit whenever they need a piece.

Second, virtual reserve is currently hard-coded to: one major piece OR one minor piece and one pawn OR two pawns. This could lead to nonsensical situations where the engine suggests to drop a piece which you couldn't possibly have. For example, in this position

(FEN: 2nk2r1/2pppp2/8/N7/PPP5/RRP4K/QRP5/QR6[q] w - - 0 1) the engine output is:

info depth 59 seldepth 4 multipv 1 score cp 1410 nodes 2255553 nps 603896 hashfull 498 tbhits 0 time 3735 pv a5b7 d8e8 R@d8

So FSF feels pretty optimistic about the line with a dropped rook (R@d8), even though the player already has four rooks.

Putting absurd examples like this aside, it's often possible to tell in practice that a given piece is not likely to become available, because they are all in opponent's reserve and/or well-defended.

So I was thinking, maybe there should be a protocol to set “potentially available” pieces? You could set it to “auto” to get the heuristics, to “none” if the current team has less time (or you just don't like the feature), or to something explicit based on which pieces on the other board are under attack.

ianfab commented 3 weeks ago

The "virtual piece drops" are a very crude hack to make it a bit less naive for e.g. simple f7 mates. Ultimately I think using these "virtual drops" in the framework of an alpha-beta search doesn't make much sense at all, it would be way more natural in an MCTS search where you easily can have random actions not being subject to maximization by either player. Therefore I am somewhat sceptical about extending this hack.

However, time is considered in that regard, see https://github.com/fairy-stockfish/Fairy-Stockfish/blob/81dd96cd0ee62172635ad90caa60db69fab2906e/src/thread.cpp#L198 However, for this to apply you need to use the CECP/xboard protocol, as for most of the features related to bughouse.

amatveiakin commented 3 weeks ago

However, for this to apply you need to use the CECP/xboard protocol, as for most of the features related to bughouse.

Oh, I see. I took the fairy-stockfish-nnue-wasm-demo, copied the engine loading logic from analysis.html and then did

setoption name UCI_Variant value bughouse
position fen <my_position>
go

You are saying this is not the correct way to apply Fairy Stockfish to bughouse?

ianfab commented 3 weeks ago

It isn't wrong, it is just that it is somewhat tricky to handle a real time game in a stateless protocol like UCI, so all bughouse engines and interfaces I am aware of use the stateful CECP/xboard, so I did the same. It can still play bughouse in UCI, but all the player communication/commands like sit/go, etc., as well as bughouse time management is only implemented for the CECP protocol so far.

amatveiakin commented 3 weeks ago

That's true. I wasn't concerned about it so far, because I only tried to do game analysis.

I'd say it's a bug that I got any virtual moves in my setup if FSF is only supposed to produce them when there is a definite time advantage. Could it be because PartnerHandler::reset is not called on ucinewgame?

Ultimately I think using these "virtual drops" in the framework of an alpha-beta search doesn't make much sense at all

I understand the concern. I don't have a strong intuition one way or another. We could test it empirically. If the engine plays noticeably stronger with virtual moves, then I guess they make sense? I could try to do an experiment one day (wouldn't promise that I'll get to it though). Do you have a ready-to-use setup for comparing two engine versions?

ianfab commented 3 weeks ago

https://github.com/fairy-stockfish/fairyfishtest is what I was using to test bughouse improvements, including the virtual drops. I am not opposed to tweaking virtual drops, just towards expanding them, e.g., by making them configurable, because once exposed to the user it is hard to remove.

amatveiakin commented 3 weeks ago

Got it. Agree that exposed APIs are hard to walk back.

Do I understand correctly that https://github.com/fairy-stockfish/Fairy-Stockfish/blob/81dd96cd0ee62172635ad90caa60db69fab2906e/src/thread.cpp#L198 only disables virtual drops when considering the very first move? It seems to me both from the code and from my experience with the engine that further down the line virtual drops are always enabled (but I haven't familiarized myself with the codebase enough to be sure). If so, is there a way to disable virtual drops completely?

ianfab commented 3 weeks ago

I don't remember whether there is a way to completely disable it, but I think no. The reasoning for the code you are referring to is that we only know for sure that we are up/down on time now, i.e., whether we can sit for a piece. On future moves some (random) piece flow will likely still happen in general regardless, and the time situation can invert as well, we only know for sure that we either can or can't sit right now. Obviously this is a bit of a simplification, but I think a much more clean reasoning than for the other rather arbitrary virtual drop conditions.