Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Warning! Long demystified chess program (explosion of Eugene's posting)

Author: Gareth McCaughan

Date: 08:41:16 06/29/99

Go up one level in this thread


That's not very demystified. Try this. I've
  - renamed all the functions
  - reordered them a little
  - renamed most of the variables
  - added comments.

There are some amusing points. I particularly like the initialisation
of the constant variables formerly known as M,N,K and now called
sixtyfour, seven and three, and the board representation.

#include <stdio.h>
#include <stdlib.h>
static int v, w, to_move = -1, from, to, p, depth, o = 9999,
           sixtyfour, seven, three, node_count, YY, ZZ,
           pcolour[9999], in_check();

/* The type |pore| is a Piece OR Evaluator. All will become clear soon. */
typedef int (*pore) (); /* define type for function returning int */
static pore ptype[9999];

int try_move (int from, int to, pore D);

/* Find the first piece on the line starting at |from| and going
 * in direction (v,w).
 */
int scan_line (void) {
  int S = (v < 0 ? -1 : !!v) + ((w < 0 ? -1 : !!w) << three);
  if (!S)
    return to;
  for (v = from + S; v != to && !ptype[v]; v += S);
  return v;
}

/* Pieces. A piece is a function void -> int. It does two things:
 * (1) sets ZZ to a value related to the piece's name
 * (2) return 0 if and only if it's legal to move that kind of
 *     piece from square |from| by (v,w). [CHECK DETAILS]
 * When one of these is called to determine legality,
 * to_move is +1/-1 according to whose move it is, and J is the
 * square we're hoping to move to. Some aspects of legality (e.g.,
 * can't capture your own pieces) are handled elsewhere.
 */
int pawn (void) {
  ZZ = three;
  return
    /* if |v!=0| we're not moving straight forward. */
    v ? (v<0 ? -v : v) > 1 || w-to_move || !ptype[to]
    /* otherwise, we are. */
      : (w - to_move && (w - to_move * 2
                   || ptype[from + to_move * (seven + 1)]
                   || (to >> three) - three + (to_move - 1) / 2))
        || ptype[to];
}
int rook (void) {
  ZZ = 5;
  return v * w || scan_line () - to;
}
int king (void) {
  ZZ = -2;
  return (v*v*v - v || w*w*w - w)
         && (to-from - 2
             || (from & seven) - 4
             || (from >> three != (to_move - 1 ? seven : 0))
             || ptype[from + 1]
             || ptype[from + 2]
             || ptype[from + three] != rook
             || pcolour[from + three] * to_move < 0);
}
int queen (void) {
  ZZ = three + 1;
  return (v * w && (v < 0 ? -v : v) - (w < 0 ? -w : w)) || scan_line () - to;
}
int bishop (void) {
  ZZ = -11;
  return (v < 0 ? -v : v) - (w < 0 ? -w : w) || scan_line () - to;
}
int knight (void) {
  ZZ = 1;
  return (v * w < 0 ? -v * w : v * w) - 2;
}

/* |rand_real| exists only for |biased_rand|. The latter returns
 * a random variable that happens to have a mean of about 0.64.
 * (Maybe *exactly* 0.64. I'm too lazy to check.)
 */
double rand_real (void) {
  int max = 0x7fff;
  return (double) (rand () & max) / (double) max;
}
double biased_rand (void) {
  double i = 0, d;
  while ((i += d = rand_real ()) < 1.0);
  return d;
}

int illegal (int ur, int n, int x)
{
  from = ur;
  to = n;
  if (pcolour[from] != to_move || pcolour[to] == to_move)
    return to + 1; /* never zero, that's all */
  v = (to & seven) - (from & seven);
  w = (to >> three) - (from >> three);
  return
    ptype[from] () || (x && try_move (from, to, in_check));
}
/* Call a piece function and return something non-0. Used to set ZZ.
 */
int call_piece (int from) {
  v = w = 0;
  return ptype[from] () + three;
}

/* Return non-0 if -to_move is in check, else 0.
 */
int in_check (void)
{
  int j = -1, i;
  to_move = -to_move;
  for (i = 0; i < sixtyfour; ++i) {
    if (j < 0 && pcolour[i] == -to_move && call_piece (i) && ZZ == -2) {
      /* Found -to_move's king. Start scanning the board again. */
      j = i;
      i = -1;
    }
    else if (j >= 0 && !illegal (i, j, 0))
      return to_move = -to_move;
  }
  return !(to_move = -to_move);
}

int init_board (void)
{
  /* This really only needs to go up to 63. */
  for (v = 0; v < 9999; ++v)
    {
      /* v>>three is rank number of square. Are we on either back rank? */
      if (((v >> three) <= three ? v >> three
                                 : seven - (v >> three)) == 0)
        {
          /* S is 0,1,2,3 for R,N,B,K/Q. */
          int S = ((v & seven) <= three ? v & seven
                                        : seven - (v & seven));
          ptype[v] = !S ? rook :
                 (S == 1 ? knight :
                 (S == 2 ? bishop :
                 (v & seven > three ? queen : king)));
        }
      /* Are we on next-to-back rank? */
      else if (((v >> three) <= three ? v >> three
                                      : seven - (v >> three)) == 1)
        ptype[v] = pawn;
      else
        ptype[v] = 0;
      pcolour[v] = !!ptype[v] * (28 - v);
    }
  return 0;
}
int print_board (void)
{
  int G = to_move, i;
  to = 0;
  for (i = 0; i < sixtyfour; ++i)
    {
      i % 8 || printf ("\n%4o ", i);
      if ((to_move = pcolour[i] = (pcolour[i] < 0 ? -1 : !!pcolour[i])) &&
call_piece (i))
        printf ("%c ", ZZ + 93 + to_move * 16);
      else
        printf ("- ");
    }
  printf ("\n    ");
  do
    printf ("%2d", i++ & seven);
  while (i & seven);
  to_move = G;
  printf ("\n");
  return 0;
}
int make_move (int from, int to)
{
  /* Promotion: */
  if ((ptype[to] = ptype[from]) == pawn
       && ((to >> three) <= three ? to >> three
                                 : seven - (to >> three)) == 0)
    ptype[to] = queen;
  /* Castling (forward or backward!): */
  if (ptype[from] == king)
    if (to - from == 2)
      make_move (to + 1, to - 1);
    else if (from - to == 2)
      make_move (from - 1, from + 1);
  pcolour[to] = pcolour[from];
  ptype[from] = 0;
  pcolour[from] = 0;
  return 0;
}
int try_move (int from, int to, pore eval)
{
  int pcolour_to = pcolour[to], result;
  pore ptype_to = ptype[to], ptype_from = ptype[from];
  make_move (from, to);
  result = eval ();
  make_move (to, from);
  ptype[to] = ptype_to; ptype[from] = ptype_from; pcolour[to] = pcolour_to;
  return result;
}
int leaf_eval (void) {
  int i, j, BZ = 0;
  for (i = 0; i < sixtyfour; ++i) {
    pore Z = ptype[i];
    if (Z) {
      /* |r| is a centrality term. |S| is a simple piece-square
       * eval for piece |Z|.
       */
      int r = ((i >> three) <= three ? i >> three
                                     : seven - (i >> three))
              + ((i & seven) <= three ? i & seven
                                        : seven - (i & seven)),
          G = to_move,
          S = Z == rook ? 88 :
              (Z == pawn ? 11 + r + (pcolour[i] < 0 ? seven - (i >> three)
                                              : (i >> three)) :
              (Z == queen ? 124 - ((YY < 8
                                    && ((i & seven) != three
                                        || (i >> three) != (pcolour[i]>0 ? 0
                                                                   : seven)))
                                   ? sixtyfour : 0) :
              (Z == bishop ? 41 + r :
              (Z == king ? 9999 - r - r : 36 + r + r))));
      /* mobility/capture term */
      to_move = pcolour[i];
      for (j = 0; j < sixtyfour; ++j)
        if (!illegal (i, j, 0))
          S += (pcolour[j] ? 5 : 1);
      BZ += G == to_move ? S : -S;
      to_move = G;
    }
  }
  if (!(++node_count & sixtyfour - 1)) write (1, ".", 1);
  return BZ;
}
int search (void)
{
  int i, Q = 0, XP = 0, c4096 = sixtyfour * sixtyfour, E = -9999, t, S = o;
  if (!depth--)
    return ++depth + leaf_eval ();
  for (i = 0; i < c4096; ++i)
    if (!illegal (i >> three + three, i & sixtyfour - 1, 1)) {
      to_move = -to_move;
      o = -E;
      t = -try_move (i >> three + three, i & sixtyfour - 1, search);
      to_move = -to_move;
      if (t > E) {
        ++XP; /* there was a legal move */
        Q = i;
        E = t;
        if (E >= S) return ++depth, E;
      }
    }
  if (!XP)
    E = in_check ()? -9999 + 1 : 0;
  p = Q;
  return ++depth, E;
}
int play_game (void)
{
  int i, j, T = 0;
  for (;;)
    {
      print_board ();
      o = 9999;
      do
        {
          printf ("\n%d %d %d %s ", node_count, T, leaf_eval (), in_check ()?
"!" : ">");
          fflush(stdout);
        }
      while (scanf ("%o%o", &i, &j) != 2 || illegal (i, j, 1));
      make_move (i, j);
      print_board ();
      node_count = 0;
      ++YY;
      to_move = -to_move;
      T = search ();
      i = p >> (three << 1);
      j = p & (sixtyfour - 1);
      if (illegal (i, j, 1))
        {
          puts("Rats!");
          return 0;
        }
      make_move (i, j);
      to_move = -to_move;
      if (T > sixtyfour * sixtyfour)
        puts("\nHar har.");
    }
  return 0;
}
#include <time.h>
main (int ac, char **av)
{
  long time (), j = time (&j);
  double i = 0;
  srand ((int) j);
  /* The following 4 lines are almost certain to set sixtyfour=64. */
  for (sixtyfour = 0; sixtyfour <= 9999; ++sixtyfour) i += biased_rand ();
  sixtyfour = i / 100;
  if (sixtyfour & 3) ++sixtyfour;
  if (sixtyfour & 1) --sixtyfour;
  /* So the following 2 lines will set seven=8, then seven=7, then three=3. */
  for (seven = 1; seven * seven < sixtyfour; ++seven);
  three = --seven / 2;
  depth = ac > 1 ? atoi (av[1]) : 2;
  init_board ();
  play_game ();
  return 0;
}



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.