/* this file contains all the code that keeps the board position uptodate, calling eval and hash procedures to ensure that the hashes and evaluation are also kept uptodate */ #include "includes.h" #include "knightcap.h" extern struct state *state; struct hashvalue_entry hash_values; static inline void init_hash_values(void) { static int initialised; int i, j; if (initialised) return; initialised = 1; memset(&hash_values, 0, sizeof(hash_values)); for (i=0;i<(2*KING+1);i++) if (i != KING) for (j=0;jp > 0) b->w_material += mat_value(p->p); else b->b_material += mat_value(-p->p); } static void deval_piece(Position *b, PieceStruct *p) { if (p->p > 0) b->w_material -= mat_value(p->p); else b->b_material -= mat_value(-p->p); } static inline void remove_piece(Position *b, PieceStruct *piece) { int pi = (piece - b->pieces); uint32 mask = ~(1<pos, piece->p); set_pboard(b, piece->pos, NULL); b->board[piece->pos] = 0; piece->p = 0; b->pawns7th &= mask; b->wpassed_pawn_mask &= mask; b->bpassed_pawn_mask &= mask; b->piece_mask &= mask; b->material_mask &= mask; } static inline void move_piece(Position *b, PieceStruct *piece, Square to) { int pi = (piece - b->pieces); if (b->pawns7th & (1<pawns7th &= ~(1<pos, piece->p); set_pboard(b, piece->pos, NULL); set_pboard(b, to, piece); b->board[piece->pos] = 0; b->board[to] = piece->p; piece->pos = to; add_hash(b, piece->pos, piece->p); if ((piece->p == PAWN && YPOS(to) == 6) || (piece->p == -PAWN && YPOS(to) == 1)) { b->pawns7th |= (1<pieces); b->board[to] = p; piece->pos = to; piece->p = p; set_pboard(b, to, piece); add_hash(b, piece->pos, piece->p); eval_piece(b, piece); if (is_sliding(p)) b->sliding_mask |= (1<pawns7th |= (1<piece_mask |= (1<material_mask |= (1<pieces); Square pos = piece->pos; if (to == QUEEN && !(b->piece_mask & WQUEEN_MASK)) { remove_piece(b, piece); add_piece(b, QUEEN, pos, &(WHITEPIECES(b)[IQUEEN])); } else if (to == -QUEEN && !(b->piece_mask & BQUEEN_MASK)) { remove_piece(b, piece); add_piece(b, -QUEEN, pos, &(BLACKPIECES(b)[IQUEEN])); } else { deval_piece(b, piece); remove_hash(b, piece->pos, piece->p); b->board[piece->pos] = to; piece->p = to; add_hash(b, piece->pos, piece->p); eval_piece(b, piece); if (is_sliding(to)) { b->sliding_mask |= (1<piece_mask |= (1<fifty_count > REPITITION_LENGTH) return 1; /* and evaluate as a draw if the position has occurred before with the same player to play */ for (i=b->move_num-2; repeats && i>=(b->move_num - b->fifty_count); i-=2) { if (state->hash_list[i] == b->hash1) repeats--; } return repeats == 0; } static inline void copy_position(Position *d, Position *s) { int n = (((char *)&d->dont_copy) - ((char *)d)); memcpy((char *)d, (char *)s, n); } /* execute the move on the board and update the flags and all the state information */ int do_move_part1(Position *b, Position *oldb, Move *move) { Piece p1; PieceStruct *piece, *oldpiece; int complex_move = 0; static Position b1; init_hash_values(); if (oldb == b) { b1 = (*b); oldb = &b1; } else { copy_position(b, oldb); } p1 = b->board[move->from]; piece = get_pboard(b, move->from); if (!piece || !p1) { lprintf(0,"no piece! %s\n", short_movestr(b, move)); print_board(b->board); save_game("bug.game"); return 0; } #if 0 if ((b->board[move->from] > 0 && b->board[move->to] > 0) || (b->board[move->from] < 0 && b->board[move->to] < 0)) { lprintf(0,"own capture! %s\n", short_movestr(b, move)); print_board(b->board); save_game("bug.game"); return 0; } if (abs(b->board[move->to]) == KING) { lprintf(0,"king capture! %s\n", short_movestr(b, move)); print_board(b->board); save_game("bug.game"); return 0; } #endif oldpiece = get_pboard(b, move->to); b->last_move = (*move); zero_move(&b->best_capture); b->flags = oldb->flags & ~(FLAG_CHECK|FLAG_PREV_CHECK|FLAG_EVAL_DONE|FLAG_EXTENDED|FLAG_DONE_TACTICS); if (oldb->flags & FLAG_CHECK) { b->flags |= FLAG_PREV_CHECK; } if (oldpiece) { remove_piece(b, oldpiece); } move_piece(b, piece, move->to); /* that was the easy bit - now all the messy bits */ /* did they take enpassent? */ if (oldb->enpassent && move->to == oldb->enpassent && abs(p1) == PAWN) { if (p1 == PAWN) { oldpiece = get_pboard(b, move->to + SOUTH); } else { oldpiece = get_pboard(b, move->to + NORTH); } remove_piece(b, oldpiece); complex_move = 1; } /* did they promote? */ if (oldb->pawns7th) { if (p1 == PAWN && YPOS(piece->pos) == 7) { if (oldb->promotion) change_piece(b, piece, oldb->promotion); else { change_piece(b, piece, QUEEN); b->flags |= FLAG_WHITE_PROMOTE; } complex_move = 1; } else if (p1 == -PAWN && YPOS(piece->pos) == 0) { if (oldb->promotion) change_piece(b, piece, -oldb->promotion); else { change_piece(b, piece, -QUEEN); b->flags |= FLAG_BLACK_PROMOTE; } complex_move = 1; } } b->promotion = 0; b->hash1 ^= (oldb->enpassent<<8); /* can the next player move enpassent? */ if (p1 == PAWN && (move->to == move->from + 2*NORTH) && (oldb->topieces[move->from+NORTH] & BPAWN_MASK)) { b->enpassent = move->from + NORTH; } else if (p1 == -PAWN && (move->to == move->from + 2*SOUTH) && (oldb->topieces[move->from+SOUTH] & WPAWN_MASK)) { b->enpassent = move->from + SOUTH; } else { b->enpassent = 0; } b->hash1 ^= (b->enpassent<<8); if (!(b->flags & FLAG_CAN_CASTLE)) goto cant_castle; b->hash1 ^= (b->flags & (FLAG_CAN_CASTLE)) << 16; /* have they castled? */ if (p1 == KING || p1 == -KING) { if (move->to == move->from + 2*EAST) { move_piece(b, get_pboard(b, move->from + 3*EAST), move->from + EAST); complex_move = 1; } else if (move->to == move->from + 2*WEST) { move_piece(b, get_pboard(b, move->from + 4*WEST), move->from + WEST); complex_move = 1; } } /* have they wrecked their castling chances? There are lots of ways to do it! */ if (p1 == KING && (b->flags & (WHITE_CASTLE_LONG | WHITE_CASTLE_SHORT))) { if (move->from == E1 && (move->to == G1 || move->to == C1)) b->flags |= WHITE_CASTLED; b->flags &= ~(WHITE_CASTLE_LONG | WHITE_CASTLE_SHORT); } else if (p1 == -KING && (b->flags & (BLACK_CASTLE_LONG | BLACK_CASTLE_SHORT))) { if (move->from == E8 && (move->to == G8 || move->to == C8)) b->flags |= BLACK_CASTLED; b->flags &= ~(BLACK_CASTLE_LONG | BLACK_CASTLE_SHORT); } if (p1 == ROOK) { if (move->from == A1 && (b->flags & WHITE_CASTLE_LONG)) { b->flags &= ~WHITE_CASTLE_LONG; } else if (move->from == H1 && (b->flags & WHITE_CASTLE_SHORT)) { b->flags &= ~WHITE_CASTLE_SHORT; } } else if (p1 == -ROOK) { if (move->from == A8 && (b->flags & BLACK_CASTLE_LONG)) { b->flags &= ~BLACK_CASTLE_LONG; } else if (move->from == H8 && (b->flags & BLACK_CASTLE_SHORT)) { b->flags &= ~BLACK_CASTLE_SHORT; } } /* this covers rook captures which wreck castling chances */ if (oldpiece) { if (move->to == A1 && (b->flags & WHITE_CASTLE_LONG)) { b->flags &= ~WHITE_CASTLE_LONG; } else if (move->to == H1 && (b->flags & WHITE_CASTLE_SHORT)) { b->flags &= ~WHITE_CASTLE_SHORT; } else if (move->to == A8 && (b->flags & BLACK_CASTLE_LONG)) { b->flags &= ~BLACK_CASTLE_LONG; } else if (move->to == H8 && (b->flags & BLACK_CASTLE_SHORT)) { b->flags &= ~BLACK_CASTLE_SHORT; } } b->hash1 ^= (b->flags & (FLAG_CAN_CASTLE)) << 16; if ((b->flags & FLAG_CAN_CASTLE) != (oldb->flags & FLAG_CAN_CASTLE)) complex_move = 1; cant_castle: /* update the fifty move counter */ if (oldpiece || abs(p1) == PAWN) b->fifty_count = 1; else b->fifty_count = oldb->fifty_count+1; state->hash_list[oldb->move_num] = oldb->hash1; state->hash_list[oldb->move_num+1] = b->hash1; b->move_num = oldb->move_num+1; b->winner = oldb->winner; b->num_moves = 0; b->moves = NULL; if (oldb != &b1) { b->oldb = oldb; } else { b->oldb = NULL; complex_move = 1; } /* we use the bottom bit of hash1 to indicate who is to move in hash entries */ b->hash1 ^= 1; if (!complex_move) { b->flags |= FLAG_NEED_PART2; return 1; } regen_moves(b); b->flags &= ~FLAG_NEED_PART2; if (p1 > 0) { int bkpos = BLACKPIECES(b)[IKING].pos; int wkpos = WHITEPIECES(b)[IKING].pos; if (b->topieces[wkpos] & BLACK_MASK) return 0; if (b->topieces[bkpos] & WHITE_MASK) b->flags |= FLAG_CHECK; } else { int bkpos = BLACKPIECES(b)[IKING].pos; int wkpos = WHITEPIECES(b)[IKING].pos; if (b->topieces[bkpos] & WHITE_MASK) return 0; if (b->topieces[wkpos] & BLACK_MASK) b->flags |= FLAG_CHECK; } return 1; } /* execute the move on the board and update the flags and all the state information */ int do_move_part2(Position *b) { if (!(b->flags & FLAG_NEED_PART2)) return 1; b->flags &= ~FLAG_NEED_PART2; update_moves(b, b->oldb, &b->last_move); if (blacks_move(b)) { int bkpos = BLACKPIECES(b)[IKING].pos; int wkpos = WHITEPIECES(b)[IKING].pos; if (b->topieces[wkpos] & BLACK_MASK) return 0; if (b->topieces[bkpos] & WHITE_MASK) b->flags |= FLAG_CHECK; } else { int bkpos = BLACKPIECES(b)[IKING].pos; int wkpos = WHITEPIECES(b)[IKING].pos; if (b->topieces[bkpos] & WHITE_MASK) return 0; if (b->topieces[wkpos] & BLACK_MASK) b->flags |= FLAG_CHECK; } return 1; } int do_move(Position *b, Position *oldb, Move *move) { if (!do_move_part1(b, oldb, move)) return 0; return do_move_part2(b); } /* setup the usual initial position */ void setup_board(Position *b) { timer_reset(); memset(b, 0, sizeof(*b)); /* all castling options are enabled */ b->flags = WHITE_CASTLE_LONG | WHITE_CASTLE_SHORT | BLACK_CASTLE_LONG | BLACK_CASTLE_SHORT; b->board[A1] = b->board[H1] = ROOK; b->board[B1] = b->board[G1] = KNIGHT; b->board[C1] = b->board[F1] = BISHOP; b->board[D1] = QUEEN; b->board[E1] = KING; b->board[A2] = b->board[B2] = b->board[C2] = b->board[D2] = PAWN; b->board[E2] = b->board[F2] = b->board[G2] = b->board[H2] = PAWN; b->board[A8] = b->board[H8] = -ROOK; b->board[B8] = b->board[G8] = -KNIGHT; b->board[C8] = b->board[F8] = -BISHOP; b->board[D8] = -QUEEN; b->board[E8] = -KING; b->board[A7] = b->board[B7] = b->board[C7] = b->board[D7] = -PAWN; b->board[E7] = b->board[F7] = b->board[G7] = b->board[H7] = -PAWN; create_pboard(b); } static int piece_comp(const void *pp1, const void *pp2) { PieceStruct *p1; PieceStruct *p2; int ret; p1 = (PieceStruct *)pp1; p2 = (PieceStruct *)pp2; ret = abs(p2->p) - abs(p1->p); if (ret == 0) return p2->pos - p1->pos; return ret; } static void shiftup(PieceStruct *p, int loc, int *n) { memmove(&p[loc+1], &p[loc], ((*n)-loc)*sizeof(*p)); p[loc].p = 0; (*n)++; } /* this assumes the board is correct and tries to form a pboard and piece list. Its done in this ugly way so that KnightCap can setup any position using the same code, and get the pieces in a sensible order for its bitmasks */ int create_pboard(Position *b) { int i; PieceStruct *pw = WHITEPIECES(b); PieceStruct *pb = BLACKPIECES(b); PieceStruct t; int w_pieces=0; int b_pieces=0; int w_pawns=0; int b_pawns=0; b->winner = 0; init_hash_values(); memset(b->pboard, 0, sizeof(b->pboard)); memset(b->pieces, 0, sizeof(b->pieces)); b->sliding_mask = 0; b->pawns7th = 0; b->hash1 = b->move_num & 1; b->hash2 = 0; b->piece_mask = 0; b->material_mask = 0; b->w_material = 0; b->b_material = 0; b->promotion = 0; b->wpassed_pawn_mask = 0; b->bpassed_pawn_mask = 0; for (i=A1;i<=H8;i++) { Piece p = b->board[i]; if (p == PAWN) { w_pawns++; } else if (p == -PAWN) { b_pawns++; } else if (p > PAWN) { pw->pos = i; pw->p = p; pw++; w_pieces++; } else if (p < -PAWN) { pb->pos = i; pb->p = p; pb++; b_pieces++; } } pw = &WHITEPIECES(b)[16 - w_pawns]; pb = &BLACKPIECES(b)[16 - b_pawns]; for (i=A1;i<=H8;i++) { Piece p = b->board[i]; if (p == PAWN) { pw->pos = i; pw->p = p; pw++; } else if (p == -PAWN) { pb->pos = i; pb->p = p; pb++; } } pw = WHITEPIECES(b); pb = BLACKPIECES(b); qsort(pw, w_pieces, sizeof(*pw), piece_comp); qsort(pb, b_pieces, sizeof(*pb), piece_comp); if (pw[0].p != KING || pb[0].p != -KING) { lprintf(0,"no king!\n"); return 0; } if (pw[IQUEEN].p != QUEEN) shiftup(pw, IQUEEN, &w_pieces); if (pw[IKROOK].p != ROOK) shiftup(pw, IKROOK, &w_pieces); if (pw[IQROOK].p != ROOK) shiftup(pw, IQROOK, &w_pieces); if (pw[IKBISHOP].p != BISHOP) shiftup(pw, IKBISHOP, &w_pieces); if (pw[IQBISHOP].p != BISHOP) shiftup(pw, IQBISHOP, &w_pieces); if (pw[IKKNIGHT].p != KNIGHT) shiftup(pw, IKKNIGHT, &w_pieces); if (pw[IQKNIGHT].p != KNIGHT) shiftup(pw, IQKNIGHT, &w_pieces); if (pb[IQUEEN].p != -QUEEN) shiftup(pb, IQUEEN, &b_pieces); if (pb[IKROOK].p != -ROOK) shiftup(pb, IKROOK, &b_pieces); if (pb[IQROOK].p != -ROOK) shiftup(pb, IQROOK, &b_pieces); if (pb[IKBISHOP].p != -BISHOP) shiftup(pb, IKBISHOP, &b_pieces); if (pb[IQBISHOP].p != -BISHOP) shiftup(pb, IQBISHOP, &b_pieces); if (pb[IKKNIGHT].p != -KNIGHT) shiftup(pb, IKKNIGHT, &b_pieces); if (pb[IQKNIGHT].p != -KNIGHT) shiftup(pb, IQKNIGHT, &b_pieces); if (pw[IKBISHOP].p && !white_square(pw[IKBISHOP].pos)) { t = pw[IKBISHOP]; pw[IKBISHOP] = pw[IQBISHOP]; pw[IQBISHOP] = t; } if (pb[IKBISHOP].p && white_square(pb[IKBISHOP].pos)) { t = pb[IKBISHOP]; pb[IKBISHOP] = pb[IQBISHOP]; pb[IQBISHOP] = t; } /* now the pboard */ memset(b->board, 0, sizeof(b->board)); memset(b->pboard, -1, sizeof(b->pboard)); pw = WHITEPIECES(b); for (i=0;i<32;i++, pw++) { if (pw->p) add_piece(b, pw->p, pw->pos, pw); } if (b->board[E1] != KING) { b->flags &= ~(WHITE_CASTLE_SHORT | WHITE_CASTLE_LONG); } if (b->board[E8] != -KING) { b->flags &= ~(BLACK_CASTLE_SHORT | BLACK_CASTLE_LONG); } if (b->board[H1] != ROOK) { b->flags &= ~WHITE_CASTLE_SHORT; } if (b->board[A1] != ROOK) { b->flags &= ~WHITE_CASTLE_LONG; } if (b->board[H8] != -ROOK) { b->flags &= ~BLACK_CASTLE_SHORT; } if (b->board[A8] != -ROOK) { b->flags &= ~BLACK_CASTLE_LONG; } b->hash1 ^= (b->enpassent<<8); b->hash1 ^= (b->flags & (FLAG_CAN_CASTLE)) << 16; regen_moves(b); return 1; }