/* vi: set tabstop=4 shiftwidth=4: */ /* * $Id: init.c,v 1.3 1996/12/28 22:11:12 schweikh Exp $ */ /* * init.c - C source for GNU CHESS * * Copyright (c) 1988,1989,1990 John Stanback * Copyright (c) 1992 Free Software Foundation * * This file is part of GNU CHESS. * * GNU Chess is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GNU Chess is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Chess; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Heavily modified in December 1994 by Jens Schweikhardt * for use with a problem solver. */ #include /* memset */ #include "chess.h" #include "init.h" #include "shutup.h" /* * nextpos[piece][from-square], nextdir[piece][from-square] gives vector * of positions reachable from from-square in ppos with piece. * If the path is blocked u = pdir[sq] will generate the continuation * of the sequence in other directions. Values range from 0 to 63. */ unsigned char nextpos[8][64][64]; unsigned char nextdir[8][64][64]; /* * distances measured in squares, dist[a1,h8] = 7 etc... * Values range from 0 to 7. */ unsigned char dist[64][64]; /* * off[from][to] * Offset for a single step for a queen to move from a to b. * 0 for unreachable. Values range from -9 to 9. */ signed char off[64][64]; /* Note: must be signed! */ /* * trap[king pos][piece pos] * wheter a piece may be trapped, direction from king to piece, 0 = untrapped * Values range from -9 to 9. */ signed char trap[64][64]; /* Note: must be signed! */ /* * Wheter a square is a border square or an edge square. * Values range from 0 to 5. */ unsigned char border[64] = { 1, 2, 2, 2, 2, 2, 2, 1, 3, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0, 0, 0, 0, 4, 1, 5, 5, 5, 5, 5, 5, 1 }; /* * To test if a direction (-9,-8,-7,-1,1,7,8,9) is diagonal: diag[dir & 15] */ unsigned char diag[16] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0}; /* * code[PIECE] = piece (for KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN) */ unsigned char code[MAX_P + 1]; /* * if a piece can move from a to b */ unsigned char ok[7][64][64]; /* * # of attacks opponent has on a square (0-15) */ unsigned char attacked[64]; int firstmv; /* who was to move first (constant) */ unsigned bit[16] = { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, BIT8, BIT9, BIT10, BIT11, BIT12, BIT13, BIT14, BIT15 }; stringlist M; /* Message catalog */ char pchar[7]; /* Piece characters */ static void Initialize_moves (void); static void Initialize_ok (void); static const short direc[8][8] = { {0, 0, 0, 0, 0, 0, 0, 0}, /* 0 nopiece */ {10, 9, 11, 0, 0, 0, 0, 0}, /* 1 pawn */ {8, -8, 12, -12, 19, -19, 21, -21}, /* 2 knight */ {9, 11, -9, -11, 0, 0, 0, 0}, /* 3 bishop */ {1, 10, -1, -10, 0, 0, 0, 0}, /* 4 rook */ {1, 10, -1, -10, 9, 11, -9, -11}, /* 5 queen */ {1, 10, -1, -10, 9, 11, -9, -11}, /* 6 king */ {-10, -9, -11, 0, 0, 0, 0, 0} /* 7 bpawn */ }; static const short max_steps[8] = {0, 2, 1, 7, 7, 7, 1, 2}; static const short nunmap[120] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, 8, 9, 10, 11, 12, 13, 14, 15, -1, -1, 16, 17, 18, 19, 20, 21, 22, 23, -1, -1, 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, -1, -1, 40, 41, 42, 43, 44, 45, 46, 47, -1, -1, 48, 49, 50, 51, 52, 53, 54, 55, -1, -1, 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; void initialize (void) { short a, b, dc, dr; for (a = 0; a < 64; a++) for (b = 0; b < 64; b++) { dc = COL (b) - COL (a); dr = ROW (b) - ROW (a); /* fill the off[][] array */ if (dc == 0) { /* up or down or a == b */ off[a][b] = dr < 0 ? -8 : 8 * (dr > 0); } else if (dr == 0) { /* left or right */ off[a][b] = dc < 0 ? -1 : (dc > 0); } else if (ABS (dc) == ABS (dr)) { /* diag */ if (dc < 0) { /* left diag */ off[a][b] = dr < 0 ? -9 : 7 * (dr > 0); } else { /* right diag */ off[a][b] = dr < 0 ? -7 : 9 * (dr > 0); } } else { off[a][b] = 0; /* unreachable */ } /* Fill the trap array, which is mostly the same as the off array * but with some combinations set to zero that can not be traps: * - piece is on edge square - piece and king on different * borders - piece on border && king not on border */ if (border[b] == 1 || (border[b] && !border[a]) || (border[a] > 1 && border[b] > 1 && border[a] != border[b])) { trap[a][b] = 0; } else { trap[a][b] = off[a][b]; } dc = ABS (dc); dr = ABS (dr); dist[a][b] = (dc > dr ? dc : dr); } /* other initialisation stuff */ Initialize_ok (); Initialize_moves (); Memset (code, 0, sizeof code); code[PAWN] = pawn; code[KNIGHT] = knight; code[BISHOP] = bishop; code[ROOK] = rook; code[QUEEN] = queen; code[KING] = king; } static void Initialize_ok (void) { /* initialize the ok[type][from][to] array */ short type, from, d, delta, s; Memset (ok, 0, sizeof ok); for (type = 2; type < 7; type++) { /* only n,b,r,q,k */ for (from = 21; from < 99; from++) { if (nunmap[from] == -1) continue; /* skip the -1's at the l & r side */ for (d = 0; d < 8; ++d) { if ((delta = direc[type][d]) != 0) { for (s = 1; s <= max_steps[type]; ++s) { if (nunmap[from + s * delta] >= 0) { ok[type][nunmap[from]][nunmap[from + s * delta]] |= 1; } else { break; } } } } } } } static void Initialize_moves (void) /* * This procedure pre-calculates all moves for every piece from every square. * This data is stored in nextpos/nextdir and used later in the move * generation routines. */ { short ptyp, po, p0, d, di, s, delta; unsigned char *ppos, *pdir; short dest[8][8]; short steps[8]; short sorted[8]; for (ptyp = 0; ptyp < 8; ptyp++) for (po = 0; po < 64; po++) for (p0 = 0; p0 < 64; p0++) { nextpos[ptyp][po][p0] = (unsigned char) po; nextdir[ptyp][po][p0] = (unsigned char) po; } for (ptyp = 1; ptyp < 8; ptyp++) for (po = 21; po < 99; po++) if (nunmap[po] >= 0) { /* skip the -1's at the l & r side */ ppos = nextpos[ptyp][nunmap[po]]; pdir = nextdir[ptyp][nunmap[po]]; /* dest is a function of direction and steps */ for (d = 0; d < 8; d++) { /* for all 8 directions */ dest[d][0] = nunmap[po]; delta = direc[ptyp][d]; if (delta != 0) { /* 0 was used to pad array direc */ p0 = po; for (s = 0; s < max_steps[ptyp]; s++) { p0 = p0 + delta; /* break if (off board) or (pawns only move two * steps from home square) */ if ( (nunmap[p0] < 0) || /* off board or */ (( (ptyp == pawn) || (ptyp == bpawn) /* a pawn */ ) && ( (s > 0) && ((d > 0) || ( /* not on either home row */ !((po >= 30 && po < 39) || (po > 80 && po < 89)) ) ) ) ) ) /* (Stboard[nunmap[po]] != pawn))))) */ break; else dest[d][s] = nunmap[p0]; } } else /* delta == 0 */ s = 0; /* sort dest in number of steps order currently no sort * is done due to compability with the move generation * order in old gnu chess */ steps[d] = s; for (di = d; s > 0 && di > 0; di--) if (steps[sorted[di - 1]] == 0) /* should be: < s */ sorted[di] = sorted[di - 1]; else break; sorted[di] = d; } /* update nextpos/nextdir, pawns have two threads (capture * and no capture) */ p0 = nunmap[po]; if (ptyp == pawn || ptyp == bpawn) { for (s = 0; s < steps[0]; s++) { ppos[p0] = (unsigned char) dest[0][s]; p0 = dest[0][s]; } p0 = nunmap[po]; for (d = 1; d < 3; d++) { pdir[p0] = (unsigned char) dest[d][0]; p0 = dest[d][0]; } } else /* no pawn */ { pdir[p0] = (unsigned char) dest[sorted[0]][0]; for (d = 0; d < 8; d++) for (s = 0; s < steps[sorted[d]]; s++) { ppos[p0] = (unsigned char) dest[sorted[d]][s]; p0 = dest[sorted[d]][s]; if (d < 7) pdir[p0] = (unsigned char) dest[sorted[d + 1]][0]; /* else is already initialized */ } } } }