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.