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
619 stars 196 forks source link

Game glitches when Reversi encloses a wall #654

Closed RainRat closed 1 year ago

RainRat commented 1 year ago

No game uses this combination yet, but if a Reversi encloses a wall, the game glitches out (loses track of everything).

INI to reproduce:

[annexation:flipello]
maxRank = 10
maxFile = 10
startFen = **4**/**4**/**4**/10/4pP4/4Pp4/10/**4**/**4**/**4**[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1
enclosingDropStart = 0
ianfab commented 1 year ago

Thanks for reporting. I can imagine that this causes problems. The start FEN looks invalid though, but I guess the same might happen even with a valid FEN.

ianfab commented 1 year ago

I just tried with a valid FEN (***4***/***4***/***4***/10/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1) and it didn't immediately show misbehavior. Can you give a specific sequence of commands to reproduce it with a valid FEN?

RainRat commented 1 year ago

Possible game to reproduce:

1. P@g5 P@g6 2. P@g7 P@h6 3. P@h7 P@f8 4. P@g8 P@h4 5. P@i6 P@i5 6. P@h5 P@i7 7. P@j5 P@j4 8. P@i4 P@g4 9. P@g3 P@f7

Synthetic FEN:

startFen = ***4***/**4p***/**4p***/5PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1

Then place the piece at g10

ianfab commented 1 year ago

Thanks, now I see a corrupted FEN in the output

load <<EOF
[annexation:flipello]
maxRank = 10
maxFile = 10
startFen = ***4***/**4p***/**4p***/5PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1
enclosingDropStart = -
EOF

setoption name UCI_Variant value annexation
position startpos
d
position startpos moves P@g10
d
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |10   [pppppppppppppppppppppppppppppppppppp]
 +---+---+---+---+---+---+---+---+---+---+
 | * | * |   |   |   |   | p | * | * | * |9
 +---+---+---+---+---+---+---+---+---+---+
 | * | * |   |   |   |   | p | * | * | * |8
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | P | P | P | P | P |7
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | p | P |   |   |   |6
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | P | p |   |   |   |5
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |   |   |4
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |3
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |2
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |1 * [PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP]
 +---+---+---+---+---+---+---+---+---+---+
   a   b   c   d   e   f   g   h   i   j

Fen: ***4***/**4p***/**4p***/5PPPPP/5pP3/5Pp3/10/1***4**/1***4**/1***4**[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w - - 0 1
Sfen: ***4***/**4p***/**4p***/5PPPPP/5pP3/5Pp3/10/1***4**/1***4**/1***4** b 36P36p 1
Key: 7DE55B9A4D597738
Checkers: 
Chased: 

 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | P | * | * | * |10 * [pppppppppppppppppppppppppppppppppppp]
 +---+---+---+---+---+---+---+---+---+---+
 | * | * |   |   |   |   | P | * | * | * |9
 +---+---+---+---+---+---+---+---+---+---+
 | * | * |   |   |   |   | P | * | * | * |8
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | P | P | P | P | P |7
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | p | P |   |   |   |6
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   | P | p |   |   |   |5
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |   |   |4
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |3
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |2
 +---+---+---+---+---+---+---+---+---+---+
 |   | * | * | * |   |   |   |   | * | * |1   [PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP]
 +---+---+---+---+---+---+---+---+---+---+
   a   b   c   d   e   f   g   h   i   j

Fen: ***3P***/**4P **/**4P* */5PPPPP/5pP3/5Pp3/10/1***4**/1***4**/1***4**[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] b - - 0 1
Sfen: ***3P***/**4P **/**4P* */5PPPPP/5pP3/5Pp3/10/1***4**/1***4**/1***4** w 35P36p 2
Key: 3E92A0D9AAECFDDC
Checkers: 
Chased: 
RainRat commented 1 year ago

I was looking into this and realized I sent the wrong synthetic FEN. I redid your test with the right one.

Fairy-Stockfish 070623 LB by Fabian Fichter
load <<EOF
[annexation:flipello]
maxRank = 10
maxFile = 10
startFen = ***4***/***3p***/***3p***/4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1
enclosingDropStart = -
EOF

setoption name UCI_Variant value annexation
info string variant annexation files 10 ranks 10 pocket 1 template fairy startpos ***4***/***3p***/***3p***/4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w 0 1
position startpos
d

 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |10   [pppppppppppppppppppppppppppppppppppp]
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | p | * | * | * |9
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | p | * | * | * |8
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | P | P | P | P | P | P |7
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | p | P |   |   |   |   |6
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | P | p |   |   |   |   |5
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |   |   |4
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |3
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |2
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |1 * [PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP]
 +---+---+---+---+---+---+---+---+---+---+
   a   b   c   d   e   f   g   h   i   j

Fen: ***4***/***3p***/***3p***/4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] w - - 0 1
Sfen: ***4***/***3p***/***3p***/4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4*** b 36P36p 1
Key: D60CB76221205DCA
Checkers:
Chased:
position startpos moves P@g10
d

 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | P | * | * | * |10 * [pppppppppppppppppppppppppppppppppppp]
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | P | * | * | * |9
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   | P | * | * | * |8
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | P | P | P | P | P | P |7
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | p | P |   |   |   |   |6
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   | P | p |   |   |   |   |5
 +---+---+---+---+---+---+---+---+---+---+
 |   |   |   |   |   |   |   |   |   |   |4
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |3
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |2
 +---+---+---+---+---+---+---+---+---+---+
 | * | * | * |   |   |   |   | * | * | * |1   [PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP]
 +---+---+---+---+---+---+---+---+---+---+
   a   b   c   d   e   f   g   h   i   j

