SEE

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

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

Re: SEE

Post by Sven »

Chan Rasjid wrote:As for the one game win against Stockfish
Hmmmm ... how is

Code: Select all

{Draw by repetition} 1/2-1/2
a "win"? ;-)

Sven
Chan Rasjid
Posts: 588
Joined: Thu Mar 09, 2006 4:47 pm
Location: Singapore

Re: SEE

Post by Chan Rasjid »

Sven Schüle wrote:
Chan Rasjid wrote:As for the one game win against Stockfish
Hmmmm ... how is

Code: Select all

{Draw by repetition} 1/2-1/2
a "win"? ;-)

Sven
If you load the game, you can know it is a win; but my program has an ending bug and just don't know how to wrap up a win. Interesting to see a top program just making a blunder (very rare).

By the way, the SEE of Robbolito has about 220 lines; mine has abput 350. I will just let it be as my NPS seems not much affected.

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

Re: SEE

Post by Sven »

Chan Rasjid wrote:By the way, the SEE of Robbolito has about 220 lines; mine has abput 350.
You mean this kind of hand-written code (I just found a version 0.085f1a somewhere)? Certainly a good coding example ;-)

Code: Select all

#ifndef BUILD_SEE
#define BUILD_SEE
#include "RobboLito.h"
typedef enum
{ valu_pedone = 100, valu_cavallo = 325, valu_alfiere = 325,
  valu_torre = 500, valu_donna = 975, valu_re = 12345 } enum_valu;
static const int valu[16] =
  { 0, valu_pedone, valu_cavallo, 12345678,
    valu_alfiere, valu_alfiere, valu_torre, valu_donna,
    0, valu_pedone, valu_cavallo, 12345678,
    valu_alfiere, valu_alfiere, valu_torre, valu_donna
};

#include "SEE.c"
#include "bianco.h"
#else
#include "nero.h"
#endif

