Tablebase suggestion

Discussion of anything and everything relating to chess playing software and machines.

Moderator: Ras

Rein Halbersma
Posts: 770
Joined: Tue May 22, 2007 11:13 am

Re: Tablebase suggestion

Post by Rein Halbersma »

Ajedrecista wrote: Mon Mar 02, 2026 8:22 pm
17v15 and 18v17 have got the same number of positions, this is not a typo from copy and paste. I hope you will find these numbers useful.
Correct, because 17v15 has 18 empty squares and 18v17 has 15 empty squares. So the total is 50!/(18! * 17! * 15!) in both cases
Rein Halbersma
Posts: 770
Joined: Tue May 22, 2007 11:13 am

Re: Tablebase suggestion

Post by Rein Halbersma »

syzygy wrote: Mon Mar 02, 2026 9:33 pm Indeed not bad at all. And 75.5 GB vs 87.4 GB is probably not going to make the difference for the feasiblity of the computation.
And a 2-bit per position WDL database (typically what is used during search) for 5v5 kings is then just under 175gb.
syzygy
Posts: 5938
Joined: Tue Feb 28, 2012 11:56 pm

Re: Tablebase suggestion

Post by syzygy »

Rein Halbersma wrote: Mon Mar 02, 2026 11:39 pm
syzygy wrote: Mon Mar 02, 2026 10:12 pm I don't know if you can do this in the first iteration. It seems to make more sense to reduce the final compressed file size than to reduce generation time, because it would seem to add a lot of extra computation.
I have to think about this. I'd much rather remove all non-canonical positions up front (similar to eliminating illegal board configurations) and not having to repeat these calculations. It's rather easy to detect whether the non-leading orbit kings move into forbidden territory (square index above the mtwist value) than having to think about full or partial symmetry breaking, and diagonals being fixed points of certains symmetries but not others. The dihedral group is just small enough to brute force all this.
I see. I have to think about this as well. I was thinking unmoving between lexicographically minimal representatives was going to be a hassle. But if you can do that and thereby create an indexing function that assigns to each position a unique number (but just has a somewhat larger indexing range than optimal), then that would make everything else a lot easier.
Rein Halbersma
Posts: 770
Joined: Tue May 22, 2007 11:13 am

Re: Tablebase suggestion

Post by Rein Halbersma »

syzygy wrote: Tue Mar 03, 2026 12:30 am I see. I have to think about this as well. I was thinking unmoving between lexicographically minimal representatives was going to be a hassle. But if you can do that and thereby create an indexing function that assigns to each position a unique number (but just has a somewhat larger indexing range than optimal), then that would make everything else a lot easier.
In your triangle+mtwist indexing, you fixate the symmetry by the leading orbit configuration. So any moves from pieces in the lower orbits can simply be looked up. Either they move beyond the mtwist range and are outside the valid index range, or do might yield a valid but non canonical index. If you have precomputed this as ILLEGAL, then you ignore that unmove. Even non-leading pieces in the leading orbit can move how they like, and they don’t require transformations. So that leaves unmoves from the leading piece in the leading orbit, and you only have to compute the canonical configurations of those predecessors by finding the correct group element to map it to the canonical section.
Rein Halbersma
Posts: 770
Joined: Tue May 22, 2007 11:13 am

Re: Tablebase suggestion

Post by Rein Halbersma »

syzygy wrote: Mon Mar 02, 2026 11:00 pm There might still be advantages to having symmetry-perfect indexing for 5 white kings ;-)
OK, I’ll bite :D do you still have your code for a perfect 5-king indexing function on a chessboard? And how did you enumerate the various cases? It should be adaptable to draughts as well, and ideally be generalizable to N-king indexing
Rein Halbersma
Posts: 770
Joined: Tue May 22, 2007 11:13 am

Re: Tablebase suggestion

Post by Rein Halbersma »

Rein Halbersma wrote: Tue Mar 03, 2026 12:58 am
syzygy wrote: Tue Mar 03, 2026 12:30 am I see. I have to think about this as well. I was thinking unmoving between lexicographically minimal representatives was going to be a hassle. But if you can do that and thereby create an indexing function that assigns to each position a unique number (but just has a somewhat larger indexing range than optimal), then that would make everything else a lot easier.
In your triangle+mtwist indexing, you fixate the symmetry by the leading orbit configuration. So any moves from pieces in the lower orbits can simply be looked up. Either they move beyond the mtwist range and are outside the valid index range, or do might yield a valid but non canonical index. If you have precomputed this as ILLEGAL, then you ignore that unmove. Even non-leading pieces in the leading orbit can move how they like, and they don’t require transformations. So that leaves unmoves from the leading piece in the leading orbit, and you only have to compute the canonical configurations of those predecessors by finding the correct group element to map it to the canonical section.
So after having moved the leading (primary) king, you have to find the new leading orbit, bitwise-and its contents, pext() this into an 8/4/2 bit index (depending on chess/draughts orbit length), lookup the group element that makes the leading orbit canonical, apply that transformation to the entire board (using CPW bit wizardry or my sketched pext/lookup/pdep per orbit) and compute the index for this new config.
syzygy
Posts: 5938
Joined: Tue Feb 28, 2012 11:56 pm

Re: Tablebase suggestion

Post by syzygy »

Rein Halbersma wrote: Tue Mar 03, 2026 1:05 am
syzygy wrote: Mon Mar 02, 2026 11:00 pm There might still be advantages to having symmetry-perfect indexing for 5 white kings ;-)
OK, I’ll bite :D do you still have your code for a perfect 5-king indexing function on a chessboard? And how did you enumerate the various cases? It should be adaptable to draughts as well, and ideally be generalizable to N-king indexing
I should still have it, and I think I know on which old hard disk...
I didn't write a perfect 5-king, but the perfect 4-king should be even more complicated.
syzygy
Posts: 5938
Joined: Tue Feb 28, 2012 11:56 pm

Re: Tablebase suggestion

Post by syzygy »

