Kiss your mate/lose score troubles good-bye

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Kiss your mate/lose score troubles good-bye

Post by sje »

Here are three code excerpts from Symbolic; well-tested and which may be useful to others.

First and simplest, fail-hard is your friend. When using a window, always update the window (eventually returning alpha as the score) such that alpha always obeys the original window bounds.:

Code: Select all

  void Update(const SV sv)
  {
    if (sv > alfa)
    {
      if (sv >= beta)
        alfa = beta;
      else
        alfa = sv;
    };
  }
Second, steal as needed from this header file excerpt:

Code: Select all

// Regular scores (micropawn units)

typedef si32  SV;     // Score value in micropawns; 32 bit signed integer

// ScoringScale: micropawns per pawn

#define ScoringScale 1000000

// In-range score span: 2^30 = 1,037,741,824

#define ScoringRangeLen BX(30)

// Longest negative mate/lose full move distance: 2^10 = 1,024

#define MateMarginLen   BX(10)

// Longest mate/lose full move distance: 2^13 = 8,192

#define MateDistanceLen BX(13)

// SV usits

#define SvMicropawn ((SV) 1)
#define SvMillipawn (SvMicropawn * 1000)
#define SvCentipawn (SvMillipawn * 10)

// Special values

#define SvBroken     ((SV) (0 - ScoringRangeLen))
#define SvPosInf     ((SV) (ScoringRangeLen - 1))
#define SvNegInf     ((SV) (1 - ScoringRangeLen))

// Draw value

#define SvEven       ((SV) 0)

// Some lose values

#define SvLoseIn0    ((SV) (SvNegInf + MateMarginLen))
#define SvLoseIn1    ((SV) (SvLoseIn0 + 1))
#define SvLoseIn2    ((SV) (SvLoseIn0 + 2))
#define SvLoseIn3    ((SV) (SvLoseIn0 + 3))

// Checkmated synonym

#define SvCheckmated SvLoseIn0

// Some mate values

#define SvMateIn1    ((SV) (SvPosInf - MateMarginLen - 1))
#define SvMateIn2    ((SV) (SvMateIn1 - 1))
#define SvMateIn3    ((SV) (SvMateIn1 - 2))
#define SvMateIn4    ((SV) (SvMateIn1 - 3))

// Longest mate/lose values

#define SvLongMate ((SV) (SvMateIn1 - MateDistanceLen + 1))
#define SvLongLose ((SV) (SvLoseIn0 + MateDistanceLen))

// Piece values

#define SvPawn   (SvMillipawn * 1000)
#define SvKnight (SvMillipawn * 3250)
#define SvBishop (SvMillipawn * 3333)
#define SvRook   (SvMillipawn * 5000)
#define SvQueen  (SvMillipawn * 9000)
#define SvKing   (SvMillipawn * 0)

// Conversion from millipawns to micropawns

#define MP(mp) ((SV) ((mp) * SvMillipawn))

inline SV SynthMateInN(const ui n) {return SvMateIn1 - ((SV) n) + 1;}
inline SV SynthLoseInN(const ui n) {return SvLoseIn0 + ((SV) n);}

inline bool IsSvBroken(const SV sv) {return sv == SvBroken;}
inline bool IsSvPosInf(const SV sv) {return sv == SvPosInf;}
inline bool IsSvNegInf(const SV sv) {return sv == SvNegInf;}
inline bool IsSvEven(const SV sv)   {return sv == SvEven;}

inline bool IsSvNotBroken(const SV sv) {return sv != SvBroken;}
inline bool IsSvInfinite(const SV sv)  {return IsSvPosInf(sv) || IsSvNegInf(sv);}
inline bool IsSvSpecial(const SV sv)   {return IsSvBroken(sv) || IsSvInfinite(sv);}

inline bool IsSvMating(const SV sv) {return IsSvNotBroken(sv) && (sv >= SvLongMate);}
inline bool IsSvLosing(const SV sv) {return IsSvNotBroken(sv) && (sv <= SvLongLose);}

inline bool IsSvMatingOrLosing(const SV sv) {return IsSvMating(sv) || IsSvLosing(sv);}

inline bool IsSvMateIn1(const SV sv) {return sv == SvMateIn1;}
inline bool IsSvLoseIn0(const SV sv) {return sv == SvLoseIn0;}

inline bool IsSvInRange(const SV sv) {return (sv > SvLongLose) && (sv < SvLongMate);}

inline bool IsSvPositive(const SV sv) {return sv > 0;}
inline bool IsSvNegative(const SV sv) {return sv < 0;}

inline ui FullMoveMatingDistance(const SV sv) {return (ui) (SvMateIn1 - sv + 1);}
inline ui FullMoveLosingDistance(const SV sv) {return (ui) (sv - SvLoseIn0);}

extern SV CalcSvDnShift(const SV sv);
extern SV CalcSvUpShift(const SV sv);

inline void UpShiftSv(SV& sv) {sv = CalcSvUpShift(sv);}
inline void DnShiftSv(SV& sv) {sv = CalcSvDnShift(sv);}
Third: when moving a score value down to the next ply (as when transmitting a window's alpha and beta), use the CalcSvDnShift() routine; when moving a score value up one ply (as when receiving an evaluation), use the CalcSvUpShift() routine:

Code: Select all

SV CalcSvDnShift(const SV sv)
{
  SV result;

  if (IsSvBroken(sv))
    result = SvBroken;
  else
  {
    if (IsSvInRange(sv))
      result = -sv;
    else
    {
      if (IsSvInfinite(sv))
      {
        if (IsSvPosInf(sv))
          result = SvNegInf;
        else
          result = SvPosInf;
      }
      else
      {
        if (IsSvMating(sv))
          result = SynthLoseInN(FullMoveMatingDistance(sv) - 1);
        else
          result = SynthMateInN(FullMoveLosingDistance(sv));
      };
    };
  };
  return result;
}

SV CalcSvUpShift(const SV sv)
{
  SV result;

  if (IsSvBroken(sv))
    result = SvBroken;
  else
  {
    if (IsSvInRange(sv))
      result = -sv;
    else
    {
      if (IsSvInfinite(sv))
      {
        if (IsSvPosInf(sv))
          result = SvNegInf;
        else
          result = SvPosInf;
      }
      else
      {
        if (IsSvMating(sv))
          result = SynthLoseInN(FullMoveMatingDistance(sv));
        else
          result = SynthMateInN(FullMoveLosingDistance(sv) + 1);
      };
    };
  };
  return result;
}