logico
mio_SEE (tipo_posizione *POSIZIONE, uint32 mossa)
{
  int di, ai, valu_pezzo, valu_cattura, d, dir;
  uint64 bit, cbf, cel, indice_pila[4], gcm = 0, T;
  int indice_turno[4], b, w;
  T = mio_xray & tuo_occupato;
  di = DI (mossa);
  ai = AI (mossa);
  while (T)
    {
      b = BSF (T);
      w = mio_xray_lista[b];
      bitLIBERO (b, T);
      if (di != w && indice_linea[ai][b] != indice_linea[b][tuo_quadretto_re])
    gcm |= quadretto_fisso[b];
    }
  gcm = ~gcm;
  valu_pezzo = valu[POSIZIONE->qu[di]];
  valu_cattura = valu[POSIZIONE->qu[ai]];
  if (valu_pezzo - valu_cattura > valu_pedone
      && tuo_attaco_pedone[ai] & bitbordo_tuo_pedone & gcm)
    return FALSO;
  bit =
    (bitbordo_mio_cavallo | (bitbordo_tuo_cavallo & gcm)) &
    attaco_cavallo[ai];
  d = valu_pezzo - valu_cattura;
  if (d > valu_cavallo && bitbordo_tuo_cavallo & bit)
    return FALSO;
  indice_turno[direzione_h1a8] =
    (POSIZIONE->occupato_sinistro45 >> linea_turno[direzione_h1a8][ai]) & 077;
  indice_turno[direzione_a1h8] =
    (POSIZIONE->occupato_retto45 >> linea_turno[direzione_a1h8][ai]) & 077;
  cel =
    bitbordo_mio_donna | bitbordo_mio_alfiere |
    ((bitbordo_tuo_donna | bitbordo_tuo_alfiere) & gcm);
  indice_pila[direzione_h1a8] = indice_pila[direzione_a1h8] = cel;
  bit |=
    (linea_obscura[direzione_h1a8][ai][indice_turno[direzione_h1a8]] |
     linea_obscura[direzione_a1h8][ai][indice_turno[direzione_a1h8]]) & cel;
  if (d > valu_alfiere && (bitbordo_tuo_alfiere & bit))
    return FALSO;
  indice_turno[direzione_orizzontale] =
    (POSIZIONE->
     occupato_nero_bianco >> linea_turno[direzione_orizzontale][ai]) & 077;
  indice_turno[direzione_verticale] =
    (POSIZIONE->
     occupato_sinistro90 >> linea_turno[direzione_verticale][ai]) & 077;
  cel =
    bitbordo_mio_donna | bitbordo_mio_torre |
    ((bitbordo_tuo_donna | bitbordo_tuo_torre) & gcm);
  indice_pila[direzione_orizzontale] = indice_pila[direzione_verticale] = cel;
  bit |=
    (linea_obscura[direzione_orizzontale][ai]
     [indice_turno[direzione_orizzontale]] |
     linea_obscura[direzione_verticale][ai][indice_turno
                        [direzione_verticale]]) & cel;
  bit |= (bitbordo_mio_re | bitbordo_tuo_re) & attaco_re[ai];
  bit |= bitbordo_tuo_pedone & tuo_attaco_pedone[ai] & gcm;
  bit |= bitbordo_mio_pedone & mio_attaco_pedone[ai];
  cbf = ~(quadretto_fisso[di] | quadretto_fisso[ai]);
  bit &= cbf;
  dir = indice_linea[di][ai];
  if (dir != direzione_malato)
    bit |= linea_obscura[dir][di][indice_turno[dir]] & indice_pila[dir] & cbf;
  valu_cattura -= valu_pezzo;
  do
    {
      cbf &= ~bit;
      cel = bitbordo_tuo_pedone & bit;
      if (cel)
    {
      bit ^= (~(cel - 1)) & cel;
      valu_pezzo = valu_pedone;
    }
      else
    {
      cel = bitbordo_tuo_cavallo & bit;
      if (cel)
        {
          bit ^= (~(cel - 1)) & cel;
          valu_pezzo = valu_cavallo;
        }
      else
        {
          cel = bitbordo_tuo_alfiere & bit;
          if (cel)
        {
          valu_pezzo = valu_alfiere;
          di = BSF (cel);
          dir = indice_linea[di][ai];
          cel =
            linea_obscura[dir][di][indice_turno[dir]] & cbf &
            indice_pila[direzione_a1h8];
          bit = cel | (quadretto_libero[di] & bit);
        }
          else
        {
          cel = bitbordo_tuo_torre & bit;
          if (cel)
            {
              valu_pezzo = valu_torre;
              di = BSF (cel);
              dir = indice_linea[di][ai];
              cel =
            linea_obscura[dir][di][indice_turno[dir]] & cbf &
            indice_pila[direzione_orizzontale];
              bit = cel | (quadretto_libero[di] & bit);
            }
          else
            {
              cel = bitbordo_tuo_donna & bit;
              if (cel)
            {
              valu_pezzo = valu_donna;
              di = BSF (cel);
              dir = indice_linea[di][ai];
              cel =
                linea_obscura[dir][di][indice_turno[dir]] & cbf &
                indice_pila[dir];
              bit = cel | (quadretto_libero[di] & bit);
            }
              else
            {
              if (!(bitbordo_tuo_re & bit))
                return VERO;
              valu_pezzo = 12345;
            }
            }
        }
        }
    }
      valu_cattura += valu_pezzo;
      if &#40;valu_cattura < -60&#41;
    return FALSO;
      cel = bitbordo_mio_pedone & bit;
      if &#40;cel&#41;
    &#123;
      bit ^= (~&#40;cel - 1&#41;) & cel;
      valu_pezzo = valu_pedone;
    &#125;
      else
    &#123;
      cel = bitbordo_mio_cavallo & bit;
      if &#40;cel&#41;
        &#123;
          bit ^= (~&#40;cel - 1&#41;) & cel;
          valu_pezzo = valu_cavallo;
        &#125;
      else
        &#123;
          cel = bitbordo_mio_alfiere & bit;
          if &#40;cel&#41;
        &#123;
          valu_pezzo = valu_alfiere;
          di = BSF &#40;cel&#41;;
          dir = indice_linea&#91;di&#93;&#91;ai&#93;;
          cel =
            linea_obscura&#91;dir&#93;&#91;di&#93;&#91;indice_turno&#91;dir&#93;&#93; & cbf &
            indice_pila&#91;direzione_a1h8&#93;;
          bit = cel | &#40;quadretto_libero&#91;di&#93; & bit&#41;;
        &#125;
          else
        &#123;
          cel = bitbordo_mio_torre & bit;
          if &#40;cel&#41;
            &#123;
              valu_pezzo = valu_torre;
              di = BSF &#40;cel&#41;;
              dir = indice_linea&#91;di&#93;&#91;ai&#93;;
              cel =
            linea_obscura&#91;dir&#93;&#91;di&#93;&#91;indice_turno&#91;dir&#93;&#93; & cbf &
            indice_pila&#91;direzione_orizzontale&#93;;
              bit = cel | &#40;quadretto_libero&#91;di&#93; & bit&#41;;
            &#125;
          else
            &#123;
              cel = bitbordo_mio_donna & bit;
              if &#40;cel&#41;
            &#123;
              valu_pezzo = valu_donna;
              di = BSF &#40;cel&#41;;
              dir = indice_linea&#91;di&#93;&#91;ai&#93;;
              cel =
                linea_obscura&#91;dir&#93;&#91;di&#93;&#91;indice_turno&#91;dir&#93;&#93; & cbf &
                indice_pila&#91;dir&#93;;
              bit = cel | &#40;quadretto_libero&#91;di&#93; & bit&#41;;
            &#125;
              else
            &#123;
              if (!&#40;bitbordo_mio_re & bit&#41;)
                return FALSO;
              if &#40;valu_cattura > 6174&#41;
                return VERO;
              valu_pezzo = 23456;
            &#125;
            &#125;
        &#125;
        &#125;
    &#125;
      valu_cattura -= valu_pezzo;
    &#125;
  while &#40;valu_cattura < -60&#41;;
  return VERO;
&#125;
Sven
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: SEE

Post by Sven »

Chan Rasjid wrote:
Sven Schüle wrote:
Chan Rasjid wrote:As for the one game win against Stockfish
Hmmmm ... how is

Code: Select all

&#123;Draw by repetition&#125; 1/2-1/2
a "win"? ;-)

Sven
If you load the game, you can know it is a win; but my program has an ending bug and just don't know how to wrap up a win. Interesting to see a top program just making a blunder (very rare).
If all games where I reached a won position would be counted as a win then I would probably be IM today.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: SEE

Post by bob »

Chan Rasjid wrote:Hello,

I don't get it why anyone need to run SEE through an en-passant move. Or did I miss out bigtime on some things.

SEE is only about isolating bad captures that may lose material and be pruned or sorted back - it does not matter if a move is clearly winning or equalizes. En-passant can never be a loser and be a candidate for prunning. It should always be make() early if there is one. So what am I missing here?

As for the one game win against Stockfish, this is the first time it happens a few days back after I added some to evaluation. But I am less surprised that it happens, even if just a rare one time event. I am confident my engine, search and evaluation, now is very thoroughly debug and almost bugfree.

Best Regards,
Rasjid.
I don't do EP in SEE myself, as that implies a pawn push, where SEE only considers captures...
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: SEE

Post by bob »

hgm wrote:
bob wrote:So at least a factor of 2x, which is 50-70, and I did not remove the extension selection tests or any other uses of Swap(), just q-search...
Time-to-depth speedup for a pruning is not a decisive measure, right? You also lose accuracy, which might cost you Elo. Some of the SEE-wise bad captures you prune actually win material (because a protector was overloaded or soft-pinned, or a capture delivered a discoverd threat), and your search will now miss that.

Besides, SEE is not really necessary for this pruning. With BLIND I make similar prunings too.
Yes, but the question would have to be "how much". The only real way to test is a cluster run, which I will fire up right now. Data this afternoon...
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: SEE

Post by Don »

hgm wrote:I would be very surprised if SEE would even gain you 10 Elo.

I would not worry too much about the 'foe-backed captures'. See is inherently unreliable (it does not take into account things like soft-pinning or overloading of the capturers). When you have foe-backed capturers, it would totally suck in most cases anyway. Because the assumption that the exchange will be limited to a single square is completely flawed in such cases. The blocked enemy slider will also attack the capturer, and usually the capturer will attack it back. If one of the two will be more valuable than the other, it usually pays to capture that in stead of on the target square. Imagine two Rooks attacking a Pawn from different direction, but one of those has a Queen of the opponent behind it. Which of the two should I use to capture the Pawn? (Answer: none. Capture the Queen in stead!) Now suppose the Pawn was attacked by two Queens, with an enemy Rook behind one of them. Should I capture with the other first, so that tha Queen keeps 'blocking' the Rook? (Bye bye Queen, despite it being a SEE-wise 'good capture'!).

In general, how would you know if the piece blocking the enemy slider is (sufficiently) protected? Not using it to capture first might make the opponent retaliate against that piece, rather than against the target square (which is likely a less valuable target, as you decided to use it first).
My see routine does it correct if you ignore pins and assume only captures on the target square. I basically have a bit board of all pieces that "Might" be attacking the target square (sliders "might" be) and I mask them out after each "pseudo" exchange. So I pick up pieces hiding behind other pieces and bishops attacking through pawns. Whether it makes sense to go to this trouble is not clear.

I disagree about the value of see in a chess program unless you mean the value of improving it a little. See is worth 100 ELO at least. I use it all over the place, not just in quies. Of course it's probably worth a bit less if you substitute see-like rules which is what I used to do. For example I had a few quick and dirty rules which were like a very shallow see, basically looking to see if the piece you want to capture is defended by a pawn or knight and when appropriate you could throw out the move in quies. Only down-captures matter anyway.

A simple rule which is probably "reasonable" is to only consider recaptures, even or up-captures and only down-captures of undefended material. But if you have to go to the trouble to figure out if a piece is defended you practically have see already.

The simplest thing you can do is check to see if the target piece is defended by a pawn or knight and act accordingly - this will allow you to prune a significant number of moves in the case of down-captures. But it's not as good as see().
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: SEE

Post by Don »

bob wrote:
Chan Rasjid wrote:Hello,

I don't get it why anyone need to run SEE through an en-passant move. Or did I miss out bigtime on some things.

SEE is only about isolating bad captures that may lose material and be pruned or sorted back - it does not matter if a move is clearly winning or equalizes. En-passant can never be a loser and be a candidate for prunning. It should always be make() early if there is one. So what am I missing here?

As for the one game win against Stockfish, this is the first time it happens a few days back after I added some to evaluation. But I am less surprised that it happens, even if just a rare one time event. I am confident my engine, search and evaluation, now is very thoroughly debug and almost bugfree.

Best Regards,
Rasjid.
I don't do EP in SEE myself, as that implies a pawn push, where SEE only considers captures...
I can call see() on any move. But see() first checks to see if it's en-passant and returns that it is safe. With promotions you just treat them as pawn moves which they are. If you promote and are captured, you don't lose a queen, you lose a pawn because you never really had the queen. If you capture to promote that's always a win of material and if you cannot push forward to promote you lose a pawn anyway. Castling is always safe if it's legal so I simply return that it's safe.
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: SEE

Post by bob »

bob wrote:
hgm wrote:
bob wrote:So at least a factor of 2x, which is 50-70, and I did not remove the extension selection tests or any other uses of Swap(), just q-search...
Time-to-depth speedup for a pruning is not a decisive measure, right? You also lose accuracy, which might cost you Elo. Some of the SEE-wise bad captures you prune actually win material (because a protector was overloaded or soft-pinned, or a capture delivered a discoverd threat), and your search will now miss that.

Besides, SEE is not really necessary for this pruning. With BLIND I make similar prunings too.
Yes, but the question would have to be "how much". The only real way to test is a cluster run, which I will fire up right now. Data this afternoon...
Here's the results. Had too many meetings and then class to check on test earlier:

23.6 is current normal crafty 23.6Q01 has the Swap() code removed from q-search only, so that all captures are searched in usual MVV/LVA order.

Crafty-23.6-1 2667 4 4 30000 62% 2572 25%
Crafty-23.6Q01-1 2615 3 3 30000 56% 2572 25%

Bottom line was 52 Elo roughly, or about 2x slower overall due to larger q-search tree...
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: SEE

Post by Don »

bob wrote:
bob wrote:
hgm wrote:
bob wrote:So at least a factor of 2x, which is 50-70, and I did not remove the extension selection tests or any other uses of Swap(), just q-search...
Time-to-depth speedup for a pruning is not a decisive measure, right? You also lose accuracy, which might cost you Elo. Some of the SEE-wise bad captures you prune actually win material (because a protector was overloaded or soft-pinned, or a capture delivered a discoverd threat), and your search will now miss that.

Besides, SEE is not really necessary for this pruning. With BLIND I make similar prunings too.
Yes, but the question would have to be "how much". The only real way to test is a cluster run, which I will fire up right now. Data this afternoon...
Here's the results. Had too many meetings and then class to check on test earlier:

23.6 is current normal crafty 23.6Q01 has the Swap() code removed from q-search only, so that all captures are searched in usual MVV/LVA order.

Crafty-23.6-1 2667 4 4 30000 62% 2572 25%
Crafty-23.6Q01-1 2615 3 3 30000 56% 2572 25%

Bottom line was 52 Elo roughly, or about 2x slower overall due to larger q-search tree...
The amount of ELO loss will depend a lot of the particular program, but I suspect it would be more for Komodo.

You said it was remove from q-search only. What does that mean? Where else does Crafty use SEE and can you remove it for a test or does the program depend on it for other things?

I may run a test where I simply return "true" regardless to see what happens.

Don
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.