syzygy wrote: Tue Mar 03, 2026 1:16 am
Rein Halbersma wrote: Tue Mar 03, 2026 1:05 am
syzygy wrote: Mon Mar 02, 2026 11:00 pm There might still be advantages to having symmetry-perfect indexing for 5 white kings ;-)
OK, I’ll bite :D do you still have your code for a perfect 5-king indexing function on a chessboard? And how did you enumerate the various cases? It should be adaptable to draughts as well, and ideally be generalizable to N-king indexing
I should still have it, and I think I know on which old hard disk...
I didn't write a perfect 5-king, but the perfect 4-king should be even more complicated.
Found it, but now I realize I overpromised :oops:
With KKKKvK, you can start with the sole K.

The most complicated case I tackled will have been KKvKKK:

Code: Select all

int encode_23(void)
{
  int idx;

  if (stype[0] >= 9) {
    if (stype[0] == 12)
      idx = (triangle[pos[0]] + triangle[pos[1]]*(triangle[pos[1]]-1)/2) * 8 + twistcnt[pos[1]];
    else if (stype[0] == 11)
      idx = 120 + triangle[pos[0]] * 16 + diag[pos[1]];
    else if (stype[0] == 10)
      idx = 120 + 96 + triangle[pos[0]];
    else
      idx = 120 + 96 + 6 + diag[pos[0]] + (pos[1]>>3)*((pos[1]>>3)-1)/2;
    idx = idx * (62*61*60/6) + pack(2);
  } else if (stype[0] >= 7) { /* B1, A2 or B1, H7 */
    if (stype[2] == 6)
      idx = lpack231() * (27*26/2) + lpack22();
    else if (stype[2] == 5)
      idx = 27*27*26/2 + lpack23();
    else if (stype[2] == 4)
      idx = 27*27*26/2 + 27*26*25/6 + diag[pos[2]] * (27*26/2) + lpack232();
    else if (stype[2] == 3)
      idx = 27*27*26/2 + 27*26*25/6 + 8*27*26/2 + diag[pos[2]] * (27*26/2) + lpack232();
    else if (stype[2] == 2)
      idx = 27*27*26/2 + 27*26*25/6 + 8*27*26 + (diag[pos[2]] + diag[pos[3]]*(diag[pos[3]]-1)/2) * 27 + lpack231();
    else if (stype[2] == 1)
      idx = 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2 + diag[pos[2]] * 27 + lpack231();
    else
      idx = 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2 + 8*27 + diag[pos[2]] + diag[pos[3]]*(diag[pos[3]]-1)/2 + diag[pos[4]]*(diag[pos[4]]-1)*(diag[pos[4]]-2)/6;
    idx += (120+96+6+6)*62*61*60/6 + (triangle[pos[0]] + 6 * (8 - stype[0])) * 19046;
  } else if (stype[0] >= 5) { /* A1, E5 or A1, D4 */
    if (stype[2] == 6)
      idx = lower[pos[4]] * (28*27/2) + lower[pos[2]] + lower[pos[3]]*(lower[pos[3]]-1)/2;
    else if (stype[2] == 5)
      idx = 28*28*27/2 + lower[pos[2]] + lower[pos[3]]*(lower[pos[3]]-1)/2 + lower[pos[4]]*(lower[pos[4]]-1)*(lower[pos[4]]-2)/6;
    else if (stype[2] == 4)
      idx = 28*28*27/2 + 28*27*26/6 + dpack221() * (28*27/2) + lower[pos[3]] + lower[pos[4]]*(lower[pos[4]]-1)/2;
    else if (stype[2] == 3)
      idx = 28*28*27/2 + 28*27*26/6 + 6*28*27/2 + dpack221() * (28*27/2) + lower[pos[3]] + lower[pos[4]]*(lower[pos[4]]-1)/2;
    else if (stype[2] == 2)
      idx = 28*28*27/2 + 28*27*26/6 + 6*28*27 + dpack22() * 28 + lower[pos[4]];
    else if (stype[2] == 1)
      idx = 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2 + dpack221() * 28 + lower[pos[3]];
    else
      idx = 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2 + 6*28 + dpack23();
    int p = triangle[pos[0]]-6, q = triangle[pos[1]]-6;
    idx += (120+96+6+6)*62*61*60/6 + 12*19046 + (p + q*(q-1)/2 + 6 * (6 - stype[0])) * 19004;
  } else if (stype[0] >= 1) { /* B1, G1 or A1, H1 */
    int p = flap[pos[2]];
    int q = flap[pos[3]];
    int r = flap[pos[4]];
    if (p > flap[pos[0]]) p--;
    if (q > flap[pos[0]]) q--;
    if (r > flap[pos[0]]) r--;
    if (stype[2])
      idx = p * (31*30/2) + q + r*(r-1)/2;
    else
      idx = 31*31*30/2 + p + q*(q-1)/2 + r*(r-1)*(r-2)/6;
    if (stype[0] > 1)
      idx += (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004 + (triangle[pos[0]] + 6 * (4-stype[0])) * 18910;
    else
      idx += (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004 + 18*18910 + (pos[0] & 0x07) * 18910;
  } else {
    if (stype[2] == 8)
      idx = (4 * fourcnt[pos[3]] + fourcnt[pos[4]]) * (12*11*10/6) + fourflip[pos[2]] + fourflip[pos[3]]*(fourflip[pos[3]]-1)/2 + fourflip[pos[4]]*(fourflip[pos[4]]-1)*(fourflip[pos[4]]-2)/6;
    else if (stype[2] == 7) {
      int q = fourflip[pos[4]];
      if (q > fourflip[pos[0]]) q--;
      if (pos[4] & 0x20) q += 7;
      idx = 3520 + fourcnt[pos[3]] * 924 + 14 * (fourflip[pos[2]] + fourflip[pos[3]]*(fourflip[pos[3]]-1)/2) + q - 12;
    } else if (stype[2] == 6) {
      int p = diag[pos[3]];
      int q = diag[pos[4]];
      if (p > diag[pos[1]]) p--;
      if (p > diag[pos[0]]) p--;
      if (q > diag[pos[1]]) q--;
      if (q > diag[pos[0]]) q--;
      idx = 3520 + 3696 + fourflip[pos[2]] * 91 + (p + q*(q-1)/2);
    } else if (stype[2] == 5) {
      if (offdiag[pos[4]]) {
	idx = lower[pos[4]];
	int p = lower[pos[2]], q = lower[flipdiag[pos[2] ^ 0x07] ^ 0x07];
	if (p < q) {
	  if (idx > q) idx--;
	  if (idx > p) idx--;
	} else {
	  if (idx > p) idx--;
	  if (idx > q) idx--;
	}
      } else {
	idx = diag[pos[4]];
	if (idx > diag[pos[1]]) idx--;
	if (idx > diag[pos[0]]) idx--;
	idx += 26;
      }
      idx += 3520 + 3696 + 1092 + fourflip[pos[2]] * 32;
    } else if (stype[2] == 4) {
      idx = 3520 + 3696 + 1092 + 384 + fourflip[pos[2]] * 29 + adjust3((pos[4] & 0x04) ? flap[pos[4] ^ 0x3f] : flap[pos[4]], flap[pos[0]], (pos[2] & 0x04) ? flap[pos[3]] : flap[pos[2]], flap[flipdiag[pos[2]]]);
    } else if (stype[2] == 3) {
      if (offdiag[pos[4] ^ 0x07]) {
	idx = adjust3(lower[pos[4] ^ 0x07], lower[pos[0] ^ 0x07], lower[pos[2] ^ 0x07], lower[flipdiag[pos[2]] ^ 0x07]);
      } else
	idx = 25 + diag[pos[4] ^ 0x07];
      idx += 3520 + 3696 + 1092 + 384 + 348 + fourflip[pos[2]] * 33;
    } else if (stype[2] == 2) {
      idx = 3520 + 3696 + 1092 + 1128 + fourflip[pos[2]];
    } else if (stype[2] == 1) {
      int p = fourflip[pos[2]], q = fourflip[pos[4]];
      if (p > fourflip[pos[0]]) {
	if (q > p) q--;
	if (q > fourflip[pos[0]]) q--;
	p--;
      } else {
	if (q > fourflip[pos[0]]) q--;
	if (q > p) q--;
      }
      p -= 12;
      q -= 12;
      idx = 3520 + 3696 + 1092 + 1128 + 12 + p * 6 + q;
    } else {
      int p = fourflip[pos[2]]-12, q = fourflip[pos[3]]-12, r = fourflip[pos[4]]-12;
      if (r < 4) {
	idx = 4 * (p + q*(q-1)/2 + r*(r-1)*(r-2)/6);
	if (pos[3] & 0x20) idx += 2;
	if (pos[4] & 0x20) idx += 1;
      } else if (q < 4) {
	if (fourflip[pos[4]] > fourflip[pos[0]]) r--;
	if (pos[3] & 0x20) r += 3;
	idx = 16 + (r - 4) * 6 + p + q*(q-1)/2;
      } else if (p < 4) {
	if (fourflip[pos[3]] > fourflip[pos[0]]) q--;
	if (fourflip[pos[4]] > fourflip[pos[0]]) r--;
	q -= 4;
	r -= 4;
	idx = 16 + 36 + p * 3 + q + r*(r-1)/2;
	if ((pos[3] ^ pos[4]) & 0x20) idx += 12;
      } else {
	idx = 16 + 36 + 24;
	if (pos[3] & 0x20) idx += 2;
	if (pos[4] & 0x20) idx += 1;
      }
      idx += 3520 + 3696 + 1092 + 1128 + 12 + 42;
    }
    idx += (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004 + 22*18910 + diag[pos[0]] * 9570;
  }

  return idx;
}

Code: Select all

void decode_23(int idx)
{
  int p, q, r;

  if (idx < (120+96+6+6)*62*61*60/6) {
    p = idx / (62*61*60/6);
    idx -= p * (62*61*60/6);
    if (p < 120) {
      r = p & 7;
      p /= 8;
      q = 1;
      while (p >= q) {
	p -= q;
	q++;
      }
      pos[0] = invtriangle[p];
      pos[1] = invtriangle[q];
      switch (r) {
      case 0:
	break;
      case 1:
	pos[1] ^= 0x07;
	break;
      case 2:
	pos[1] = flipdiag[pos[1]];
	break;
      case 3:
	pos[1] = flipdiag[pos[1]] ^ 0x07;
	break;
      case 4:
	pos[1] = flipdiag[pos[1]] ^ 0x38;
	break;
      case 5:
	pos[1] = flipdiag[pos[1]] ^ 0x3f;
	break;
      case 6:
	pos[1] ^= 0x38;
	break;
      case 7:
	pos[1] ^= 0x3f;
	break;
      }
    } else if (p < 120 + 96) {
      pos[0] = invtriangle[(p - 120)/16];
      pos[1] = invdiag[(p - 120) & 0x0f];
    } else if (p < 120 + 96 + 6) {
      pos[0] = invtriangle[p - 120 - 96];
      pos[1] = flipdiag[pos[0]] ^ 0x07;
    } else {
      p -= 120 + 96 + 6;
      q = 1;
      while (p >= q) {
	p -= q;
	q++;
      }
      pos[0] = invdiag[p];
      pos[1] = invdiag[q] ^ 0x07;
    }
    unpack(2, idx);
  } else if (idx < (120+96+6+6)*62*61*60/6 + 12*19046) {
    idx -= (120+96+6+6)*62*61*60/6;
    p = idx / 19046;
    idx -= p * 19046;
    if (p < 6)
      pos[0] = invtriangle[p];
    else
      pos[0] = invtriangle[p - 6] ^ 0x07;
    pos[1] = flipdiag[pos[0]];
    if (idx < 27*27*26/2) {
      p = idx / (27*26/2);
      idx -= p * (27*26/2);
      if (p >= lower[pos[0]]) p++;
      pos[4] = flipdiag[invlower[p]];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      if (p >= lower[pos[0]]) p++;
      if (idx >= lower[pos[0]]) idx++;
      pos[2] = invlower[idx];
      pos[3] = invlower[p];
    } else if (idx < 27*27*26/2 + 27*26*25/6) {
      idx -= 27*27*26/2;
      p = 2;
      while (idx >= p*(p-1)/2) {
	idx -= p*(p-1)/2;
	p++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      if (p >= lower[pos[0]]) p++;
      if (q >= lower[pos[0]]) q++;
      if (idx >= lower[pos[0]]) idx++;
      pos[2] = invlower[idx];
      pos[3] = invlower[q];
      pos[4] = invlower[p];
    } else if (idx < 27*27*26/2 + 27*26*25/6 + 8*27*26/2) {
      idx -= 27*27*26/2 + 27*26*25/6;
      p = idx / (27*26/2);
      idx -= p * (27*26/2);
      pos[2] = invdiag[p];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      if (idx >= lower[pos[0]]) idx++;
      if (p >= lower[pos[0]]) p++;
      pos[3] = invlower[idx];
      pos[4] = flipdiag[invlower[p]];
    } else if (idx < 27*27*26/2 + 27*26*25/6 + 8*27*26) {
      idx -= 27*27*26/2 + 27*26*25/6 + 8*27*26/2;
      p = idx / (27*26/2);
      idx -= p * (27*26/2);
      pos[2] = invdiag[p];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      if (idx >= lower[pos[0]]) idx++;
      if (p >= lower[pos[0]]) p++;
      pos[3] = invlower[idx];
      pos[4] = invlower[p];
    } else if (idx < 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2) {
      idx -= 27*27*26/2 + 27*26*25/6 + 8*27*26;
      p = idx / 27;
      idx -= p * 27;
      if (idx >= lower[pos[0]]) idx++;
      pos[4] = invlower[idx];
      idx = 1;
      while (p >= idx) {
	p -= idx;
	idx++;
      }
      pos[2] = invdiag[p];
      pos[3] = invdiag[idx];
    } else if (idx < 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2 + 8*27) {
      idx -= 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2;
      p = idx / 27;
      idx -= p * 27;
      pos[2] = invdiag[p];
      if (idx >= lower[pos[0]]) idx++;
      pos[3] = invlower[idx];
      pos[4] = flipdiag[invlower[idx]];
    } else {
      idx -= 27*27*26/2 + 27*26*25/6 + 8*27*26 + 8*7*27/2 + 8*27;
      p = 2;
      while (idx >= p*(p-1)/2) {
	idx -= p*(p-1)/2;
	p++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      pos[2] = invdiag[idx];
      pos[3] = invdiag[q];
      pos[4] = invdiag[p];
    }
  } else if (idx < (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004) {
    idx -= (120+96+6+6)*62*61*60/6 + 12*19046;
    p = idx / 19004;
    idx -= p * 19004;
    if (p < 6) {
      int q = 1;
      while (p >= q) {
	p -= q;
	q++;
      }
      pos[0] = invdiag[p];
      pos[1] = invdiag[q] ^ 0x3f;
    } else {
      p -= 6;
      int q = 1;
      while (p >= q) {
	p -= q;
	q++;
      }
      pos[0] = invdiag[p];
      pos[1] = invdiag[q];
    }
    if (idx < 28*28*27/2) {
      p = idx / (28*27/2);
      idx -= p * (28*27/2);
      pos[4] = flipdiag[invlower[p]];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      pos[2] = invlower[idx];
      pos[3] = invlower[p];
    } else if (idx < 28*28*27/2 + 28*27*26/6) {
      idx -= 28*28*27/2;
      p = 2;
      while (idx >= p*(p-1)/2) {
	idx -= p*(p-1)/2;
	p++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      pos[2] = invlower[idx];
      pos[3] = invlower[q];
      pos[4] = invlower[p];
    } else if (idx < 28*28*27/2 + 28*27*26/6 + 6*28*27/2) {
      idx -= 28*28*27/2 + 28*27*26/6;
      p = idx / (28*27/2);
      idx -= p * (28*27/2);
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      pos[2] = invdiag[p];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      pos[3] = invlower[idx];
      pos[4] = flipdiag[invlower[p]];
    } else if (idx < 28*28*27/2 + 28*27*26/6 + 6*28*27) {
      idx -= 28*28*27/2 + 28*27*26/6 + 6*28*27/2;
      p = idx / (28*27/2);
      idx -= p * (28*27/2);
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      pos[2] = invdiag[p];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      pos[3] = invlower[idx];
      pos[4] = invlower[p];
    } else if (idx < 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2) {
      idx -= 28*28*27/2 + 28*27*26/6 + 6*28*27;
      p = idx / 28;
      idx -= p * 28;
      pos[4] = invlower[idx];
      idx = 1;
      while (p >= idx) {
        p -= idx;
        idx++;
      }
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      if (idx >= diag[pos[0]]) idx++;
      if (idx >= diag[pos[1]]) idx++;
      pos[2] = invdiag[p];
      pos[3] = invdiag[idx];
    } else if (idx < 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2 + 6*28) {
      idx -= 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2;
      p = idx / 28;
      idx -= p * 28;
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      pos[2] = invdiag[p];
      pos[3] = invlower[idx];
      pos[4] = flipdiag[invlower[idx]];
    } else {
      idx -= 28*28*27/2 + 28*27*26/6 + 6*28*27 + 6*5*28/2 + 6*28;
      p = 2;
      while (idx >= p*(p-1)/2) {
	idx -= p*(p-1)/2;
	p++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      if (idx >= diag[pos[0]]) idx++;
      if (idx >= diag[pos[1]]) idx++;
      if (q >= diag[pos[0]]) q++;
      if (q >= diag[pos[1]]) q++;
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      pos[2] = invdiag[idx];
      pos[3] = invdiag[q];
      pos[4] = invdiag[p];
    }
  } else if (idx < (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004 + 22*18910) {
    idx -= (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004;
    p = idx / 18910;
    idx -= p * 18910;
    if (p < 6)
      pos[0] = invtriangle[p];
    else if (p < 12)
      pos[0] = flipdiag[invtriangle[p - 6]];
    else if (p < 18)
      pos[0] = invtriangle[p - 12];
    else
      pos[0] = invdiag[p - 18];
    pos[1] = pos[0] ^ 0x07;
    if (idx < 31*31*30/2) {
      int q = idx / (31*30/2);
      idx -= q * (31*30/2);
      if (q >= flap[pos[0]]) q++;
      pos[2] = invflap[q] ^ 0x07;
      q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      if (idx >= flap[pos[0]]) idx++;
      if (q >= flap[pos[0]]) q++;
      pos[3] = invflap[idx];
      pos[4] = invflap[q];
    } else {
      idx -= 31*31*30/2;
      int r = 2;
      while (idx >= r*(r-1)/2) {
	idx -= r*(r-1)/2;
	r++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      if (idx >= flap[pos[0]]) idx++;
      if (q >= flap[pos[0]]) q++;
      if (r >= flap[pos[0]]) r++;
      pos[2] = invflap[idx];
      pos[3] = invflap[q];
      pos[4] = invflap[r];
    }
    if (p >= 12 && p < 18) {
      int i;
      for (i = 1; i < 4; i++)
        if (pos[i] & 0x04) pos[i] ^= 0x38;
    }
  } else {
    idx -= (120+96+6+6)*62*61*60/6 + 12*19046 + 12*19004 + 22*18910;
    p = idx / 9570;
    idx -= p * 9570;
    pos[0] = invdiag[p];
    pos[1] = invdiag[p] ^ 0x3f;
    if (idx < 3520) {
      p = idx / (12*11*10/6);
      idx -= p * (12*11*10/6);
      int r = 2;
      while (idx >= r*(r-1)/2) {
	idx -= r*(r-1)/2;
	r++;
      }
      int q = 1;
      while (idx >= q) {
	idx -= q;
	q++;
      }
      pos[2] = invfourflip[idx];
      switch (p/4) {
      case 0:
	pos[3] = invfourflip[q];
	break;
      case 1:
	pos[3] = flipdiag[invfourflip[q]];
	break;
      case 2:
	pos[3] = flipdiag[invfourflip[q] ^ 0x07] ^ 0x07;
	break;
      case 3:
	pos[3] = invfourflip[q] ^ 0x3f;
	break;
      }
      switch (p & 3) {
      case 0:
	pos[4] = invfourflip[r];
	break;
      case 1:
	pos[4] = flipdiag[invfourflip[r]];
	break;
      case 2:
	pos[4] = flipdiag[invfourflip[r] ^ 0x07] ^ 0x07;
	break;
      case 3:
	pos[4] = invfourflip[r] ^ 0x3f;
	break;
      }
    } else if (idx < 3520 + 3696) {
      idx -= 3520;
      p = idx / 924;
      idx -= p * 924;
      q = idx / 14;
      idx -= q * 14;
      if (idx < 7) {
	idx += 12;
	if (idx >= fourflip[pos[0]]) idx++;
        pos[4] = invfourflip[idx];
      } else {
	idx += 12-7;
	if (idx >= fourflip[pos[0]]) idx++;
	pos[4] = invfourflip[idx] ^ 0x3f;
      }
      idx = 1;
      while (q >= idx) {
	q -= idx;
	idx++;
      }
      pos[2] = invfourflip[q];
      switch (p) {
      case 0:
	pos[3] = invfourflip[idx];
	break;
      case 1:
	pos[3] = flipdiag[invfourflip[idx]];
	break;
      case 2:
	pos[3] = flipdiag[invfourflip[idx] ^ 0x07] ^ 0x07;
	break;
      case 3:
	pos[3] = invfourflip[idx] ^ 0x3f;
	break;
      }
    } else if (idx < 3520 + 3696 + 1092) {
      idx -= 3520 + 3696;
      p = idx / 91;
      idx -= p * 91;
      pos[2] = invfourflip[p];
      p = 1;
      while (idx >= p) {
	idx -= p;
	p++;
      }
      if (idx >= diag[pos[0]]) idx++;
      if (idx >= diag[pos[1]]) idx++;
      if (p >= diag[pos[0]]) p++;
      if (p >= diag[pos[1]]) p++;
      pos[3] = invdiag[idx];
      pos[4] = invdiag[p];
    } else if (idx < 3520 + 3696 + 1092 + 384) {
      idx -= 3520 + 3696 + 1092;
      p = idx / 32;
      idx -= p * 32;
      pos[2] = invfourflip[p];
      pos[3] = flipdiag[pos[2]];
      if (idx < 26) {
	int p = lower[pos[2]], q = lower[flipdiag[pos[2] ^ 0x07] ^ 0x07];
	if (p < q) {
	  if (idx >= p) idx++;
	  if (idx >= q) idx++;
	} else {
	  if (idx >= q) idx++;
	  if (idx >= p) idx++;
	}
	pos[4] = invlower[idx];
      } else {
	idx -= 26;
	if (idx >= diag[pos[0]]) idx++;
	if (idx >= diag[pos[1]]) idx++;
	pos[4] = invdiag[idx];
      }
    } else if (idx < 3520 + 3696 + 1092 + 384 + 348) {
      idx -= 3520 + 3696 + 1092 + 384;
      p = idx / 29;
      idx -= p * 29;
      pos[2] = invfourflip[p];
      pos[3] = pos[2] ^ 0x3f;
      pos[4] = invflap[unadjust3(idx, flap[pos[0]], (pos[2] & 0x04) ? flap[pos[3]] : flap[pos[2]], flap[flipdiag[pos[2]]])];
    } else if (idx < 3520 + 3696 + 1092 + 1128) {
      idx -= 3520 + 3696 + 1092 + 384 + 348;
      p = idx / 33;
      idx -= p * 33;
      pos[2] = invfourflip[p];
      pos[3] = flipdiag[pos[2] ^ 0x07] ^ 0x07;
      if (idx < 25)
	pos[4] = invlower[unadjust3(idx, lower[pos[0] ^ 0x07], lower[pos[2] ^ 0x07], lower[flipdiag[pos[2]] ^ 0x07])] ^ 0x07;
      else
	pos[4] = invdiag[idx - 25] ^ 0x07;
    } else if (idx < 3520 + 3696 + 1092 + 1128 + 12) {
      idx -= 3520 + 3696 + 1092 + 1128;
      pos[2] = invfourflip[idx];
      pos[3] = flipdiag[invfourflip[idx]];
      pos[4] = invfourflip[idx] ^ 0x3f;
    } else if (idx < 3520 + 3696 + 1092 + 1128 + 12 + 42) {
      idx -= 3520 + 3696 + 1092 + 1128 + 12;
      p = idx / 6;
      idx -= p * 6;
      p += 12;
      idx += 12;
      if (p >= fourflip[pos[0]]) {
	p++;
	if (idx >= fourflip[pos[0]]) idx++;
	if (idx >= p) idx++;
      } else {
	if (idx >= p) idx++;
	if (idx >= fourflip[pos[0]]) idx++;
      }
      pos[2] = invfourflip[p];
      pos[3] = invfourflip[p] ^ 0x3f;
      pos[4] = invfourflip[idx];
    } else {
      idx -= 3520 + 3696 + 1092 + 1128 + 12 + 42;
      if (idx < 16) {
	p = idx / 4;
	int r = 2;
	while (p >= r*(r-1)/2) {
	  p -= r*(r-1)/2;
	  r++;
	}
	int q = 1;
	while (p >= q) {
	  p -= q;
	  q++;
	}
	pos[2] = invfourflip[p + 12];
	pos[3] = invfourflip[q + 12];
	pos[4] = invfourflip[r + 12];
	if (idx & 2) pos[3] ^= 0x3f;
	if (idx & 1) pos[4] ^= 0x3f;
      } else if (idx < 16 + 36) {
	idx -= 16;
	p = idx / 6;
	idx -= p * 6;
	int q = 1;
	while (idx >= q) {
	  idx -= q;
	  q++;
	}
	pos[2] = invfourflip[idx + 12];
	pos[3] = invfourflip[q + 12];
	if (p >= 3) {
	  p -= 3;
	  pos[3] ^= 0x3f;
	}
	p += 16;
	if (p >= fourflip[pos[0]]) p++;
	pos[4] = invfourflip[p];
      } else if (idx < 16 + 36 + 24) {
	idx -= 16 + 36;
	p = idx / 3;
	idx -= p * 3;
	int q = 1;
	while (idx >= q) {
	  idx -= q;
	  q++;
	}
	idx += 16;
	q += 16;
	if (idx >= fourflip[pos[0]]) idx++;
	if (q >= fourflip[pos[0]]) q++;
	pos[3] = invfourflip[idx];
	pos[4] = invfourflip[q];
	if (p >= 4) {
	  p -= 4;
	  pos[4] ^= 0x3f;
	}
	pos[2] = invfourflip[p + 12];
      } else {
	idx -= 16 + 36 + 24;
	int q = 16;
	for (p = 2; p < 5; p++, q++) {
	  if (q == fourflip[pos[0]]) q++;
	  pos[p] = invfourflip[q];
	}
	if (idx & 2) pos[3] ^= 0x3f;
	if (idx & 1) pos[4] ^= 0x3f;
      }
    }
  }
}

Code: Select all

void normalize_2(struct TBEntry *ptr)
{
  int i, j;
  int n = ptr->num;
  nptr = ptr;

  if (triangle[pos[0]] > triangle[pos[1]])
    Swap(pos[0], pos[1]);

  if (pos[0] & 0x04)
    for (i = 0; i < n; i++)
      pos[i] ^= 0x07;

  if (pos[0] & 0x20)
    for (i = 0; i < n; i++)
      pos[i] ^= 0x38;

  if (offdiag[pos[0]] > 0)
    for (i = 0; i < n; i++)
      pos[i] = flipdiag[pos[i]];

  if (triangle[pos[0]] < 6) {
    if (triangle[pos[1]] < 6) {
      if (triangle[pos[0]] != triangle[pos[1]]) {
	stype[0] = 12; /* no syms */
      } else {
	switch (twistcnt[pos[1]]) {
	case 4: /* A7 */
	  i = pos[0];
	  pos[0] = flipdiag[pos[1] ^ 0x38];
	  pos[1] = flipdiag[i ^ 0x38];
	  for (i = 2; i < n; i++)
	    pos[i] = flipdiag[pos[i] ^ 0x38];
	case 3: /* H2, no syms */
	  stype[0] = 10;
	  break;
	case 1: /* G1, leftright */
	  stype[0] = 4;
	  break;
	case 6: /* B8, updown -> leftright */
	  stype[0] = 3;
	  for (i = 0; i < n; i++)
	    pos[i] = flipdiag[pos[i]];
	  break;
	case 7: /* G8, 180 -> leftright */
	  stype[0] = 2;
	  for (i = 1; i < n; i++)
	    if (pos[i] & 0x04) pos[i] ^= 0x38;
	  break;
	case 2: /* A2, A1-H8 */
	  stype[0] = 8;
	  break;
	case 5: /* H7, A8-H1 -> A1-H8 */
	  stype[0] = 7;
	  for (i = 0; i < n; i++)
	    pos[i] ^= 0x07;
	  break;
	}
      }
    } else {
      stype[0] = 11; /* no syms */
    }
  } else {
    if (twistcnt[pos[1]] == 2)
      for (i = 1; i < n; i++)
	pos[i] = flipdiag[pos[i]];
    if (triangle[pos[0]] != triangle[pos[1]]) {
      if (twistcnt[pos[1]] == 1) { /* no syms */
	stype[0] = 9;
      } else if (twistcnt[pos[1]] == 3) { /* A1-H8 */
	stype[0] = 6;
      } else { /* A1-H8 */
	stype[0] = 5;
      }
    } else {
      if (twistcnt[pos[1]] == 3) { /* A1-H8, A8-H1 */
	stype[0] = 0; 
      } else { /* leftright */
	stype[0] = 1;
      }
    }
  }

  if (ptr->norm[2] == 2) {
    if (stype[0] >= 9) { /* no syms */
      if (pos[2] > pos[3]) Swap(pos[2], pos[3]);
    } else if (stype[0] >= 5) { /* A1H8 */
      if (offdiag[pos[2]] && !offdiag[pos[3]]) Swap(pos[2], pos[3]);
      if (offdiag[pos[2]]) {
	if (lower[pos[2]] == lower[pos[3]])
	  stype[2] = 1;
	else {
	  if (lower[pos[2]] > lower[pos[3]]) Swap(pos[2], pos[3]);
	  if (offdiag[pos[2]] == offdiag[pos[3]])
	    stype[2] = 3;
	  else
	    stype[2] = 4;
	}
      } else if (offdiag[pos[3]]) {
	stype[2] = 2;
      } else {
	stype[2] = 0;
	if (pos[2] > pos[3]) Swap(pos[2], pos[3]);
      }
    } else if (stype[0] >= 1) { /* leftright */
      if (flap[pos[2]] == flap[pos[3]])
	stype[2] = 0;
      else {
	if (flap[pos[2]] > flap[pos[3]]) Swap(pos[2], pos[3]);
	if ((pos[2] & 0x04) == (pos[3] & 0x04))
	  stype[2] = 1;
	else
	  stype[2] = 2;
      }
    } else { /* A1H8, A8H1 */
      if (fourflip[pos[2]] > fourflip[pos[3]]) Swap(pos[2], pos[3]);
      if (offdiag[pos[2]] > 0) {
	pos[2] = flipdiag[pos[2]];
	pos[3] = flipdiag[pos[3]];
      }
      if (offdiag[pos[2] ^ 0x07] > 0) {
	pos[2] = flipdiag[pos[2] ^ 0x07] ^ 0x07;
	pos[3] = flipdiag[pos[3] ^ 0x07] ^ 0x07;
      }
      if (fourflip[pos[2]] < 12) {
	if (fourflip[pos[2]] == fourflip[pos[3]])
	  stype[2] = 0;
	else if (fourflip[pos[3]] < 12)
	  stype[2] = 1;
	else
	  stype[2] = 2;
      } else {
	if (fourflip[pos[2]] == fourflip[pos[3]])
	  stype[2] = 3;
	else
	  stype[2] = 4;
      }
    }
  } else { /* norm[2] == 3 */
    if (stype[0] >= 9) { /* no syms */
      for (i = 2; i < 4; i++)
	for (j = i+1; j < 5; j++)
	  if (pos[i] > pos[j]) Swap(pos[i], pos[j]);
    } else if (stype[0] >= 5) { /* A1H8 */
      if (offdiag[pos[3]] && !offdiag[pos[4]])
	Swap(pos[3], pos[4]);
      if (offdiag[pos[2]] && !offdiag[pos[3]]) {
	Swap(pos[2], pos[3]);
	if (!offdiag[pos[4]])
	  Swap(pos[3], pos[4]);
      }
      if (!offdiag[pos[2]]) {
	if (!offdiag[pos[3]]) {
	  if (!offdiag[pos[4]]) {
	    for (i = 2; i < 4; i++)
	      for (j = i+1; j < 5; j++)
		if (pos[i] > pos[j]) Swap(pos[i], pos[j]);
	    stype[2] = 0;
	  } else {
	    if (pos[2] > pos[3])
	      Swap(pos[2], pos[3]);
	    stype[2] = 2;
	  }
	} else if (lower[pos[3]] == lower[pos[4]]) {
	  stype[2] = 1;
	} else {
	  if (lower[pos[3]] > lower[pos[4]])
	    Swap(pos[3], pos[4]);
	  if (offdiag[pos[3]] != offdiag[pos[4]])
	    stype[2] = 4;
	  else
	    stype[2] = 3;
	}
      } else if (offdiag[pos[2]] == offdiag[pos[3]] && offdiag[pos[2]] == offdiag[pos[4]]) {
	for (i = 2; i < 4; i++)
	  for (j = i+1; j < 5; j++)
	    if (lower[pos[i]] > lower[pos[j]]) Swap(pos[i], pos[j]);
	stype[2] = 5;
      } else {
	if (offdiag[pos[3]] == offdiag[pos[4]])
	  Swap(pos[2], pos[4])
	else if (offdiag[pos[2]] == offdiag[pos[4]])
	  Swap(pos[3], pos[4]);
	if (lower[pos[2]] > lower[pos[3]])
	  Swap(pos[2], pos[3]);
	stype[2] = 6;
      }
    } else if (stype[0] >= 1) {
      if ((pos[2] & 0x04) == (pos[3] & 0x04) && (pos[2] & 0x04) == (pos[4] & 0x04)) {
	for (i = 2; i < 4; i++)
	  for (j = i+1; j < 5; j++)
	    if (flap[pos[i]] > flap[pos[j]]) Swap(pos[i], pos[j]);
	stype[2] = 0;
      } else {
	if ((pos[2] & 0x04) == (pos[3] & 0x04))
	  Swap(pos[2], pos[4])
	else if ((pos[2] & 0x04) == (pos[4] & 0x04))
	  Swap(pos[2], pos[3]);
	if (flap[pos[3]] > flap[pos[4]])
	  Swap(pos[3], pos[4]);
	stype[2] = 1;
      }
    } else {
      for (i = 2; i < 4; i++)
	for (j = i+1; j < 5; j++)
	  if (fourflip[pos[i]] > fourflip[pos[j]]) Swap(pos[i], pos[j]);
      if (offdiag[pos[2]] > 0)
	for (i = 2; i < 5; i++)
	  pos[i] = flipdiag[pos[i]];
      if (offdiag[pos[2] ^ 0x07] > 0)
	for (i = 2; i < 5; i++)
	  pos[i] = flipdiag[pos[i] ^ 0x07] ^ 0x07;
      if (fourflip[pos[2]] < 12) {
	if (fourflip[pos[2]] != fourflip[pos[3]] && (fourflip[pos[3]] != fourflip[pos[4]] || fourflip[pos[3]] >= 12)) {
	  if (fourflip[pos[4]] < 12)
	    stype[2] = 8;
	  else if (fourflip[pos[3]] < 12)
	    stype[2] = 7;
	  else {
	    if (diag[pos[3]] > diag[pos[4]]) Swap(pos[3], pos[4]);
	    stype[2] = 6;
	  }
	} else {
	  if (fourflip[pos[2]] != fourflip[pos[3]]) {
	    Swap(pos[2], pos[4]);
            if (offdiag[pos[2]] > 0)
	      for (i = 2; i < 5; i++)
		pos[i] = flipdiag[pos[i]];
	    if (offdiag[pos[2] ^ 0x07] > 0)
	      for (i = 2; i < 5; i++)
		pos[i] = flipdiag[pos[i] ^ 0x07] ^ 0x07;
	  }
	  if (fourflip[pos[2]] == fourflip[pos[4]])
	    stype[2] = 2;
	  else if (fourcnt[pos[3]] == 1)
	    stype[2] = 5;
	  else if (fourcnt[pos[3]] == 3) {
	    stype[2] = 4;
	  } else
	    stype[2] = 3;
	}
      } else {
	if (fourflip[pos[3]] == fourflip[pos[4]]) {
	  Swap(pos[2], pos[4])
	  stype[2] = 1;
	} else if (fourflip[pos[2]] == fourflip[pos[3]])
	  stype[2] = 1;
	else
	  stype[2] = 0;
      }
    }
  }
}
To encode, I first called the applicable normalization function, so here normalize(), then encode_23().
syzygy
Posts: 5938
Joined: Tue Feb 28, 2012 11:56 pm

Re: Tablebase suggestion

Post by syzygy »

I think the most relevant function is normalize_2(), which seems to classify the leading KK configuration. Then for each class, encode_23() adds the other 3 pieces. So if encode_23() is replaced with the straightforward method of placing 3 Ks, normalize_2() does not need to do the classification (recorded in stype[]) but just calculate an index for the 2 leading Ks.

But normalize_2() is not yet close to normalize_5()...

For completeness:

Code: Select all

const int flap[] = {
  0, 1, 2, 3, 3, 2, 1, 0,
  4, 5, 6, 7, 7, 6, 5, 4,
  8, 9, 10, 11, 11, 10, 9, 8,
 12, 13, 14, 15, 15, 14, 13, 12,
 16, 17, 18, 19, 19, 18, 17, 16,
 20, 21, 22, 23, 23, 22, 21, 20,
 24, 25, 26, 27, 27, 26, 25, 24,
 28, 29, 30, 31, 31, 30, 29, 28
};

const int invflap[] = {
  0, 1, 2, 3, 8, 9, 10, 11,
  16, 17, 18, 19, 24, 25, 26, 27,
  32, 33, 34, 35, 40, 41, 42, 43,
  48, 49, 50, 51, 56, 57, 58, 59
};

const int twistcnt[] = {
  0, 0, 0, 0, 1, 1, 1, 1,
  2, 0, 0, 0, 1, 1, 1, 3,
  2, 2, 0, 0, 1, 1, 3, 3,
  2, 2, 2, 0, 1, 3, 3, 3,
  4, 4, 4, 2, 3, 5, 5, 5,
  4, 4, 2, 6, 7, 3, 5, 5,
  4, 2, 6, 6, 7, 7, 3, 5,
  2, 6, 6, 6, 7, 7, 7, 3
};

const int diag[] = {
   0,  0,  0,  0,  0,  0,  0,  8,
   0,  1,  0,  0,  0,  0,  9,  0,
   0,  0,  2,  0,  0, 10,  0,  0,
   0,  0,  0,  3, 11,  0,  0,  0,
   0,  0,  0, 12,  4,  0,  0,  0,
   0,  0, 13,  0,  0,  5,  0,  0,
   0, 14,  0,  0,  0,  0,  6,  0,
  15,  0,  0,  0,  0,  0,  0,  7
};

const int invdiag[] = {
  0, 9, 18, 27, 36, 45, 54, 63,
  7, 14, 21, 28, 35, 42, 49, 56
};

const int fourflip[] = {
  19,  0,  1,  2,  3,  4,  5, 12,
   0, 18,  6,  7,  8,  9, 13,  5,
   1,  6, 17, 10, 11, 14,  9,  4,
   2,  7, 10, 16, 15, 11,  8,  3,
   3,  8, 11, 15, 16, 10,  7,  2,
   4,  9, 14, 11, 10, 17,  6,  1,
   5, 13,  9,  8,  7,  6, 18,  0,
  12,  5,  4,  3,  2,  1,  0, 19
};

const int invfourflip[] = {
 1, 2, 3, 4, 5, 6, 10, 11, 12, 13,
 19, 20, 7, 14, 21, 28, 27, 18, 9
};

const int fourcnt[] = {
  0, 0, 0, 0, 0, 0, 0, 0,
  1, 0, 0, 0, 0, 0, 0, 2,
  1, 1, 0, 0, 0, 0, 2, 2, 
  1, 1, 1, 0, 0, 2, 2, 2,
  1, 1, 1, 0, 0, 2, 2, 2,
  1, 1, 0, 3, 3, 0, 2, 2,
  1, 0, 3, 3, 3, 3, 0, 2,
  0, 3, 3, 3, 3, 3, 3, 0
};
And then there are functions like:

Code: Select all

int lpack23(void)
{
  int p = lower[pos[2]];
  int q = lower[pos[3]];
  int r = lower[pos[4]];
  if (p >= lower[pos[0]]) p--;
  if (q >= lower[pos[0]]) q--;
  if (r >= lower[pos[0]]) r--;
  return p + q*(q-1)/2 + r*(r-1)*(r-2)/6;
}

int lpack231(void)
{
  int p = lower[pos[4]];
  if (p >= lower[pos[0]]) p--;
  return p;
}

int lpack232(void)
{
  int p = lower[pos[3]];
  int q = lower[pos[4]];
  if (p >= lower[pos[0]]) p--;
  if (q >= lower[pos[0]]) q--;
  return p + q*(q-1)/2;
}

int dpack23(void)
{
  int p = diag[pos[2]];
  int q = diag[pos[3]];
  int r = diag[pos[4]];
  if (p > diag[pos[1]]) p--;
  if (p > diag[pos[0]]) p--;
  if (q > diag[pos[1]]) q--;
  if (q > diag[pos[0]]) q--;
  if (r > diag[pos[1]]) r--;
  if (r > diag[pos[0]]) r--;
  return p + q*(q-1)/2 + r*(r-1)*(r-2)/6;
}

static int adjust3(int p, int q, int r, int s)
{
  if (r > s)
    Swap(r, s);
  if (q > r) {
    Swap(q, r);
    if (r > s)
      Swap(r, s);
  }
  if (p > s) p--;
  if (p > r) p--;
  if (p > q) p--;

  return p;
}

static int unadjust3(int p, int q, int r, int s)
{
  if (r > s)
    Swap(r, s);
  if (q > r) {
    Swap(q, r);
    if (r > s)
      Swap(r, s);
  }
  if (p >= q) p++;
  if (p >= r) p++;
  if (p >= s) p++;

  return p;
}
syzygy
Posts: 5938
Joined: Tue Feb 28, 2012 11:56 pm

Re: Tablebase suggestion

Post by syzygy »

syzygy wrote: Tue Mar 03, 2026 2:01 am I think the most relevant function is normalize_2(), which seems to classify the leading KK configuration.
It actually does more starting from the "if (ptr->norm[2] ==2)" part. So the KK-case isn't too difficult, the real complexity is in mixing in the other three Ks and taking into account all possible symmetries, but we don't want to do that for pieces outside the non-leading set.

So I think 5Ks should be somewhat doable, also given that there is a symmetry less in draughts. But it is a non-trivial exercise, and my old code probably does not really help too much.