Indeed, there is nothing against mixed or redundant representations. (Most bitboard engines also use a mailbox board, for fast identification of victim type.) I think that Fruit 2.1 detects passers the way you describe. But the incremental update is a pain, because you would have to do it on every move to make sure the info is available when you get a pawn-hash miss. It is bad enough you have to incrementally update the pawn hash key. But however you do it, evaluation of pawn structure is important in chess, and complex. So you will always gain a lot by using a pawn hash table. And once you do, it doesn't matter much how costly it is to process a miss, as you won't have many misses. But it would probably not be a good idea to maintain other pawn data incrementally on every move.gaard wrote: ↑Fri Nov 26, 2021 8:35 amCheating should be allowed. If you add a member to you board structure like uint8_t pawn_on_files[ColorCount][1 + 8 + 1], where pawn_on_files[0/1][0/9] are off-board, and assuming the lsb of pawn_on_files[0/1][1-8] are rank 1 and the msb is rank 8, you can combine the benefits of mailbox with pseudo-bitboards if you update it incrementally. With a hash table the difference is probably a wash though, since the hit rate will be above 90%.
It always annoyed me having to update the pawn hash key. It can change both when the moving piece is a pawn and when a pawn gets captured, and if statements that test whether the piece is a pawn are poorly predictable. So I usually maintain the pawn key just like the main hash key, unconditionally applying the key changes due to mover and victim. Except that they use Zobrist tables where all non-pawns have a table of all zeroes. This doesn't require much extra space, as I usually implement the Zobrist tables as an array of pointers indexed by piece number (so basically part of the piece list), which point to a board-size table of keys. That way pieces of the same type can point to the same table, so you just need 2x6 tables for the piece types, plus a 'null table' for the empty square (which acts as 'victim' of a non-capture, so that you can unconditionally update the key for the victim contribution too). For the pawn has I have a similar array of pointers, where all the pointers for non-pawns point to the null table.
I often wondered if one could not combine both keys into one: use one 64-bit key, but use only N bits for the non-pawns, the remaining part of the key for those being zero. If Stockfish can get away with using 16 bits as hash signature for the main TT, you could probably also do that for the signature of the pawn hash: collisions there would not be ay more harmful than collisions in the TT. And with a 32-byte entry a 1MB pawn hash table would only have 2^15 entries, so only 15 bits are needed for the index. So only 32 bits of pawn key are needed, and the other 32 bits could then be used to distinguish constellations of the other pieces.