some questions about mailbox

Discussion of chess software programming and technical issues.

Moderator: Ras

Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: some questions about mailbox

Post by Sven »

tcusr wrote: Fri Dec 24, 2021 1:40 am

Code: Select all

bool pawn_is_passed(int square, int color)
{
    return neighbor[square][relative_north(color)] == GUARD;
}
bool rook_on_open_file(int square)
{
    return neighbor[square][north] == GUARD && neighbor[square][south] == GUARD;
}

bool is_doubled_pawn(int square, int color)
{
    return neighbor[square][relative_north(color)] == PAWN + color;
}
That pawn_is_passed() function does not look correct to me. A white pawn on d5 is passed if no black pawns are present on c6, c7, d6, d7, e6, e7. The code above seems to test d6 and d7 only.
Sven Schüle (engine author: Jumbo, KnockOut, Surprise)
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

Sven wrote: Fri Dec 24, 2021 7:57 pm
tcusr wrote: Fri Dec 24, 2021 1:40 am

Code: Select all

bool pawn_is_passed(int square, int color)
{
    return neighbor[square][relative_north(color)] == GUARD;
}
bool rook_on_open_file(int square)
{
    return neighbor[square][north] == GUARD && neighbor[square][south] == GUARD;
}

bool is_doubled_pawn(int square, int color)
{
    return neighbor[square][relative_north(color)] == PAWN + color;
}
That pawn_is_passed() function does not look correct to me. A white pawn on d5 is passed if no black pawns are present on c6, c7, d6, d7, e6, e7. The code above seems to test d6 and d7 only.
yeah you're right but that's not important, i quickly wrote it just to get the idea on how to use it
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: some questions about mailbox

Post by Sven »

It is important because a correct implementation using a neighbor table is even more expensive.
Sven Schüle (engine author: Jumbo, KnockOut, Surprise)
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

Sven wrote: Fri Dec 24, 2021 8:48 pm It is important because a correct implementation using a neighbor table is even more expensive.
hgm already answered why it is not important, anyway this should be correct

Code: Select all

bool pawn_is_passed(int square, int color)
{
	if (!((square + 1) & 0x88))
		if (neighbor[square + 1][relative_north(color)] != GUARD)
			return false;
			
	if (!((square - 1) & 0x88))
		if (neighbor[square - 1][relative_north(color)] != GUARD)
			return false;
	
	return neighbor[square][relative_north(color)] == GUARD;
}
is it optimal? no, in this case we should use other techniques but the other examples remain valid
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: some questions about mailbox

Post by hgm »

Pawns that are blocked by pieces other than pawns are still passers, and your code would not see that.

Btw, there is a kind of in-between method, which keeps track of the most-backward pawn in each file not as a rank number, but as a 1-byte bitmap. The maps for all files together than are a sort of bitboard, but never used as a 64-bit int. Calculating the max/minimum then amounts to ORing the masks that belong to the ranks of the pawns (which have the bits corresponding to squares in the file in front of the pawns set to 1). Each pawn can the OR the bytes for neighboring rank, and test the bit corresponding to their own rank. Fruit uses this method.
User avatar
emadsen
Posts: 440
Joined: Thu Apr 26, 2012 1:51 am
Location: Oak Park, IL, USA
Full name: Erik Madsen

Re: some questions about mailbox

Post by emadsen »

hgm wrote: Fri Dec 24, 2021 11:45 am There are more efficient ways for doing that. I like the TSCP method, which first loops through all pawns to determine the most backward one in each file.
That’s true. Actually, that’s what I did in MadChess 1.x and 2.x.

I guess I like the simplicity of eval using bitboards. And less bookkeeping during move generation due to the “magic” of magic bitboard’s perfect hashing.
Erik Madsen | My C# chess engine: https://www.madchess.net
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

hgm wrote: Fri Dec 24, 2021 10:01 pm Pawns that are blocked by pieces other than pawns are still passers, and your code would not see that.
this is more complicated than i thought, i can't just change '!= GUARD' to '& PAWN_FLAG' because there may be a piece before a pawn...
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: some questions about mailbox

Post by hgm »

