/* vi: set tabstop=4 shiftwidth=4: */ /* * $Id: attack.c,v 1.3 1996/12/28 22:11:02 schweikh Exp $ */ #include /* memset */ #include /* err */ #include "attack.h" #include "chess.h" #include "init.h" #include "shutup.h" /* * Position that's giving check, for movegen, -1 if no check. * Has file scope because it may be assigned in all three functions * of this file. Initialized to -1 at the beginning of attacks(). */ static int checked_by; /*__________________________________________________________________________ * */ __inline static void findw_attack (const unsigned char *const board, const int ptyp, const int start); __inline static void findb_attack (const unsigned char *const board, const int ptyp, const int start); /*__________________________________________________________________________ * */ __inline static void findw_attack (const unsigned char *const board, const int ptyp, const int start) /* * Find the squares attacked by white piece of type ptyp at startsquare. * attacked[] is incremented for each attack, shouldn't ever exceed 15! */ { unsigned char const *const ppos = nextpos[ptyp][start]; unsigned char const *const pdir = nextdir[ptyp][start]; int current = ppos[start]; /* 0 .. 63 */ do { ++attacked[current]; if (board[current] == FREE) current = ppos[current]; /* keep going in that direction */ else { /* not free */ /* If opponent attacks our king, and his piece is Q|R|B then also * mark the next square BEHIND the king as attacked This square * is ppos if ppos != pdir . What a hack! This saves us * considerable headaches, when a king must move out of check. * Will it cause other headaches because an actually unattacked * square is marked attacked??? */ if (board[current] == (BLACK | KING)) { /* Save info who is giving check. It's okay to overwrite when * more than one check is given since in such a case we do * not use checked_by (cause then we have to move the king * anyway). */ checked_by = start; if (IS_QRB (bit[ptyp]) && (ppos[current] != pdir[current])) ++attacked[ppos[current]]; } current = pdir[current]; /* start a new direction */ } } while (current != start); /* until I am back home again */ } __inline static void findb_attack (const unsigned char *const board, const int ptyp, const int start) /* * Find the squares attacked by black piece of type ptyp at startsquare. * attacked[] is incremented for each attack, shouldn't ever exceed 15! */ { unsigned char const *const ppos = nextpos[ptyp][start]; unsigned char const *const pdir = nextdir[ptyp][start]; int current = ppos[start]; /* 0 .. 63 */ do { ++attacked[current]; if (board[current] == FREE) current = ppos[current]; /* keep going in that direction */ else { /* not free */ /* If opponent attacks our king, and his piece is Q|R|B then also * mark the next square BEHIND the king as attacked This square * is ppos if ppos != pdir . What a hack! This saves us * considerable headaches, when a king must move out of check. * Will it cause other headaches because an actually unattacked * square is marked attacked??? */ if (board[current] == (WHITE | KING)) { /* Save info who is giving check. It's okay to overwrite when * more than one check is given since in such a case we do * not use checked_by (cause then we have to move the king * anyway). */ checked_by = start; if (IS_QRB (bit[ptyp]) && (ppos[current] != pdir[current])) ++attacked[ppos[current]]; } current = pdir[current]; /* start a new direction */ } } while (current != start); /* until I am back home again */ } int attacks (const State * const s) { /* called before movegen */ /* Find the squares attacked by the opponent. Needed later to decide * where a king may walk and if castling is allowed. Returns the position * that is giving check or -1. */ int i; /* index, range: 0 .. 15 */ int p; /* position, range: 0 .. 63 */ unsigned char const *const board = s->brd; unsigned char const *fig, *pos; Memset (attacked, 0, sizeof attacked); checked_by = -1; if (BLACK_TO_MOVE) { fig = s->fig[0]; pos = s->pos[0]; i = s->n[0]; do { /* for all white pieces */ --i; if (fig[i] & PAWN) { p = pos[i]; if (COL (p) != 0) { /* b - h */ ++attacked[p + 7]; if (board[p + 7] == (BLACK | KING)) checked_by = p; } if (COL (p) != 7) { /* a - g */ ++attacked[p + 9]; if (board[p + 9] == (BLACK | KING)) checked_by = p; } } else { /* not pawn */ findw_attack (board, code[fig[i]], pos[i]); } } while (i != 0); /* for all pieces */ } else { /* white to move */ fig = s->fig[1]; pos = s->pos[1]; i = s->n[1]; do { /* for all black pieces */ --i; if (fig[i] & PAWN) { p = pos[i]; if (COL (p) != 0) { /* b - h */ ++attacked[p - 9]; if (board[p - 9] == (WHITE | KING)) checked_by = p; } if (COL (p) != 7) { /* a - g */ ++attacked[p - 7]; if (board[p - 7] == (WHITE | KING)) checked_by = p; } } else { /* not pawn */ findb_attack (board, code[fig[i]], pos[i]); } } while (i != 0); /* for all pieces */ } return checked_by; }