Exemplo n.º 1
0
bool board_equal(const board_t * board_1, const board_t * board_2) {

   int sq_64, sq;

   ASSERT(board_is_ok(board_1));
   ASSERT(board_is_ok(board_2));

   // fast comparison

   if (board_1->key != board_2->key) return false;

   // slow comparison

   for (sq_64 = 0; sq_64 < 64; sq_64++) {
      sq = square_from_64(sq_64);
      if (board_1->square[sq] != board_2->square[sq]) return false;
   }

   if (board_1->turn != board_2->turn) return false;
   if (board_1->castle[White][SideH] != board_2->castle[White][SideH]) return false;
   if (board_1->castle[White][SideA] != board_2->castle[White][SideA]) return false;
   if (board_1->castle[Black][SideH] != board_2->castle[Black][SideH]) return false;
   if (board_1->castle[Black][SideA] != board_2->castle[Black][SideA]) return false;
   if (board_1->ep_square != board_2->ep_square) return false;

   return true;
}
Exemplo n.º 2
0
void move_undo_null(board_t * board, const undo_t * undo) {

   ASSERT(board!=NULL);
   ASSERT(undo!=NULL);

   ASSERT(board_is_legal(board));
   ASSERT(!board_is_check(board));

   // update board info

   board->turn = undo->turn;
   board->ep_square = undo->ep_square;
   board->ply_nb = undo->ply_nb;
   board->cap_sq = undo->cap_sq;
   board->key = undo->key;

   // update key stack

   ASSERT(board->sp>0);
   board->sp--;

   // debug

   ASSERT(board_is_ok(board));
}
Exemplo n.º 3
0
int king_pos(const board_t * board, int colour) {

   ASSERT(board_is_ok(board));
   ASSERT(colour_is_ok(colour));

   return board->list[colour][0];
}
Exemplo n.º 4
0
bool is_in_check(const board_t * board, int colour) {

    ASSERT(board_is_ok(board));
    ASSERT(colour_is_ok(colour));

    return is_attacked(board,king_pos(board,colour),colour_opp(colour));
}
Exemplo n.º 5
0
void filter_legal(list_t * list, const board_t * board) {

   int pos;
   int i, move, value;

   ASSERT(list_is_ok(list));
   ASSERT(board_is_ok(board));

   pos = 0;

   for (i = 0; i < list_size(list); i++) {

      ASSERT(pos>=0&&pos<=i);

      move = list_move(list,i);
      value = list_value(list,i);

      if (pseudo_is_legal(move,board)) {
         list->move[pos] = move;
         list->value[pos] = value;
         pos++;
      }
   }

   ASSERT(pos>=0&&pos<=list_size(list));
   list->size = pos;
}
Exemplo n.º 6
0
bool piece_attack(const board_t * board, int piece, int from, int to) {

    int delta;
    int inc, sq;

    ASSERT(board_is_ok(board));
    ASSERT(piece_is_ok(piece));
    ASSERT(square_is_ok(from));
    ASSERT(square_is_ok(to));

    delta = to - from;
    ASSERT(delta_is_ok(delta));

    if ((piece & DELTA_MASK(delta)) == 0) return false; // no pseudo-attack

    if (!piece_is_slider(piece)) return true;

    inc = DELTA_INC(delta);
    ASSERT(inc_is_ok(inc));

    for (sq = from+inc; sq != to; sq += inc) {
        ASSERT(square_is_ok(sq));
        if (board->square[sq] != Empty) return false; // blocker
    }

    return true;
}
Exemplo n.º 7
0
void board_copy(board_t * dst, const board_t * src) {

   ASSERT(dst!=NULL);
   ASSERT(board_is_ok(src));

   *dst = *src;
}
Exemplo n.º 8
0
bool board_is_stalemate(const board_t * board) {

   ASSERT(board_is_ok(board));

   if (board_is_check(board)) return false;
   if (board_can_play(board)) return false;

   return true;
}
Exemplo n.º 9
0
int board_mobility(const board_t * board) {

   list_t list[1];

   ASSERT(board_is_ok(board));

   gen_legal_moves(list,board);

   return list_size(list);
}
Exemplo n.º 10
0
bool move_is_pseudo(int move, const board_t * board) {

   list_t list[1];

   ASSERT(move_is_ok(move));
   ASSERT(board_is_ok(board));

   gen_moves(list,board);

   return list_contain(list,move);
}
Exemplo n.º 11
0
static bool move_is_legal_debug(int move, const board_t * board) {

   list_t list[1];

   ASSERT(move_is_ok(move));
   ASSERT(board_is_ok(board));

   gen_legal_moves(list,board);

   return list_contain(list,move);
}
Exemplo n.º 12
0
bool move_is_legal(int move, const board_t * board) {

   bool legal;

   ASSERT(move_is_ok(move));
   ASSERT(board_is_ok(board));

   legal = move_is_pseudo(move,board) && pseudo_is_legal(move,board);
   ASSERT(legal==move_is_legal_debug(move,board));

   return legal;
}
Exemplo n.º 13
0
void move_do_null(board_t * board, undo_t * undo) {

   int sq;

   ASSERT(board!=NULL);
   ASSERT(undo!=NULL);

   ASSERT(board_is_legal(board));
   ASSERT(!board_is_check(board));

   // initialise undo

   undo->turn = board->turn;
   undo->ep_square = board->ep_square;
   undo->ply_nb = board->ply_nb;
   undo->cap_sq = board->cap_sq;
	undo->moving_piece = board->moving_piece;
   undo->key = board->key;

   // update key stack

   ASSERT(board->sp<StackSize);
   board->stack[board->sp++] = board->key;

   // update turn

   board->turn = COLOUR_OPP(board->turn);
   board->key ^= RANDOM_64(RandomTurn);

   // update en-passant square

   sq = board->ep_square;
   if (sq != SquareNone) {
      board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA);
      board->ep_square = SquareNone;
   }

   // update move number

   board->ply_nb = 0; // HACK: null move is considered as a conversion

   // update last square

   board->cap_sq = SquareNone;
	board->moving_piece = PieceNone256;

   // debug

   ASSERT(board_is_ok(board));
}
Exemplo n.º 14
0
bool pseudo_is_legal(int move, const board_t * board) {

   board_t new_board[1];

   ASSERT(move_is_ok(move));
   ASSERT(board_is_ok(board));

   ASSERT(move_is_pseudo(move,board));

   board_copy(new_board,board);
   move_do(new_board,move);

   return !is_in_check(new_board,colour_opp(new_board->turn));
}
Exemplo n.º 15
0
Arquivo: san.cpp Projeto: ageneau/scid
int move_from_san(const char string[], const board_t * board) {

   char s[256];
   int move;

   ASSERT(string!=NULL);
   ASSERT(board_is_ok(board));

   san_to_lan(string,board,s,256);
   move = move_from_lan(s,board);

   ASSERT(!UseSlowDebug||move==move_from_san_debug(string,board));

   return move;
}
Exemplo n.º 16
0
bool board_can_play(const board_t * board) {

   list_t list[1];
   int i, move;

   ASSERT(board_is_ok(board));

   gen_moves(list,board);

   for (i = 0; i < list_size(list); i++) {
      move = list_move(list,i);
      if (pseudo_is_legal(move,board)) return true;
   }

   return false; // no legal move
}
Exemplo n.º 17
0
Arquivo: san.cpp Projeto: ageneau/scid
int move_from_san_debug(const char string[], const board_t * board) {

   list_t list[1];
   int i, move;
   char move_string[256];

   ASSERT(string!=NULL);
   ASSERT(board_is_ok(board));

   gen_legal_moves(list,board);

   for (i = 0; i < list_size(list); i++) {
      move = list_move(list,i);
      if (!move_to_san(move,board,move_string,256)) ASSERT(false);
      if (my_string_equal(move_string,string)) return move;
   }

   return MoveNone;
}
Exemplo n.º 18
0
bool line_to_san(const move_t line[], const board_t * board, char string[], int size) {

	board_t new_board[1];
	int pos;
	int move;
	char move_string[256];

	ASSERT(line_is_ok(line));
	ASSERT(board_is_ok(board));
	ASSERT(string!=NULL);
	ASSERT(size>=StringSize);

	// init
	string[0]='\0';
	if (size < StringSize) return false;
//    return false;
	board_copy(new_board,board);
	pos = 0;

	// loop

	while ((move = *line++) != MoveNone) {
		if (pos != 0) {
			if (pos >= size) return false;
			string[pos++] = ' ';
		}
		if (!move_is_legal(move,new_board)
			|| !move_to_san(move,new_board,&string[pos],size-pos)) {
				if (Strict || UseDebug) {
					move_to_can(move,new_board,move_string,sizeof(move_string));
					my_log("POLYGLOT ILLEGAL MOVE IN LINE %s\n",move_string);
					board_disp(new_board);
					if (Strict) my_fatal("line_to_san(): illegal move\n");
				}
				break;
		}
		pos += (int)strlen(&string[pos]);
		move_do(new_board,move);
	}
	if (pos >= size) return false;
	string[pos] = '\0';
	return true;
}
Exemplo n.º 19
0
void list_disp(const list_t * list, const board_t * board) {

   int i, move, value;
   char string[256];

   ASSERT(list_is_ok(list));
   ASSERT(board_is_ok(board));

   for (i = 0; i < list->size; i++) {

      move = list->move[i];
      value = list->value[i];

      if (!move_to_can(move,board,string,256)) ASSERT(false);
      my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value);
   }

   my_log("POLYGLOT\n");
}
Exemplo n.º 20
0
bool is_attacked(const board_t * board, int to, int colour) {

    const uint8 * ptr;
    int from, piece;

    ASSERT(board_is_ok(board));
    ASSERT(square_is_ok(to));
    ASSERT(colour_is_ok(colour));

    for (ptr = board->list[colour]; (from=*ptr) != SquareNone; ptr++) {

        piece = board->square[from];
        ASSERT(colour_equal(piece,colour));

        if (piece_attack(board,piece,from,to)) return true;
    }

    return false;
}
Exemplo n.º 21
0
void move_undo_null( const undo_t * undo) {

   
   ASSERT(undo!=NULL);

   // update board info

   Turn = undo->turn;
   Key = undo->key;
   Lock= undo->lock;

   // update key stack

   ASSERT(Sp>0);
   Sp--;

   // debug

   ASSERT(board_is_ok(board));
}
Exemplo n.º 22
0
static void perft(const board_t * board, int depth) {

   int me;
   list_t list[1];
   int i, move;
   board_t new_board[1];

   ASSERT(board_is_ok(board));
   ASSERT(depth_is_ok(depth));

   ASSERT(!is_in_check(board,colour_opp(board->turn)));

   // init

   NodeNb++;

   // leaf

   if (depth == 0) {
      LeafNb++;
      return;
   }

   // more init

   me = board->turn;

   // move loop

   gen_moves(list,board);

   for (i = 0; i < list_size(list); i++) {

      move = list_move(list,i);

      board_copy(new_board,board);
      move_do(new_board,move);

      if (!is_in_check(new_board,me)) perft(new_board,depth-1);
   }
}
Exemplo n.º 23
0
bool game_is_ok(const game_t * game) {

   board_t board[1];
   int pos, move;

   if (game == NULL) return false;

   if (game->size < 0 || game->size > GameSize) return false;
   if (game->pos < 0 || game->pos > game->size) return false;

   // optional heavy DEBUG mode

   if (!UseSlowDebug) return true;

   if (!board_is_ok(game->start_board)) return false;

   board_copy(board,game->start_board);

   for (pos = 0; pos <= game->size; pos++) {

      if (pos == game->pos) {
         if (!board_equal(game->board,board)) return false;
      }

      if (pos >= game->size) break;

      if (game->key[pos] != board->key) return false;

      move = game->move[pos];
      if (!move_is_legal(move,board))
          ;

      move_do(board,move);
   }

   if (game->status != game_comp_status(game)) return false;

   return true;
}
Exemplo n.º 24
0
int search_full_root(list_t * list, board_t * board, int a, int b, int depth, int search_type, int ThreadId) {

   int value;

   ASSERT(list_is_ok(list));
   ASSERT(board_is_ok(board));
   ASSERT(depth_is_ok(depth));
   ASSERT(search_type==SearchNormal||search_type==SearchShort);

   ASSERT(list==SearchRoot[ThreadId]->list);
   ASSERT(!LIST_IS_EMPTY(list));
   ASSERT(board==SearchCurrent[ThreadId]->board);
   ASSERT(board_is_legal(board));
   ASSERT(depth>=1);

   value = full_root(list,board,a,b,depth,0,search_type, ThreadId);

   ASSERT(value_is_ok(value));
   ASSERT(LIST_VALUE(list,0)==value);

   return value;
}
Exemplo n.º 25
0
bool line_to_can(const move_t line[], const board_t * board, char string[], int size) {

   board_t new_board[1];
   int pos;
   int move;

   ASSERT(line_is_ok(line));
   ASSERT(board_is_ok(board));
   ASSERT(string!=NULL);
   ASSERT(size>=StringSize);

   // init

   if (size < StringSize) return false;

   board_copy(new_board,board);
   pos = 0;

   // loop

   while ((move = *line++) != MoveNone) {

      if (pos != 0) {
         if (pos >= size) return false;
         string[pos++] = ' ';
      }

      if (!move_to_can(move,new_board,&string[pos],size-pos)) return false;
      pos += (int)strlen(&string[pos]);

      move_do(new_board,move);
   }

   if (pos >= size) return false;
   string[pos] = '\0';

   return true;
}
Exemplo n.º 26
0
bool line_from_can (move_t line[], const board_t * board, const char string[], int size) {

   int pos;
   char new_string[StringSize], *p;
   int move;
   board_t new_board[1];

   ASSERT(line!=NULL);
   ASSERT(board_is_ok(board));
   ASSERT(string!=NULL);
   ASSERT(size>=LineSize);

   // init

   pos = 0;
   board_copy(new_board,board);

   // loop

   strcpy(new_string,string); // HACK

   for (p = strtok(new_string," "); p != NULL; p = strtok(NULL," ")) {
      move = move_from_can(p,new_board);
      ASSERT(move!=MoveNone);
      ASSERT(move_is_legal(move,new_board));
      if (move == MoveNone || !move_is_legal(move,new_board)) break; // HACK: ignore illegal moves
      if (pos >= size) return false;
      line[pos++] = move;

      move_do(new_board,move);
   }

   if (pos >= size) return false;
   line[pos] = MoveNone;

   return true;
}
Exemplo n.º 27
0
void search_perft(const board_t * board, int depth_max) {

   int depth;
   my_timer_t timer[1];
   double time, speed;

   ASSERT(board_is_ok(board));
   ASSERT(depth_max>=1&&depth_max<DepthMax);

   // init

   board_disp(board);

   // iterative deepening

   for (depth = 1; depth <= depth_max; depth++) {

      // init

      NodeNb = 0;
      LeafNb = 0;

      my_timer_reset(timer);

      my_timer_start(timer);
      perft(board,depth);
      my_timer_stop(timer);

      time = my_timer_elapsed_cpu(timer);
      speed = (time < 0.01) ? 0.0 : double(NodeNb) / time;

      printf("%2d %10lld %10lld %7.2f %7.0f\n",depth,NodeNb,LeafNb,time,speed);
   }

   printf("\n");
}
Exemplo n.º 28
0
int search_full_root(list_t * list, board_t * board, int depth, int search_type) {

   int value, a, b;

   ASSERT(list_is_ok(list));
   ASSERT(board_is_ok(board));
   ASSERT(depth_is_ok(depth));
   ASSERT(search_type==SearchNormal||search_type==SearchShort);

   ASSERT(list==SearchRoot->list);
   ASSERT(!LIST_IS_EMPTY(list));
   ASSERT(board==SearchCurrent->board);
   ASSERT(board_is_legal(board));
   ASSERT(depth>=1);

   if (SearchBest[SearchCurrent->multipv].value == 0){
	   a = -ValueInf;
	   b = +ValueInf;
   }
   else{
	   a = SearchBest[SearchCurrent->multipv].value - 40;
	   b = SearchBest[SearchCurrent->multipv].value + 40;
   }

   if (SearchInput->multipv > 0){
	   a = -ValueInf;
       b = +ValueInf;
   }

   value = full_root(list,board,a,b,depth,0,search_type);

   ASSERT(value_is_ok(value));
   ASSERT(LIST_VALUE(list,0)==value);

   return value;
}
Exemplo n.º 29
0
void search() {

   int move;
   int depth;
   int i;
   bool search_ready;

     
   for (i = 0; i < MultiPVMax; i++){
	  save_multipv[SearchCurrent->multipv].mate = 0;
	  save_multipv[SearchCurrent->multipv].depth = 0;
	  save_multipv[SearchCurrent->multipv].max_depth = 0;
	  save_multipv[SearchCurrent->multipv].value = 0;
	  save_multipv[SearchCurrent->multipv].time = 0;
	  save_multipv[SearchCurrent->multipv].node_nb = 0;
	  strcpy(save_multipv[SearchCurrent->multipv].pv_string,""); 
   }
  
   SearchInput->multipv = option_get_int("MultiPV")-1;
   SearchCurrent->multipv = 0;
   
   
   ASSERT(board_is_ok(SearchInput->board));

   // opening book

   if (option_get_bool("OwnBook") && !SearchInput->infinite) {

      move = book_move(SearchInput->board);

      if (move != MoveNone) {

         // play book move

         SearchBest[SearchCurrent->multipv].move = move;
         SearchBest[SearchCurrent->multipv].value = 1;
         SearchBest[SearchCurrent->multipv].flags = SearchExact;
         SearchBest[SearchCurrent->multipv].depth = 1;
         SearchBest[SearchCurrent->multipv].pv[0] = move;
         SearchBest[SearchCurrent->multipv].pv[1] = MoveNone;

         search_update_best();

         return;
      }
   }

   // SearchInput

   gen_legal_moves(SearchInput->list,SearchInput->board);

   if (LIST_SIZE(SearchInput->list) < SearchInput->multipv+1){ 
	  SearchInput->multipv = LIST_SIZE(SearchInput->list)-1;
   }

   if (LIST_SIZE(SearchInput->list) <= 1) {
      SearchInput->depth_is_limited = true;
      SearchInput->depth_limit = 4; // was 1
   }

   // SearchInfo

   if (setjmp(SearchInfo->buf) != 0) {
      ASSERT(SearchInfo->can_stop);
      ASSERT(SearchBest->move!=MoveNone);
      search_update_current();
      return;
   }

   // SearchRoot

   list_copy(SearchRoot->list,SearchInput->list);

   // SearchCurrent

   board_copy(SearchCurrent->board,SearchInput->board);
   my_timer_reset(SearchCurrent->timer);
   my_timer_start(SearchCurrent->timer);

   // init

   trans_inc_date(Trans);

   sort_init();
   search_full_init(SearchRoot->list,SearchCurrent->board);

   // analyze game for evaluation
   
   if (SearchCurrent->board->piece_size[White] < 3 && SearchCurrent->board->piece_size[Black] < 3){
	   trans_endgame = true;
   }
   else{
	   trans_endgame = false;
   }

   
   // iterative deepening

   search_ready = false;

   for (depth = 1; depth < DepthMax; depth++) {
	   for (SearchCurrent->multipv = 0; SearchCurrent->multipv <= SearchInput->multipv; SearchCurrent->multipv++){

		  if (DispDepthStart && SearchCurrent->multipv == 0) send("info depth %d",depth);

		  SearchCurrent->max_extensions = depth * 10;
		  SearchRoot->bad_1 = false;
		  SearchRoot->change = false;

		  board_copy(SearchCurrent->board,SearchInput->board);

		  if (UseShortSearch && depth <= ShortSearchDepth) {
			 search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort);
		  } else {
			 search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal);
		  }

		  search_update_current();

		  if (DispDepthEnd && SearchCurrent->multipv == SearchInput->multipv) {
			 send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed);
		  }

		  // update search info

		  if (depth >= 1) SearchInfo->can_stop = true;

		  if (depth == 1
		   && LIST_SIZE(SearchRoot->list) >= 2
		   && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) {
			 SearchRoot->easy = true;
		  }

		  if (depth > 1) {
			 SearchRoot->bad_2 = SearchRoot->bad_1;
			 SearchRoot->bad_1 = false;
			 ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold));
		  }

		  SearchRoot->last_value = SearchBest[SearchCurrent->multipv].value;

		  // stop search?

		  if (SearchInput->depth_is_limited && SearchCurrent->multipv >= SearchInput->multipv
		   && depth >= SearchInput->depth_limit) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time * 2 >= SearchInput->time_limit_1
		   && !SearchRoot->bad_2) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio
		   && SearchRoot->easy) {
			 ASSERT(!SearchRoot->bad_2);
			 ASSERT(!SearchRoot->change);
			 SearchRoot->flag = true;
		  }

		  if (SearchInput->time_is_limited
		   && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio
		   && !SearchRoot->bad_2
		   && !SearchRoot->change) {
			 SearchRoot->flag = true;
		  }

		  if (SearchInfo->can_stop 
		   && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) {
			  search_ready = true;
			  break;
		  }
	   }
	   if (search_ready)
		   break;
   }
}
Exemplo n.º 30
0
void move_do(board_t * board, int move) {

   int me, opp;
   int from, to;
   int piece, pos, capture;
   int old_flags, new_flags;
   int sq, ep_square;
   int pawn;

   ASSERT(board_is_ok(board));
   ASSERT(move_is_ok(move));

   ASSERT(move_is_pseudo(move,board));

   // init

   me = board->turn;
   opp = colour_opp(me);

   from = move_from(move);
   to = move_to(move);

   piece = board->square[from];
   ASSERT(colour_equal(piece,me));

   pos = board->pos[from];
   ASSERT(pos>=0);

   // update turn

   board->turn = opp;
   board->key ^= random_64(RandomTurn);

   // update castling rights

   old_flags = board_flags(board);

   if (piece_is_king(piece)) {
      board->castle[me][SideH] = SquareNone;
      board->castle[me][SideA] = SquareNone;
   }

   if (board->castle[me][SideH] == from) board->castle[me][SideH] = SquareNone;
   if (board->castle[me][SideA] == from) board->castle[me][SideA] = SquareNone;

   if (board->castle[opp][SideH] == to) board->castle[opp][SideH] = SquareNone;
   if (board->castle[opp][SideA] == to) board->castle[opp][SideA] = SquareNone;

   new_flags = board_flags(board);

   board->key ^= hash_castle_key(new_flags^old_flags); // HACK

   // update en-passant square

   ep_square = sq = board->ep_square;
   if (sq != SquareNone) {
      board->key ^= random_64(RandomEnPassant+square_file(sq));
      board->ep_square = SquareNone;
   }

   if (piece_is_pawn(piece) && abs(to-from) == 32) {
      pawn = piece_make_pawn(opp);
      if (board->square[to-1] == pawn || board->square[to+1] == pawn) {
         board->ep_square = sq = (from + to) / 2;
         board->key ^= random_64(RandomEnPassant+square_file(sq));
      }
   }

   // update ply number (captures are handled later)

   board->ply_nb++;
   if (piece_is_pawn(piece)) board->ply_nb = 0; // conversion

   // update move number

   if (me == Black) board->move_nb++;

   // castle

   if (colour_equal(board->square[to],me)) {

      int rank;
      int king_from, king_to;
      int rook_from, rook_to;
      int rook;

      rank = colour_is_white(me) ? Rank1 : Rank8;

      king_from = from;
      rook_from = to;

      if (to > from) { // h side
         king_to = square_make(FileG,rank);
         rook_to = square_make(FileF,rank);
      } else { // a side
         king_to = square_make(FileC,rank);
         rook_to = square_make(FileD,rank);
      }

      // remove the rook

      pos = board->pos[rook_from];
      ASSERT(pos>=0);

      rook = Rook64 | me; // HACK

      square_clear(board,rook_from,rook);

      // move the king

      square_move(board,king_from,king_to,piece);

      // put the rook back

      square_set(board,rook_to,rook,pos);

      ASSERT(board->key==hash_key(board));

      return;
   }

   // remove the captured piece

   if (piece_is_pawn(piece) && to == ep_square) {

      // en-passant capture

      sq = square_ep_dual(to);
      capture = board->square[sq];
      ASSERT(capture==piece_make_pawn(opp));

      square_clear(board,sq,capture);

      board->ply_nb = 0; // conversion

   } else {

      capture = board->square[to];

      if (capture != Empty) {

         // normal capture

         ASSERT(colour_equal(capture,opp));
         ASSERT(!piece_is_king(capture));

         square_clear(board,to,capture);

         board->ply_nb = 0; // conversion
      }
   }

   // move the piece

   if (move_is_promote(move)) {

      // promote

      square_clear(board,from,piece);
      piece = move_promote_hack(move) | me; // HACK
      square_set(board,to,piece,pos);

   } else {

      // normal move

      square_move(board,from,to,piece);
   }

   ASSERT(board->key==hash_key(board));
}