Indeed, you would need to maintain a second neighbor table which only sees pawns. (I do something like that in my Tenjiku Shogi engine Inferno, because that has to handle pieces that can jump over arbitrary many occupied squares, but not over each other, and these have their own table.) But this might not be competitive. Although you are only interested in vertical neighbors for this application. And in fact you are only interested in the neigbors of the promotion rank. Which is exactly the same as recording the backward-most pawn per file, as in the TSCP algorithm. As mentioned, this can easily be done incrementally. But when you have pawn hash that will be more expensive than calculating it from scratch in the rare case you do have a miss there.

There are so many other aspects of pawn-structure beside passers, which you need to evaluate too (backward, doubled, isolated pawns, (half-)open files, pawns per square shade, pawn-shield quality in each wing, closedness of the position) that hashing all that info is immensely beneficial. A pawn-hash is a must-have.

A refinement is that you could work castling rights into the pawn-hash key, so that you can evaluate the rights in the context of the pawn-shield quality in that direction, and include that in the tabulated score. Most of the game there will be no castling rights at all, so then it just acts like a normal pawn table. Only in the few moves before castling this will increase the number of distinct pawn structure / castling rights combinations, and thus reduce the hit rate somewhat. (But you will likely castle in book anyway, so that this never happens in practice.)
JohnWoe
Posts: 529
Joined: Sat Mar 02, 2013 11:31 pm

Re: some questions about mailbox

Post by JohnWoe »

hgm wrote: Fri Dec 24, 2021 7:29 pm
JohnWoe wrote: Fri Dec 24, 2021 11:58 am FRC code from Mayhem: https://github.com/SamuraiDangyo/mayhem ... .hpp#L1464

This is pretty much the fastest way to check bishops on corners.
In Stockfish 100% the same way.

Code: Select all

// Trapped bishop penalty in FRC
// Bishop on a1/h1/a8/h8 blocked by own pawn
int FixFRC() {
  // No bishop in corner -> Speedup
  constexpr std::uint64_t corners = Bit(0) | Bit(7) | Bit(56) | Bit(63);
  if (!((g_board->white[2] | g_board->black[2]) & corners))
    return 0;

  auto s = 0;
  if (g_board->pieces[0]  == +3 && g_board->pieces[9]  == +1) s -= FRC_PENALTY;
  if (g_board->pieces[7]  == +3 && g_board->pieces[14] == +1) s -= FRC_PENALTY;
  if (g_board->pieces[56] == -3 && g_board->pieces[49] == -1) s += FRC_PENALTY;
  if (g_board->pieces[63] == -3 && g_board->pieces[54] == -1) s += FRC_PENALTY;
  return s;
}
It occurred to me that this could be done infinitely faster, as a completely free side effect of evaluating the castling rights: next to the 4 flags that indicate which castling rights exist, you add 4 flags for indicating which bishops are still trapped in a corner. The spoilers for the squares where bishops and the pawns that block those start would clear those bits when they move or get captured, just as moving king or rook clear castling rights. The flag word is than used to index a 256-entry table in which you can look up the applicable eval bonus (for castling rights) plus penalty (for the bishop trapping).
I doubt there's much Elo. This is Stockfish implementation. Some extra noise but pretty close to mine: https://github.com/official-stockfish/S ... .cpp#L1047

Your idea would be faster. IIRC. To clear trapped flags when B2 pawns moves and bishop exist on A1. etc But this is so rare it doesn't matter. But w/o this fix bishops are trapped forever.
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: some questions about mailbox

Post by hgm »

Of course there is no measurable Elo in micro-optimalizations like this. But the reasoning "this only takes <small number> percent of the execution time, so it makes no sense to optimize it" is flawed: if you have 100 routines that each take only 1%, and make each of those twice as fast, your program is still twice faster. I also brought it up to falsify the idea "this is how Stockfish does it, so it is the best possible solution".

Btw, the more I think about it, the more I like the idea of working both castling rights and trapped bishops in the pawn hash key. The trapping condition can be accounted together with the castling rights, through the usual spoiler mechanism. The rights byte can then be used as index in a table of Zobrist keys, rather than indexing scores directly. The selected key can then be XORed with the pawn key before accessing the pawn hash table. That way the castling rights can be evaluated in the context of the pawn structure in the corresponding wing.