Kiss your mate/lose score troubles good-bye

Discussion of chess software programming and technical issues.

Moderators: hgm, Dann Corbit, Harvey Williamson

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&#40;const SV sv&#41; &#123;return IsSvNotBroken&#40;sv&#41; && &#40;sv <= SvLongLose&#41;;&#125;

inline bool IsSvMatingOrLosing&#40;const SV sv&#41; &#123;return IsSvMating&#40;sv&#41; || IsSvLosing&#40;sv&#41;;&#125;

inline bool IsSvMateIn1&#40;const SV sv&#41; &#123;return sv == SvMateIn1;&#125;
inline bool IsSvLoseIn0&#40;const SV sv&#41; &#123;return sv == SvLoseIn0;&#125;

inline bool IsSvInRange&#40;const SV sv&#41; &#123;return &#40;sv > SvLongLose&#41; && &#40;sv < SvLongMate&#41;;&#125;

inline bool IsSvPositive&#40;const SV sv&#41; &#123;return sv > 0;&#125;
inline bool IsSvNegative&#40;const SV sv&#41; &#123;return sv < 0;&#125;

inline ui FullMoveMatingDistance&#40;const SV sv&#41; &#123;return &#40;ui&#41; &#40;SvMateIn1 - sv + 1&#41;;&#125;
inline ui FullMoveLosingDistance&#40;const SV sv&#41; &#123;return &#40;ui&#41; &#40;sv - SvLoseIn0&#41;;&#125;

extern SV CalcSvDnShift&#40;const SV sv&#41;;
extern SV CalcSvUpShift&#40;const SV sv&#41;;

inline void UpShiftSv&#40;SV& sv&#41; &#123;sv = CalcSvUpShift&#40;sv&#41;;&#125;
inline void DnShiftSv&#40;SV& sv&#41; &#123;sv = CalcSvDnShift&#40;sv&#41;;&#125;
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&#40;const SV sv&#41;
&#123;
  SV result;

  if &#40;IsSvBroken&#40;sv&#41;)
    result = SvBroken;
  else
  &#123;
    if &#40;IsSvInRange&#40;sv&#41;)
      result = -sv;
    else
    &#123;
      if &#40;IsSvInfinite&#40;sv&#41;)
      &#123;
        if &#40;IsSvPosInf&#40;sv&#41;)
          result = SvNegInf;
        else
          result = SvPosInf;
      &#125;
      else
      &#123;
        if &#40;IsSvMating&#40;sv&#41;)
          result = SynthLoseInN&#40;FullMoveMatingDistance&#40;sv&#41; - 1&#41;;
        else
          result = SynthMateInN&#40;FullMoveLosingDistance&#40;sv&#41;);
      &#125;;
    &#125;;
  &#125;;
  return result;
&#125;

SV CalcSvUpShift&#40;const SV sv&#41;
&#123;
  SV result;

  if &#40;IsSvBroken&#40;sv&#41;)
    result = SvBroken;
  else
  &#123;
    if &#40;IsSvInRange&#40;sv&#41;)
      result = -sv;
    else
    &#123;
      if &#40;IsSvInfinite&#40;sv&#41;)
      &#123;
        if &#40;IsSvPosInf&#40;sv&#41;)
          result = SvNegInf;
        else
          result = SvPosInf;
      &#125;
      else
      &#123;
        if &#40;IsSvMating&#40;sv&#41;)
          result = SynthLoseInN&#40;FullMoveMatingDistance&#40;sv&#41;);
        else
          result = SynthMateInN&#40;FullMoveLosingDistance&#40;sv&#41; + 1&#41;;
      &#125;;
    &#125;;
  &#125;;
  return result;
&#125;