Table of Contents

Chess - Programming - Endgame Table-Bases - Encoding

Suppose we have KRvK.

The simplest way to map this position to an index is like this:

index = wK * 64*64 + wR * 64 + bK;

NOTE: This is going to be an array of 64*64*64 = 262144 positions.

  • But with lots of positions being equivalent (because they are mirrors of each other) and lots of positions being invalid (two pieces on one square, adjacent kings, etc.).

Usually the first step is to take the wK and bK together.

Once we have placed the wK and bK, there are 62 squares left for the wR.

wR -= (wR > wK) + (wR > bK);

Example:

wK = 11 (d2)
bK = 32 (a4)

then wR = 63 is mapped to 61 (we skip 11 and 32)
wR = 30 is mapped to 29 (we skip 11), 
and wR = 8 is mapped to 8 (nothing to skip).

We can still improve on 28644.

NOTE: This is for 3 pieces.

  • The extension to 4, 5 and 6 pieces is not all too difficult, but we get new complications once we have like pieces of the same color.
  • For example KRRvK.
    • We do not want to have one index value for R1 on a1, R2 on b1 and another index value for R1 on b1, R2 on a1.
    • We can place two Rs “together” in 62*61/2 ways.
    • If we have 3 Rs, it is 62*61*60/6 ways.
    • If we have 4 Rs, it is 62*61*60*59/24 ways.“

Encode Piece

Encode Piece works like this:


The usual case is “111” (enc_type == 0).

The “only for suicide” case cannot happen: white king and black king ensure j >= 2.

This also means that the “K3” case seems never to occur and could probably be removed.

In principle, “111” does not reduce the index space as much as “K3”.

It was initially thought the “K3” case was useful to have, but then found out that compression is always better if we use “111”.

After the switch(), we place groups of like pieces (RR, RRR, RRRR) together.

The factor[] values have to do with the “best” ordering found by the generator.

Similar story for encode_pawn().

There are special case routines for indexing KKKvNN for suicide chess.


Line by line explanation of the "111" case

We are calculating an index for wK, wR, bK (pos[0], pos[1], pos[2]).

The wK has been mapped to the a1-d1-d4 triangle.

i = pos[1] > pos[0];
int j = (pos[2] > pos[0]) + (pos[2] > pos[1]);

Precalculate the values we will have to deduct from pos[1] and pos[2].

if (OffdiagA1H8[pos[0]])
  idx = Triangle[pos[0]] * 63*62 + (pos[1] - i) * 62 + (pos[2] - j);

wK is below the diagonal.

else 
if (OffdiagA1H8[pos[1]])
  idx = 6*63*62 + Diag[pos[0]] * 28*62 + Lower[pos[1]] * 62 + pos[2] - j;

wK is on the half-diagonal a1-d4, wR is below the diagonal.

else
if (OffdiagA1H8[pos[2]])
  idx = 6*63*62 + 4*28*62 + (Diag[pos[0]]) * 7*28 + (Diag[pos[1]] - i) * 28 + Lower[pos[2]];

Now wK is on the half-diagonal a1-d4, wR is on the diagonal a1-h8, bK is below the diagonal.

else
  idx = 6*63*62 + 4*28*62 + 4*7*28 + (Diag[pos[0]] * 7*6) + (Diag[pos[1]] - i) * 6 + (Diag[pos[2]] - j);

And the final case: all on the diagonal a1-h8.


References

http://www.talkchess.com/forum3/viewtopic.php?t=59947

http://www.talkchess.com/forum3/viewtopic.php?t=59904