This guide explains how to play and analyze Fog-of-War (FoW) chess variants using Fairy-Stockfish from the command line.
In Fog-of-War chess, players can only see squares that their pieces can attack or move to. The opponent's pieces on unseen squares are hidden, creating an imperfect information game similar to poker or StarCraft.
Fairy-Stockfish supports three FoW-based variants:
- fogofwar: Standard chess with fog-of-war rules
- darkcrazyhouse: Crazyhouse with fog-of-war rules. When you have a piece in hand, all empty squares are visible (you can drop anywhere)
- darkcrazyhouse2: Crazyhouse with fog-of-war rules. You can only drop pieces on visible squares (standard FoW vision rules apply)
- Start Fairy-Stockfish and initialize UCI:
uci
- Select the FoW variant:
setoption name UCI_Variant value fogofwar
- Set up the starting position:
position startpos
- Make moves and get the fog view:
position startpos moves e2e4
go movetime 1000
- The engine will search and return its best move considering the fog-of-war rules.
- Set the protocol:
xboard
- Select the variant:
variant fogofwar
- (Optional) Display the board:
d
- Make your first move:
e2e4
- Ask the engine to play:
go
- Continue playing by making moves. The engine will automatically reply after the first
gocommand.
Fairy-Stockfish includes an advanced search algorithm specifically designed for imperfect information games, based on the Obscuro research paper. This uses game-theoretic search techniques including:
- Belief state management: Tracks all possible board states consistent with observations
- Counterfactual Regret Minimization (CFR): Computes Nash equilibrium strategies
- Knowledge-Limited Subgame Solving (KLUSS): Solves local subgames efficiently
- Game-Theoretic CFR expansion: Explores the game tree using PUCT selection
To use the advanced imperfect information search:
uci
setoption name UCI_Variant value fogofwar
setoption name UCI_FoW value true
setoption name UCI_IISearch value true
position startpos
go movetime 5000
The following UCI options control the Obscuro search behavior:
Enable Fog-of-War search mode. Must be set to true to use imperfect information search.
setoption name UCI_FoW value true
Enable Imperfect Information Search. When true, uses the full Obscuro algorithm. When false, uses simplified search.
setoption name UCI_IISearch value true
Minimum number of nodes in an information set before expansion. Larger values create bigger subgames, improving solution quality but increasing computation time.
setoption name UCI_MinInfosetSize value 256
Number of threads for GT-CFR expansion (PUCT-based game tree exploration). More threads explore more branches in parallel.
setoption name UCI_ExpansionThreads value 2
Number of threads for CFR solving. Typically 1 is sufficient since CFR is memory-bound.
setoption name UCI_CFRThreads value 1
Maximum support for action purification (max number of actions to consider). Lower values force more deterministic play, higher values allow more mixed strategies.
setoption name UCI_PurifySupport value 3
Exploration constant for PUCT selection in GT-CFR. Higher values encourage more exploration, lower values focus on exploitation.
setoption name UCI_PUCT_C value 100
Time budget in milliseconds for FoW search. The planner will use approximately this much time to compute strategies before selecting an action.
setoption name UCI_FoW_TimeMs value 5000
Here's a complete example configuring all FoW options for strong play:
uci
setoption name UCI_Variant value fogofwar
setoption name UCI_FoW value true
setoption name UCI_IISearch value true
setoption name UCI_MinInfosetSize value 512
setoption name UCI_ExpansionThreads value 4
setoption name UCI_CFRThreads value 1
setoption name UCI_PurifySupport value 3
setoption name UCI_PUCT_C value 100
setoption name UCI_FoW_TimeMs value 10000
position startpos
go
Fast play (weaker but quick):
setoption name UCI_MinInfosetSize value 128
setoption name UCI_ExpansionThreads value 1
setoption name UCI_FoW_TimeMs value 1000
Strong play (slower but better):
setoption name UCI_MinInfosetSize value 1024
setoption name UCI_ExpansionThreads value 8
setoption name UCI_FoW_TimeMs value 30000
Blitz/Bullet (very fast):
setoption name UCI_MinInfosetSize value 64
setoption name UCI_ExpansionThreads value 2
setoption name UCI_FoW_TimeMs value 500
Dark Crazyhouse combines Crazyhouse rules (captured pieces can be dropped back on the board) with Fog-of-War. When you have a piece in hand, all empty squares become visible, allowing you to drop anywhere:
uci
setoption name UCI_Variant value darkcrazyhouse
setoption name UCI_FoW value true
position startpos
go movetime 5000
Key features:
- Not knowing what pieces your opponent has in their hand
- When you capture a piece and have it in hand, you can see all empty squares
- Drops allowed on any empty square when you have pieces
- Managing your own captured pieces while dealing with incomplete information
Dark Crazyhouse 2 is a more restrictive variant where you can only drop pieces on squares you can see (based on standard FoW vision rules):
uci
setoption name UCI_Variant value darkcrazyhouse2
setoption name UCI_FoW value true
position startpos
go movetime 5000
Key differences from Dark Crazyhouse:
- Drops restricted to visible squares only
- No automatic visibility of empty squares when holding pieces
- More strategic piece placement required
- Surprise drops only possible in areas your pieces can already see
To analyze a specific position where you know the full board state, use the position fen command:
uci
setoption name UCI_Variant value fogofwar
setoption name UCI_FoW value true
position fen rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1
go infinite
To stop the search:
stop
When you only know what you can see (your observation), use position fog_fen to specify the partial observation. This is useful for analyzing positions from the perspective of a player who has incomplete information:
uci
setoption name UCI_Variant value darkcrazyhouse2
setoption name UCI_FoW value true
setoption name UCI_IISearch value true
setoption name UCI_FoW_TimeMs value 10000
position fog_fen ????????/??????pp/1?????1P/?1??p1?1/8/1P2P3/PB1P1PP1/NQ1NRBKR b KQk - 0 8
go infinite
In a fog FEN:
?(or*) represents unknown/fogged squares- Visible pieces are shown normally (e.g.,
p,P,N, etc.) - Empty visible squares are shown as part of the rank count (e.g.,
8,1)
The engine will:
- Parse and store the fog FEN
- Enumerate positions consistent with what the fog FEN shows (permuting hidden opponent pieces across unseen squares)
- Use that belief state to guide the Obscuro search before selecting a move
The engine internally tracks what each player can see. When making moves via UCI, the engine automatically:
- Updates the true game state
- Computes visibility for the side to move
- Builds a belief state (set of consistent positions)
- Searches over the belief state to find the best move
Note: The standard UCI protocol does not have a built-in command to display the fog view from the command line. To get the fog view, you would need to use a GUI that supports FoW or query via the pyffish Python bindings:
import pyffish as sf
fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
fog_fen = sf.get_fog_fen(fen, "fogofwar")
print(fog_fen) # Shows what black sees (e.g., "********/********/...")All three FoW variants use NNUE (neural network) evaluation:
- fogofwar: Uses standard chess NNUE
- darkcrazyhouse: Uses crazyhouse NNUE
- darkcrazyhouse2: Uses crazyhouse NNUE
The Obscuro search algorithm (CFR, KLUSS, GT-CFR) is for search (deciding which positions to evaluate), while NNUE is for evaluation (scoring individual positions). They work together seamlessly:
- The search explores the game tree and belief states
- NNUE evaluates leaf positions to guide the search
- The fact that pieces use "commoner" instead of "king" doesn't affect NNUE
Note: NNUE networks are trained on complete-information games. In FoW positions, NNUE evaluates each possible board state in the belief set as if it were a standard chess/crazyhouse position. The search algorithm then aggregates these evaluations to make decisions under uncertainty.
From the Obscuro paper (Appendix A), the key fog-of-war rules are:
- Vision: You see all squares your pieces can attack or move to
- Pawn vision: Pawns reveal their diagonal attack squares (even if empty)
- Blocked pieces: You see the blocking piece but not squares beyond it
- En passant: The en passant square is revealed if you have a pawn that can capture it
- Castling: You can only castle if you can see that the king/rook haven't moved
- Check: You may not know you're in check if the attacking piece is in fog
- Time management: Set
UCI_FoW_TimeMsappropriately for your time control - Thread allocation: More expansion threads help with complex positions
- Information set size: Larger values are better for endgames, smaller for opening/middlegame
- Purification support: Keep at 3 for balanced play, reduce to 1-2 for more tactical positions
Engine is too slow: Reduce UCI_MinInfosetSize, UCI_ExpansionThreads, or UCI_FoW_TimeMs
Engine plays poorly: Increase UCI_MinInfosetSize and UCI_FoW_TimeMs, add more UCI_ExpansionThreads
Engine doesn't respond: Make sure you set position startpos or position fen ... after selecting the variant
FoW search not working: Verify both UCI_FoW value true and UCI_IISearch value true are set
- Obscuro paper: "Optimal play in imperfect-information games using counterfactual regret minimization"
- FoW chess rules: See paper Appendix A
- UCI protocol: http://wbec-ridderkerk.nl/html/UCIProtocol.html
- Fairy-Stockfish: https://github.com/fairy-stockfish/Fairy-Stockfish
The current implementation includes:
- ✅ Core Obscuro algorithm (CFR, KLUSS, GT-CFR)
- ✅ FoW visibility computation (Appendix A rules)
- ✅ UCI integration and options
- ✅ Multi-threaded search (1 CFR solver + 2 expanders)
- ✅ fog_fen parsing wired into belief state enumeration
- ✅ Belief state management (enumerates hidden opponent permutations up to 1024 states per observation)
- ✅ NNUE evaluation for all FoW variants
⚠️ Action purification (placeholder implementation)⚠️ KLUSS order-2 neighborhood is still simplified⚠️ Resolve/Maxmargin gadget details are incomplete- 🔲 Instrumentation (Appendix B.4 metrics)
What Works:
- The engine runs FoW search and returns moves
- UCI options are properly parsed and applied
- Multi-threaded CFR solver and expanders run correctly
- The fog_fen command parses and stores partial observations
What Doesn't Work Yet:
-
Belief diversity limits: Enumeration permutes hidden opponent pieces from the current position and caps at 1024 states; it does not yet model captures beyond the observed piece set or piece-in-hand drops for crazyhouse variants.
-
KLUSS neighborhood: The KLUSS computation is still a placeholder and does not freeze/unfreeze infosets per the paper's order-2 definition.
-
Purification and gadgets: Action purification and Resolve/Maxmargin gadget details remain simplified, so play quality may vary in tricky information sets.
Current best use case: Using position fog_fen to explore imperfect-information situations where hidden opponent pieces could be on multiple unseen squares. The engine will enumerate those possibilities and search them, but higher-level gadgets and purification are still simplified.
Not yet suitable for: Positions that rely on advanced KLUSS freezing/unfreezing logic or deep purification requirements (e.g., adversarial bluffing scenarios and crazyhouse drop speculation).
For development status and technical details, see OBSCURO_FOW_IMPLEMENTATION.md.