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.