Fen: ***3P***/***3P **/***3P* */4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4***[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppppppp] b - - 0 1
Sfen: ***3P***/***3P **/***3P* */4PPPPPP/4pP4/4Pp4/10/***4***/***4***/***4*** w 35P36p 2
Key: 957B4C21C695D72E
Checkers:
Chased:

The bug is still real though; there's spaces in the output FEN, and the engine fails to analyse the position further.

The fix would be to take into account wall squares by adding | st->wallSquares

This is my reasoning:

Bitboard b = attacks_bb(us, QUEEN, to, board_bb() & ((~           pieces(~us)) | st->wallSquares)) & ~PseudoAttacks[us][KING][to] & pieces(us);
//                                                   (us+empty)   (wall+opp)    (us+empty+wall)  
//This parameter is the occupied squares   ^^^  so                              ^^^^^^^^^^^^^^^ should block a reversi from connecting
  1. pieces(~us) is walls + opponent pieces
  2. ~ negated is our pieces + empty
  3. | st->wallSquares adds wall squares to the list, so ours+empty+wall are considered 'occupied' so those three prevent a Reversi from connecting.

There's also Reversi code in evaluate.cpp, but I haven't thought about how walls change evaluation.

ianfab commented 1 year ago

Thanks for looking into it. I am slightly puzzled though. Shouldn't pieces(~us) be just our opponent's pieces and therefore ~pieces(~us) empty+ours+walls?

The only bitboard where wall squares are included is the byTypeBB[ALL_PIECES] and this is only returned by pieces(). All other pieces(...) methods use additional masks, e.g., the byColorBB, which doesn't (or at least shouldn't) include the walls.

I think the issue might be that board_bb() excludes wall squares, meaning that they are considered as empty for purposes of this attacks_bb. However, looking at it now I do not understand why this mask is even there, because there should be no harm in also considering squares outside the board as blocked and actually is more consistent. So maybe removing board_bb() & might already be sufficient? What do you think?

RainRat commented 1 year ago

My logic could very well be wrong; I tried to figure it out from the code. I retried:

st->wallSquares board_bb() & Result
No No Fine
Yes No Fine
Yes Yes Glitch
No Yes Glitch

So it appears removing board_bb() & works, and st->wallSquares is irrelevant. I don't know what happened, must have made some mistake in testing.