some questions about mailbox

Discussion of chess software programming and technical issues.

Moderator: Ras

tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

reviving this thread because of a new discovery which could really speed up evaluation for mailbox engines.
let's start with this declaration

Code: Select all

uint8_t fi[2][8]; // files info
now we run through all the pawns and update it like this

Code: Select all

fi[side][file(sq)] |= 1 << rank(sq);
this way we have all the information we want about pawns and files with just one look up and some operations, no loops.
some examples:

Code: Select all

bool is_on_openf(int sq)
{
	return fi[0][file(sq)] + fi[1][file(sq)] == 0;
}

bool is_on_semiopenf(int sq, int side)
{
	return fi[side][file(sq)] == 0;
}

// no enemy pawns in front of us
bool free_run(int sq, int side)
{
	return fi[side ^ 1][file(sq)] >> rank(sq) == 0;
}

// doubled pawns: more than one bit set on file(sq)
there's probably another way to check for passed pawns other than calling free_run() 3 times.
since the bits are ordered by rank from white's POV one could check if a file is greater/lesser than the other one.

the nice thing about this is that the table can be updated incrementally and we don't need to check the board/piece list for pawns because we just run a loop through all the files and apply all the bonuses/maluses.

i have to say that i really using a mailbox representation, the code is simpler and i have to actually use my brain, maybe hgm was right all along...
what do you guys think?
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

i only now realized that that's basically a poor man's bitboard...i feel stupid
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

actually no it's not stupid, Fruit 2.1 seems to do the same thing and also Rebel from what i was able to understand by reading some of his old posts.
i came up with it on my own but i just have to accept that most of the chess programming has been studied to death so it's easy for things like this to happen, it's not the first time anyway...
i guess now nothing stops me from writing a really detailed eval in a competitive way for a mailbox engine.
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

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;
}
only know that i'm writing an eval i'm wondering why should i do this, shouldn't this be already included in the mobility eval?
the so called "blockers loops" usually stop at 3-4 iteration and execute no code so they should be really fast

Code: Select all

for (to = from + inc; board[to] == empty; to += inc) {}
edit:
actually no the only they might execute is something like: mobility += bonus;
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 »

A neighbor table would save you the work of such loops, as it directly tells you where the blockers in the various directions are. You could use that info for accessing a distance table. (In my engine Inferno I even tabulate the distances to neighbors directly, rather than the square they are on, as the square numbers there do not fit in a byte due to the large board.)

You could even keep track of that info incrementally, i.e. maintain tables for Bishop and Rook mobility on every occupied square. When you update the neighbor table for evacuation of a square you can then increase the applicable (diagonal or orthogonal) mobility of the neighbors by the amount of path that was added into the direction towards the evacuated square. Like

for(direction=1; direction<8; direction += 2) diagMobility[sqr] += distance[sqr - neighbor[sqr][direction]];

and similar for orthMobility. The loop would be unrolled by the compiler, and has no branches, as it always has 4 iterations. That basically reduces the work for calculating mobility to a single Queen mobility per node, (by the accelerated lookup method). In the evaluation you can then simply look up the mobility for the squares the Rooks and Bishops are on, and for a Queen you look up both, and add those.

Only in case of a non-capture (about 6% of the moves) you would have to do account for occupation of an empty square. This still requires the blocking loops for the update of the neighbor table for the occupied square. But again these then give the mobility changes as a nearly free side effect.
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

hgm wrote: Sat Feb 05, 2022 2:31 pm A neighbor table would save you the work of such loops, as it directly tells you where the blockers in the various directions are. You could use that info for accessing a distance table. (In my engine Inferno I even tabulate the distances to neighbors directly, rather than the square they are on, as the square numbers there do not fit in a byte due to the large board.)

You could even keep track of that info incrementally, i.e. maintain tables for Bishop and Rook mobility on every occupied square. When you update the neighbor table for evacuation of a square you can then increase the applicable (diagonal or orthogonal) mobility of the neighbors by the amount of path that was added into the direction towards the evacuated square. Like

for(direction=1; direction<8; direction += 2) diagMobility[sqr] += distance[sqr - neighbor[sqr][direction]];

and similar for orthMobility. The loop would be unrolled by the compiler, and has no branches, as it always has 4 iterations. That basically reduces the work for calculating mobility to a single Queen mobility per node, (by the accelerated lookup method). In the evaluation you can then simply look up the mobility for the squares the Rooks and Bishops are on, and for a Queen you look up both, and add those.

Only in case of a non-capture (about 6% of the moves) you would have to do account for occupation of an empty square. This still requires the blocking loops for the update of the neighbor table for the occupied square. But again these then give the mobility changes as a nearly free side effect.
my idea of mobility is not only possibly attacked squares, also x-rays etc...
the neighbor table is certainly useful but may i ask why you are against blocker loops? many really strong engines (Fruit, Loop) and if they find them good enough so do i
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 »

Well, blocker loops are slow. They require many iterations, and usually a branch mispredict at the end, because the number of iterations varies. Now speed of course only makes a small contribution to strength, but is is still a non-zero contribution, so most people like their engine to be as fast as possible. However strong Fruit and Loop might be, make them twice faster and they would still be 50-70 Elo stronger.
JohnWoe
Posts: 529
Joined: Sat Mar 02, 2013 11:31 pm

Re: some questions about mailbox

Post by JohnWoe »

tcusr wrote: Fri Feb 04, 2022 3:56 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;
}
only know that i'm writing an eval i'm wondering why should i do this, shouldn't this be already included in the mobility eval?
the so called "blockers loops" usually stop at 3-4 iteration and execute no code so they should be really fast

Code: Select all

for (to = from + inc; board[to] == empty; to += inc) {}
edit:
actually no the only they might execute is something like: mobility += bonus;
This fix is for Chess960 only. If your engine supports it then yes. Mobility alone probably isn't enough encouraging getting bishop out of a1 enough. I give heavy penalty on B on a1/etc. My HCE is super simple and fast.
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 »

If mobility alone is not enough, this suggest there is something fundamentally wrong in the mobility eval. Because the only reason for pushing that Pawn is to give the Bishop mobility.

The aspect that conventional mobility evaluation (i.e. proportional to the number of moves) fails to take into account, is that several moves in the same direction are likely worth less than moves in different directions, and no moves in any direction is exceptionally bad.
tcusr
Posts: 325
Joined: Tue Aug 31, 2021 10:32 pm
Full name: tcusr

Re: some questions about mailbox

Post by tcusr »

hgm wrote: Mon Feb 07, 2022 10:39 pm If mobility alone is not enough, this suggest there is something fundamentally wrong in the mobility eval. Because the only reason for pushing that Pawn is to give the Bishop mobility.

The aspect that conventional mobility evaluation (i.e. proportional to the number of moves) fails to take into account, is that several moves in the same direction are likely worth less than moves in different directions, and no moves in any direction is exceptionally bad.
with mailbox it's easy, decrement the bonus while advancing to the direction.
i don't know how i would do it with bitboards