/******************************************
* Needle - a bitboard based chess engine. *
* (C) 2004 Mikko Nummelin                 *
******************************************/

#define _MOVES_C

#include "needle.h"

extern const unsigned char rsquares[][0x100];
const char promotion_pieces[]="QRBN";

int capture_value(char piece){
	switch(piece){
	case 'Q':
	case 'q':
		return QUEEN_VALUE;
	case 'R':
	case 'r':
		return ROOK_VALUE;
	case 'B':
	case 'b':
		return BISHOP_VALUE;
	case 'N':
	case 'n':
		return KNIGHT_VALUE;
	case 'P':
	case 'p':
	case 'e':
		return PAWN_VALUE;
	}
	return 0;
}

int moving_value(char piece){
	switch(piece){
		case 'K':
		case 'k':
			return -60;
		case 'Q':
		case 'q':
			return -40;
		case 'R':
		case 'r':
			return -50;
		case 'B':
		case 'b':
			return -30;
		case 'N':
		case 'n':
			return -20;
		case 'P':
		case 'p':
			return -10;
	}
	return 0;
}

/* Pushes move into movelist, auto-detects promotions and pushes
 * 4 moves in that case */
void push_move(Movelist *mvl, const char moving_piece, const char *original_square,
	const char *destination_square, const char captured_piece){
	int i;

	/* Is promotion? */
	if(((moving_piece=='P')&&(destination_square[1]=='8'))||
	((moving_piece=='p')&&(destination_square[1]=='1'))){
		/* Yes, it is. */
		for(i=0;i<4;i++) {
			mvl->moves[mvl->size].moving_piece=moving_piece;
			mvl->moves[mvl->size].move[0]=original_square[0];
			mvl->moves[mvl->size].move[1]=original_square[1];
			mvl->moves[mvl->size].move[2]=destination_square[0];
			mvl->moves[mvl->size].move[3]=destination_square[1];
			mvl->moves[mvl->size].move[4]=promotion_pieces[i];
			mvl->moves[mvl->size].move[5]=0;
			mvl->moves[mvl->size].captured_piece=captured_piece;
			mvl->moves[mvl->size].approx_move_value=
				capture_value(promotion_pieces[i])+
				capture_value(captured_piece)-
				capture_value(moving_piece)+200000;
			mvl->size++;
		}
	} else {
		/* No, it is not. */
		mvl->moves[mvl->size].moving_piece=moving_piece;
		mvl->moves[mvl->size].move[0]=original_square[0];
		mvl->moves[mvl->size].move[1]=original_square[1];
		mvl->moves[mvl->size].move[2]=destination_square[0];
		mvl->moves[mvl->size].move[3]=destination_square[1];
		mvl->moves[mvl->size].move[4]=0;
		mvl->moves[mvl->size].captured_piece=captured_piece;
		if(capture_value(captured_piece)!=0) {
			mvl->moves[mvl->size].approx_move_value=
				capture_value(captured_piece)-
				capture_value(moving_piece)+100000;
		} else {
			/* Let's do most of captures first */
			if(((moving_piece=='K')||(moving_piece=='k'))&&
				(abs(original_square[0]-destination_square[0])==2)){
				/* Castling should be given a fair value */
				mvl->moves[mvl->size].approx_move_value=500;
			} else {
				mvl->moves[mvl->size].approx_move_value=moving_value(moving_piece);
			}
		}
		mvl->size++;
	}
}

/* Returns TRUE is the side whose move it currently is,
 * is threatening to virtually capture into the
 * square specified by bitno, FALSE otherwise */
int is_threat(const Board *brd, char whosmove, int bitno){
	Bitboard all,all_r,all_nw,all_ne;
	int rank,file,nw_diano,ne_diano;
	unsigned char occupancy,squares_on_rank,squares_on_file,
		squares_on_nw,squares_on_ne,nw_diamask,ne_diamask;
	if(whosmove=='w'){
		if(kmask_for_bit(bitno)&brd->K.whole)
			return TRUE;
		if(nmask_for_bit(bitno)&brd->N.whole)
			return TRUE;
		if((BITBOARD_UNIT<<nw_bit_for_bit(bitno))&
			((brd->Pnw.whole&0x7c7973674f1f3f7e)<<1))
			return TRUE;
		if((BITBOARD_UNIT<<ne_bit_for_bit(bitno))&
			((brd->Pne.whole&0x7e3e9ecee6f2f8fc)>>1))
			return TRUE;
		all.whole    = totally_all_pieces(brd);
		all_r.whole  = totally_all_pieces_r(brd);
		all_nw.whole = totally_all_pieces_nw(brd);
		all_ne.whole = totally_all_pieces_ne(brd);
		rank         = rankno_for_bit(bitno);
		file		 = bitno&0x7;
		occupancy    = all.rows[rank];
		squares_on_rank = rsquares[file][occupancy];
		if(squares_on_rank & (brd->R.rows[rank] | brd->Q.rows[rank])){
			return TRUE;
		}
		occupancy    = all_r.rows[7-file];
		squares_on_file = rsquares[rank][occupancy];
		if(squares_on_file & (brd->Rr.rows[7-file] | brd->Qr.rows[7-file])){
			return TRUE;
		}
		nw_diano=nw_diano_for_bit(bitno);
		ne_diano=ne_diano_for_bit(bitno);
		nw_diamask=nw_mask_for_bit(bitno);
		ne_diamask=ne_mask_for_bit(bitno);
		occupancy	= all_nw.rows[nw_diano];
		squares_on_nw = rsquares[file][occupancy] & nw_diamask;
		if(squares_on_nw & (brd->Bnw.rows[nw_diano] | brd->Qnw.rows[nw_diano])){
			return TRUE;
		}
		occupancy	= all_ne.rows[ne_diano];
		squares_on_ne = rsquares[file][occupancy] & ne_diamask;
		if(squares_on_ne & (brd->Bne.rows[ne_diano] | brd->Qne.rows[ne_diano])){
			return TRUE;
		}
	} else {
		if(kmask_for_bit(bitno)&brd->k.whole)
			return TRUE;
		if(nmask_for_bit(bitno)&brd->n.whole)
			return TRUE;
		if((BITBOARD_UNIT<<ne_bit_for_bit(bitno))&
			((brd->pne.whole&0x7f3f1f4f6773797c)<<1))
			return TRUE;
		if((BITBOARD_UNIT<<nw_bit_for_bit(bitno))&
			((brd->pnw.whole&0xfcf8f2e6ce9e3e7e)>>1))
			return TRUE;
		all.whole    = totally_all_pieces(brd);
		all_r.whole  = totally_all_pieces_r(brd);
		all_nw.whole = totally_all_pieces_nw(brd);
		all_ne.whole = totally_all_pieces_ne(brd);
		rank         = rankno_for_bit(bitno);
		file		 = bitno&0x7;
		occupancy    = all.rows[rank];
		squares_on_rank = rsquares[file][occupancy];
		if(squares_on_rank & (brd->r.rows[rank] | brd->q.rows[rank])){
			return TRUE;
		}
		occupancy    = all_r.rows[7-file];
		squares_on_file = rsquares[rank][occupancy];
		if(squares_on_file & (brd->rr.rows[7-file] | brd->qr.rows[7-file])){
			return TRUE;
		}
		nw_diano=nw_diano_for_bit(bitno);
		ne_diano=ne_diano_for_bit(bitno);
		nw_diamask=nw_mask_for_bit(bitno);
		ne_diamask=ne_mask_for_bit(bitno);
		occupancy	= all_nw.rows[nw_diano];
		squares_on_nw = rsquares[file][occupancy] & nw_diamask;
		if(squares_on_nw & (brd->bnw.rows[nw_diano] | brd->qnw.rows[nw_diano])){
			return TRUE;
		}
		occupancy	= all_ne.rows[ne_diano];
		squares_on_ne = rsquares[file][occupancy] & ne_diamask;
		if(squares_on_ne & (brd->bne.rows[ne_diano] | brd->qne.rows[ne_diano])){
			return TRUE;
		}
	}
	return FALSE;
}

/* Generates only "straight" promotions. Capture promotions are generated
 * along other captures. */
void generate_promotions(Board *brd, Movelist *mvl){
	int bitno;
	const char *found_square;
	char captured_piece,original_square[3];

	Bitboard almost_promoted, all_pieces, promotion_squares;
	if(brd->whosmove=='w'){
		/* White promotions straight up */
		almost_promoted.whole=brd->Pr.whole&0x4040404040404040;
		all_pieces.whole=totally_all_pieces_r(brd);
		promotion_squares.whole=(almost_promoted.whole<<1)& ~all_pieces.whole;
		while(promotion_squares.whole){
			bitno=my_bsf(promotion_squares.whole);
			found_square=r_square_for_bit(bitno);
			original_square[0]=found_square[0];
			original_square[1]=found_square[1]-1;
			original_square[2]=0;
			captured_piece=' ';
			push_move(mvl,'P',original_square,found_square,captured_piece);
			promotion_squares.whole &= ~(BITBOARD_UNIT<<bitno);
		}
	} else {
		/* Black promotions straight down */
		almost_promoted.whole=brd->pr.whole&0x0202020202020202;
		all_pieces.whole=totally_all_pieces_r(brd);
		promotion_squares.whole=(almost_promoted.whole>>1)& ~all_pieces.whole;
		while(promotion_squares.whole){
			bitno=my_bsf(promotion_squares.whole);
			found_square=r_square_for_bit(bitno);
			original_square[0]=found_square[0];
			original_square[1]=found_square[1]+1;
			original_square[2]=0;
			captured_piece=' ';
			push_move(mvl,'p',original_square,found_square,captured_piece);
			promotion_squares.whole &= ~(BITBOARD_UNIT<<bitno);
		}
	}
}

/* King threats */
void kthreats_to(const Board *brd, Movelist *mvl, char whosmove, int bitno) {

	const char *found_square=NULL,*to_square;
	char captured_piece;
	Bitboard from_these_squares;
	int from_bitno;

	to_square=square_for_bit(bitno);
	captured_piece = testsquare(brd,to_square);
	if(whosmove=='w'){
		/* Sets up bitboard where white king can move from */
		from_these_squares.whole = kmask_for_bit(bitno)&brd->K.whole;
		while(from_these_squares.whole){
			from_bitno=my_bsf(from_these_squares.whole);
			found_square=square_for_bit(from_bitno);
			push_move(mvl,'K',found_square,to_square,captured_piece);
			from_these_squares.whole &= ~(BITBOARD_UNIT<<from_bitno);
		}
	} else {
		/* Sets up bitboard where black king can move from */
		from_these_squares.whole = kmask_for_bit(bitno)&brd->k.whole;
		while(from_these_squares.whole){
			from_bitno=my_bsf(from_these_squares.whole);
			found_square=square_for_bit(from_bitno);
			push_move(mvl,'k',found_square,to_square,captured_piece);
			from_these_squares.whole &= ~(BITBOARD_UNIT<<from_bitno);
		}
	}
}

/* Knight threats */
void nthreats_to(const Board *brd, Movelist *mvl, char whosmove, int bitno) {
	const char *found_square=NULL,*to_square;
	char captured_piece;
	Bitboard from_these_squares;
	int from_bitno;

	to_square=square_for_bit(bitno);
	captured_piece = testsquare(brd,to_square);
	if(whosmove=='w'){
		/* Sets up bitboard where white knight can move from */
		from_these_squares.whole = nmask_for_bit(bitno)&brd->N.whole;
		while(from_these_squares.whole){
			from_bitno=my_bsf(from_these_squares.whole);
			found_square=square_for_bit(from_bitno);
			push_move(mvl,'N',found_square,to_square,captured_piece);
			from_these_squares.whole &= ~(BITBOARD_UNIT<<from_bitno);
		}
	} else {
		/* Sets up bitboard where black knight can move from */
		from_these_squares.whole = nmask_for_bit(bitno)&brd->n.whole;
		while(from_these_squares.whole){
			from_bitno=my_bsf(from_these_squares.whole);
			found_square=square_for_bit(from_bitno);
			push_move(mvl,'n',found_square,to_square,captured_piece);
			from_these_squares.whole &= ~(BITBOARD_UNIT<<from_bitno);
		}
	}
}

/* Pawn threats */
void pthreats_to(const Board *brd, Movelist *mvl, char whosmove,
	int bitno, int pawnmovestyle) {
	Bitboard pawns_single_move_board_r,pawns_double_move_board_r;
	char captured_piece;
	const char *to_square;
	char from_square[3];

	to_square=square_for_bit(bitno);
	captured_piece = testsquare(brd,to_square);
	if(whosmove=='w'){
		if(pawnmovestyle){
			/* Pawns capture */
			if((BITBOARD_UNIT<<nw_bit_for_bit(bitno))&
			((brd->Pnw.whole&0x7c7973674f1f3f7e)<<1)){
				/* NW */
				mvl->moves[mvl->size].moving_piece='P';
				from_square[0]=to_square[0]+1;
				from_square[1]=to_square[1]-1;
				from_square[2]=0;
				push_move(mvl,'P',from_square,to_square,captured_piece);
			}
			if((BITBOARD_UNIT<<ne_bit_for_bit(bitno))&
			((brd->Pne.whole&0x7e3e9ecee6f2f8fc)>>1)){
				/* NE */
				mvl->moves[mvl->size].moving_piece='P';
				from_square[0]=to_square[0]-1;
				from_square[1]=to_square[1]-1;
				from_square[2]=0;
				push_move(mvl,'P',from_square,to_square,captured_piece);
			}
		} else {
			/* Pawns move straight up */
			pawns_single_move_board_r.whole = (brd->Pr.whole&0x7e7e7e7e7e7e7e7e)<<1;
			if((BITBOARD_UNIT<<r_bit_for_bit(bitno))&
			pawns_single_move_board_r.whole){
				/* Up */
				mvl->moves[mvl->size].moving_piece='P';
				from_square[0]=to_square[0];
				from_square[1]=to_square[1]-1;
				from_square[2]=0;
				push_move(mvl,'P',from_square,to_square,captured_piece);
			}
			pawns_double_move_board_r.whole =
				((pawns_single_move_board_r.whole & 0x0404040404040404) &
					~totally_all_pieces_r(brd))<<1;
			if((BITBOARD_UNIT<<r_bit_for_bit(bitno))&
			pawns_double_move_board_r.whole){
				/* Up 2 squares */
				mvl->moves[mvl->size].moving_piece='P';
				from_square[0]=to_square[0];
				from_square[1]=to_square[1]-2;
				from_square[2]=0;
				push_move(mvl,'P',from_square,to_square,captured_piece);
			}
		}
	} else {
		if(pawnmovestyle){
			/* Pawns capture */
			if((BITBOARD_UNIT<<ne_bit_for_bit(bitno))&
			((brd->pne.whole&0x7e3f1f4f6773797c)<<1)){
				/* SW */
				mvl->moves[mvl->size].moving_piece='p';
				from_square[0]=to_square[0]+1;
				from_square[1]=to_square[1]+1;
				from_square[2]=0;
				push_move(mvl,'p',from_square,to_square,captured_piece);
			}
			if((BITBOARD_UNIT<<nw_bit_for_bit(bitno))&
			((brd->pnw.whole&0xfcf8f2e6ce9e3e7e)>>1)){
				/* SE */
				mvl->moves[mvl->size].moving_piece='p';
				from_square[0]=to_square[0]-1;
				from_square[1]=to_square[1]+1;
				from_square[2]=0;
				push_move(mvl,'p',from_square,to_square,captured_piece);
			}
		} else {
			/* Pawns move straight down */
			pawns_single_move_board_r.whole = (brd->pr.whole&0x7e7e7e7e7e7e7e7e)>>1;
			if((BITBOARD_UNIT<<r_bit_for_bit(bitno))&
			pawns_single_move_board_r.whole){
				/* Down */
				mvl->moves[mvl->size].moving_piece='p';
				from_square[0]=to_square[0];
				from_square[1]=to_square[1]+1;
				from_square[2]=0;
				push_move(mvl,'p',from_square,to_square,captured_piece);
			}
			pawns_double_move_board_r.whole =
				((pawns_single_move_board_r.whole & 0x2020202020202020) &
					~totally_all_pieces_r(brd))>>1;
			if((BITBOARD_UNIT<<r_bit_for_bit(bitno))&
			pawns_double_move_board_r.whole){
				/* Down 2 squares */
				mvl->moves[mvl->size].moving_piece='p';
				from_square[0]=to_square[0];
				from_square[1]=to_square[1]+2;
				from_square[2]=0;
				push_move(mvl,'p',from_square,to_square,captured_piece);
			}
		}
	}
}

void rqthreats_to(const Board *brd, Movelist *mvl, char whosmove, int bitno) {

	Bitboard all,all_r;
	int from_bitno,rank,file;
	unsigned char occupancy,squares_on_rank,RQ_on_rank,RQ_on_file,
		squares_on_file;
	char moving_piece,captured_piece;
	const char *found_square=NULL,*to_square;

	to_square=square_for_bit(bitno);
	captured_piece = testsquare(brd,to_square);
	all.whole    = totally_all_pieces(brd);
	all_r.whole  = totally_all_pieces_r(brd);
	rank         = rankno_for_bit(bitno);
	file         = bitno&0x7;

	if(whosmove=='w'){
		/* Rook and queen moves along the rank */
		occupancy    = all.rows[rank];
		squares_on_rank = rsquares[file][occupancy];
		RQ_on_rank = squares_on_rank & (brd->R.rows[rank] | brd->Q.rows[rank]);
		while(RQ_on_rank){
			from_bitno=my_bsf(RQ_on_rank);
			found_square=square_for_bit((rank<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			RQ_on_rank &= ~(0x1<<from_bitno);
		}

		/* Rook and queen moves along the file */
		occupancy    = all_r.rows[7-file];
		squares_on_file = rsquares[rank][occupancy];
		RQ_on_file = squares_on_file & (brd->Rr.rows[7-file] | brd->Qr.rows[7-file]);
		while(RQ_on_file){
			from_bitno=my_bsf(RQ_on_file);
			found_square=square_for_bit((from_bitno<<3)|file);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			RQ_on_file &= ~(0x1<<from_bitno);
		}
	} else {
		/* Rook and queen moves along the rank */
		occupancy    = all.rows[rank];
		squares_on_rank = rsquares[file][occupancy];
		RQ_on_rank = squares_on_rank & (brd->r.rows[rank] | brd->q.rows[rank]);
		while(RQ_on_rank){
			from_bitno=my_bsf(RQ_on_rank);
			found_square=square_for_bit((rank<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			RQ_on_rank &= ~(0x1<<from_bitno);
		}

		/* Rook and queen moves along the file */
		occupancy    = all_r.rows[7-file];
		squares_on_file = rsquares[rank][occupancy];
		RQ_on_file = squares_on_file & (brd->rr.rows[7-file] | brd->qr.rows[7-file]);
		while(RQ_on_file){
			from_bitno=my_bsf(RQ_on_file);
			found_square=square_for_bit((from_bitno<<3)|file);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			RQ_on_file &= ~(0x1<<from_bitno);
		}
	}
}

void bqthreats_to(const Board *brd, Movelist *mvl, char whosmove, int bitno) {

	Bitboard all_nw,all_ne;
	int from_bitno,file,nw_diamask,ne_diamask,nw_diano,ne_diano;
	unsigned char occupancy,BQ_on_nw,BQ_on_ne,squares_on_diagonal;
	char moving_piece,captured_piece;
	const char *found_square=NULL,*to_square;

	to_square=square_for_bit(bitno);
	captured_piece = testsquare(brd,to_square);
	all_nw.whole = totally_all_pieces_nw(brd);
	all_ne.whole = totally_all_pieces_ne(brd);
	file         = bitno&0x7;
	nw_diamask   = nw_mask_for_bit(bitno);
	ne_diamask   = ne_mask_for_bit(bitno);
	nw_diano     = nw_diano_for_bit(bitno);
	ne_diano     = ne_diano_for_bit(bitno);

	if(whosmove=='w'){
		/* White bishop and queen moves along NW_diagonals */
		occupancy    = all_nw.rows[nw_diano];
		squares_on_diagonal = rsquares[file][occupancy] & nw_diamask;
		BQ_on_nw = squares_on_diagonal & (brd->Bnw.rows[nw_diano] | brd->Qnw.rows[nw_diano]);
		while(BQ_on_nw){
			from_bitno=my_bsf(BQ_on_nw);
			found_square=nw_square_for_bit((nw_diano<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			BQ_on_nw &= ~(0x1<<from_bitno);
		}

		occupancy    = all_ne.rows[ne_diano];
		squares_on_diagonal = rsquares[file][occupancy] & ne_diamask;
		BQ_on_ne = squares_on_diagonal & (brd->Bne.rows[ne_diano] | brd->Qne.rows[ne_diano]);
		while(BQ_on_ne){
			from_bitno=my_bsf(BQ_on_ne);
			found_square=ne_square_for_bit((ne_diano<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			BQ_on_ne &= ~(0x1<<from_bitno);
		}
	} else {
		/* Black bishop and queen moves along NW_diagonals */
		occupancy    = all_nw.rows[nw_diano];
		squares_on_diagonal = rsquares[file][occupancy] & nw_diamask;
		BQ_on_nw = squares_on_diagonal & (brd->bnw.rows[nw_diano] | brd->qnw.rows[nw_diano]);
		while(BQ_on_nw){
			from_bitno=my_bsf(BQ_on_nw);
			found_square=nw_square_for_bit((nw_diano<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			BQ_on_nw &= ~(0x1<<from_bitno);
		}

		occupancy    = all_ne.rows[ne_diano];
		squares_on_diagonal = rsquares[file][occupancy] & ne_diamask;
		BQ_on_ne = squares_on_diagonal & (brd->bne.rows[ne_diano] | brd->qne.rows[ne_diano]);
		while(BQ_on_ne){
			from_bitno=my_bsf(BQ_on_ne);
			found_square=ne_square_for_bit((ne_diano<<3)|from_bitno);
			moving_piece=testsquare(brd,found_square);
			push_move(mvl,moving_piece,found_square,to_square,captured_piece);
			BQ_on_ne &= ~(0x1<<from_bitno);
		}
	}
}

/* Similar to is_threat(...), but generates a movelist into square
 * specified by bitno. If pawnmovestyle is FALSE, then pawns move
 * forward, if TRUE, then they are trying to capture into the square. */
void threats_to(const Board *brd, Movelist *mvl, char whosmove,
	int bitno, int pawnmovestyle) {
	kthreats_to(brd,mvl,whosmove,bitno);
	nthreats_to(brd,mvl,whosmove,bitno);
	pthreats_to(brd,mvl,whosmove,bitno,pawnmovestyle);
	rqthreats_to(brd,mvl,whosmove,bitno);
	bqthreats_to(brd,mvl,whosmove,bitno);
}

void generate_captures(Board *brd, Movelist *mvl){
	Bitboard all_opponents_pieces,all_opponents_pieces_nw,all_opponents_pieces_ne,
		all_pawn_capture_squares_nw,all_pawn_capture_squares_ne;
	const char *to_square;
	char captured_piece,from_square[3];
	int found_opp_piece_bit;

	if(brd->whosmove=='w'){
		all_opponents_pieces_nw.whole=all_black_pieces_except_K_nw(brd);
		all_pawn_capture_squares_nw.whole=
			((brd->Pnw.whole & 0x7c7973674f1f3f7e)<<1)&
			(all_opponents_pieces_nw.whole|brd->epnw.whole);
		while(all_pawn_capture_squares_nw.whole){
			found_opp_piece_bit=my_bsf(all_pawn_capture_squares_nw.whole);
			to_square=nw_square_for_bit(found_opp_piece_bit);
			captured_piece=testsquare(brd,to_square);
			from_square[0]=to_square[0]+1;
			from_square[1]=to_square[1]-1;
			push_move(mvl,'P',from_square,to_square,captured_piece);
			all_pawn_capture_squares_nw.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}
		all_opponents_pieces_ne.whole=all_black_pieces_except_K_ne(brd);
		all_pawn_capture_squares_ne.whole=
			((brd->Pne.whole & 0x7e3e9ecee6f2f8fc)>>1)&
			(all_opponents_pieces_ne.whole|brd->epne.whole);
		while(all_pawn_capture_squares_ne.whole){
			found_opp_piece_bit=my_bsf(all_pawn_capture_squares_ne.whole);
			to_square=ne_square_for_bit(found_opp_piece_bit);
			captured_piece=testsquare(brd,to_square);
			from_square[0]=to_square[0]-1;
			from_square[1]=to_square[1]-1;
			push_move(mvl,'P',from_square,to_square,captured_piece);
			all_pawn_capture_squares_ne.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}

		all_opponents_pieces.whole=all_black_pieces_except_K(brd);
		while(all_opponents_pieces.whole){
			found_opp_piece_bit=my_bsf(all_opponents_pieces.whole);
			kthreats_to(brd,mvl,'w',found_opp_piece_bit);
			nthreats_to(brd,mvl,'w',found_opp_piece_bit);
			rqthreats_to(brd,mvl,'w',found_opp_piece_bit);
			bqthreats_to(brd,mvl,'w',found_opp_piece_bit);
			all_opponents_pieces.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}
	} else {
		all_opponents_pieces_nw.whole=all_white_pieces_except_K_nw(brd);
		all_pawn_capture_squares_nw.whole=
			((brd->pnw.whole & 0xfcf8f2e6ce9e3e7e)>>1)&
			(all_opponents_pieces_nw.whole|brd->epnw.whole);
		while(all_pawn_capture_squares_nw.whole){
			found_opp_piece_bit=my_bsf(all_pawn_capture_squares_nw.whole);
			to_square=nw_square_for_bit(found_opp_piece_bit);
			captured_piece=testsquare(brd,to_square);
			from_square[0]=to_square[0]-1;
			from_square[1]=to_square[1]+1;
			push_move(mvl,'p',from_square,to_square,captured_piece);
			all_pawn_capture_squares_nw.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}
		all_opponents_pieces_ne.whole=all_white_pieces_except_K_ne(brd);
		all_pawn_capture_squares_ne.whole=
			((brd->pne.whole & 0x7e3f1f4f6773797c)<<1)&
			(all_opponents_pieces_ne.whole|brd->epne.whole);
		while(all_pawn_capture_squares_ne.whole){
			found_opp_piece_bit=my_bsf(all_pawn_capture_squares_ne.whole);
			to_square=ne_square_for_bit(found_opp_piece_bit);
			captured_piece=testsquare(brd,to_square);
			from_square[0]=to_square[0]+1;
			from_square[1]=to_square[1]+1;
			push_move(mvl,'p',from_square,to_square,captured_piece);
			all_pawn_capture_squares_ne.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}

		all_opponents_pieces.whole=all_white_pieces_except_K(brd);
		while(all_opponents_pieces.whole){
			found_opp_piece_bit=my_bsf(all_opponents_pieces.whole);
			kthreats_to(brd,mvl,'b',found_opp_piece_bit);
			nthreats_to(brd,mvl,'b',found_opp_piece_bit);
			rqthreats_to(brd,mvl,'b',found_opp_piece_bit);
			bqthreats_to(brd,mvl,'b',found_opp_piece_bit);
			all_opponents_pieces.whole &= ~(BITBOARD_UNIT<<found_opp_piece_bit);
		}
	}
}

void generate_quiet_moves(Board *brd, Movelist *mvl){

	Bitboard all_pieces,all_pieces_r,all_pieces_nw,all_pieces_ne,
		all_own_pawns_r,pawns_single_move_board,pawns_double_move_board,
		pdests,all_own_pieces_except_pawns,destsquares;
	int bitno,dest_bitno,rank,file,nw_diamask,ne_diamask,nw_diano,ne_diano;
	const char *to_square,*found_square;
	char moving_piece,from_square[3];
	unsigned char occupancy,squares_on_rank,squares_on_file,squares_on_nw,squares_on_ne;

	all_pieces.whole    = totally_all_pieces(brd);
	all_pieces_r.whole  = totally_all_pieces_r(brd);
	all_pieces_nw.whole = totally_all_pieces_nw(brd);
	all_pieces_ne.whole = totally_all_pieces_ne(brd);

	if(brd->whosmove=='w'){
		/* Generates castling if possible */
		if((brd->castling_flags&0x1)&&
		(brd->K.rows[0]&0x08)&&
		(brd->R.rows[0]&0x01)&&
		((all_pieces.rows[0]&0x0f)==0x09)&&
		(is_threat(brd,'b',3)==FALSE)&&
		(is_threat(brd,'b',2)==FALSE)&&
		(is_threat(brd,'b',1)==FALSE)){
			push_move(mvl,'K',"e1","g1",' '); /* Short castling */
		}

		if((brd->castling_flags&0x2)&&
		(brd->K.rows[0]&0x08)&&
		(brd->R.rows[0]&0x80)&&
		((all_pieces.rows[0]&0xf8)==0x88)&&
		(is_threat(brd,'b',3)==FALSE)&&
		(is_threat(brd,'b',4)==FALSE)&&
		(is_threat(brd,'b',5)==FALSE)){
			push_move(mvl,'K',"e1","c1",' '); /* Long castling */
		}

		all_own_pawns_r.whole=brd->Pr.whole;
		pawns_single_move_board.whole =
			((all_own_pawns_r.whole & 0x3e3e3e3e3e3e3e3e)<<1) & ~all_pieces_r.whole;
		pdests.whole=pawns_single_move_board.whole;
		while(pdests.whole){
			bitno=my_bsf(pdests.whole);
			to_square=r_square_for_bit(bitno);
			from_square[0]=to_square[0];
			from_square[1]=to_square[1]-1;
			from_square[2]=0;
			push_move(mvl,'P',from_square,to_square,' ');
			pdests.whole &= ~(BITBOARD_UNIT<<bitno);
		}
		pawns_double_move_board.whole =
			((pawns_single_move_board.whole & 0x0404040404040404)<<1) & ~all_pieces_r.whole;
		pdests.whole=pawns_double_move_board.whole;
		while(pdests.whole){
			bitno=my_bsf(pdests.whole);
			to_square=r_square_for_bit(bitno);
			from_square[0]=to_square[0];
			from_square[1]=to_square[1]-2;
			from_square[2]=0;
			push_move(mvl,'P',from_square,to_square,' ');
			pdests.whole &= ~(BITBOARD_UNIT<<bitno);
		}

		all_own_pieces_except_pawns.whole=all_white_pieces_except_pawns(brd);
		while(all_own_pieces_except_pawns.whole){
			bitno=my_bsf(all_own_pieces_except_pawns.whole);
			found_square=square_for_bit(bitno);
			moving_piece=testsquare(brd,found_square);
			rank=(bitno&0x38)>>3;
			file=bitno&0x7;
			nw_diamask   = nw_mask_for_bit(bitno);
			ne_diamask   = ne_mask_for_bit(bitno);
			nw_diano     = nw_diano_for_bit(bitno);
			ne_diano     = ne_diano_for_bit(bitno);
			if(moving_piece=='K'){
				destsquares.whole = kmask_for_bit(bitno)& ~all_pieces.whole;
				while(destsquares.whole){
					dest_bitno=my_bsf(destsquares.whole);
					to_square=square_for_bit(dest_bitno);
					push_move(mvl,'K',found_square,to_square,' ');
					destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
				}
			}
			if(moving_piece=='N'){
				destsquares.whole = nmask_for_bit(bitno)& ~all_pieces.whole;
				while(destsquares.whole){
					dest_bitno=my_bsf(destsquares.whole);
					to_square=square_for_bit(dest_bitno);
					push_move(mvl,'N',found_square,to_square,' ');
					destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
				}
			}
			if((moving_piece=='R')||(moving_piece=='Q')){
				occupancy = all_pieces.rows[rank];
				squares_on_rank = rsquares[file][occupancy] & ~all_pieces.rows[rank];
				while(squares_on_rank){
					dest_bitno=my_bsf(squares_on_rank);
					to_square=square_for_bit((rank<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_rank &= ~(0x1<<dest_bitno);
				}
				occupancy = all_pieces_r.rows[7-file];
				squares_on_file = rsquares[rank][occupancy] & ~all_pieces_r.rows[7-file];
				while(squares_on_file){
					dest_bitno=my_bsf(squares_on_file);
					to_square=r_square_for_bit(((7-file)<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_file &= ~(0x1<<dest_bitno);
				}
			}
			if((moving_piece=='B')||(moving_piece=='Q')){
				occupancy = all_pieces_nw.rows[nw_diano];
				squares_on_nw =
					rsquares[file][occupancy] & nw_diamask & ~all_pieces_nw.rows[nw_diano];
				while(squares_on_nw){
					dest_bitno=my_bsf(squares_on_nw);
					to_square=nw_square_for_bit((nw_diano<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_nw &= ~(0x1<<dest_bitno);
				}
				occupancy = all_pieces_ne.rows[ne_diano];
				squares_on_ne =
					rsquares[file][occupancy] & ne_diamask & ~all_pieces_ne.rows[ne_diano];
				while(squares_on_ne){
					dest_bitno=my_bsf(squares_on_ne);
					to_square=ne_square_for_bit((ne_diano<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_ne &= ~(0x1<<dest_bitno);
				}
			}
			all_own_pieces_except_pawns.whole &= ~(BITBOARD_UNIT<<bitno);
		}
	} else {
		/* Generates castling if possible */
		if((brd->castling_flags&0x4)&&
		(brd->k.rows[7]&0x08)&&
		(brd->r.rows[7]&0x01)&&
		((all_pieces.rows[7]&0x0f)==0x09)&&
		(is_threat(brd,'w',073)==FALSE)&&
		(is_threat(brd,'w',072)==FALSE)&&
		(is_threat(brd,'w',071)==FALSE)){
			push_move(mvl,'k',"e8","g8",' '); /* Short castling */
		}

		if((brd->castling_flags&0x8)&&
		(brd->k.rows[7]&0x08)&&
		(brd->r.rows[7]&0x80)&&
		((all_pieces.rows[7]&0xf8)==0x88)&&
		(is_threat(brd,'w',073)==FALSE)&&
		(is_threat(brd,'w',074)==FALSE)&&
		(is_threat(brd,'w',075)==FALSE)){
			push_move(mvl,'k',"e8","c8",' '); /* Long castling */
		}

		all_own_pawns_r.whole=brd->pr.whole;
		pawns_single_move_board.whole =
			((all_own_pawns_r.whole & 0x7c7c7c7c7c7c7c7c)>>1) & ~all_pieces_r.whole;
		pdests.whole=pawns_single_move_board.whole;
		while(pdests.whole){
			bitno=my_bsf(pdests.whole);
			to_square=r_square_for_bit(bitno);
			from_square[0]=to_square[0];
			from_square[1]=to_square[1]+1;
			from_square[2]=0;
			push_move(mvl,'p',from_square,to_square,' ');
			pdests.whole &= ~(BITBOARD_UNIT<<bitno);
		}
		pawns_double_move_board.whole =
			((pawns_single_move_board.whole & 0x2020202020202020)>>1) & ~all_pieces_r.whole;
		pdests.whole=pawns_double_move_board.whole;
		while(pdests.whole){
			bitno=my_bsf(pdests.whole);
			to_square=r_square_for_bit(bitno);
			from_square[0]=to_square[0];
			from_square[1]=to_square[1]+2;
			from_square[2]=0;
			push_move(mvl,'p',from_square,to_square,' ');
			pdests.whole &= ~(BITBOARD_UNIT<<bitno);
		}

		all_own_pieces_except_pawns.whole=all_black_pieces_except_pawns(brd);
		while(all_own_pieces_except_pawns.whole){
			bitno=my_bsf(all_own_pieces_except_pawns.whole);
			found_square=square_for_bit(bitno);
			moving_piece=testsquare(brd,found_square);
			rank=(bitno&0x38)>>3;
			file=bitno&0x7;
			nw_diamask   = nw_mask_for_bit(bitno);
			ne_diamask   = ne_mask_for_bit(bitno);
			nw_diano     = nw_diano_for_bit(bitno);
			ne_diano     = ne_diano_for_bit(bitno);
			if(moving_piece=='k'){
				destsquares.whole = kmask_for_bit(bitno)& ~all_pieces.whole;
				while(destsquares.whole){
					dest_bitno=my_bsf(destsquares.whole);
					to_square=square_for_bit(dest_bitno);
					push_move(mvl,'k',found_square,to_square,' ');
					destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
				}
			}
			if(moving_piece=='n'){
				destsquares.whole = nmask_for_bit(bitno)& ~all_pieces.whole;
				while(destsquares.whole){
					dest_bitno=my_bsf(destsquares.whole);
					to_square=square_for_bit(dest_bitno);
					push_move(mvl,'n',found_square,to_square,' ');
					destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
				}
			}
			if((moving_piece=='r')||(moving_piece=='q')){
				occupancy = all_pieces.rows[rank];
				squares_on_rank = rsquares[file][occupancy] & ~all_pieces.rows[rank];
				while(squares_on_rank){
					dest_bitno=my_bsf(squares_on_rank);
					to_square=square_for_bit((rank<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_rank &= ~(0x1<<dest_bitno);
				}
				occupancy = all_pieces_r.rows[7-file];
				squares_on_file = rsquares[rank][occupancy] & ~all_pieces_r.rows[7-file];
				while(squares_on_file){
					dest_bitno=my_bsf(squares_on_file);
					to_square=r_square_for_bit(((7-file)<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_file &= ~(0x1<<dest_bitno);
				}
			}
			if((moving_piece=='b')||(moving_piece=='q')){
				occupancy = all_pieces_nw.rows[nw_diano];
				squares_on_nw =
					rsquares[file][occupancy] & nw_diamask & ~all_pieces_nw.rows[nw_diano];
				while(squares_on_nw){
					dest_bitno=my_bsf(squares_on_nw);
					to_square=nw_square_for_bit((nw_diano<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_nw &= ~(0x1<<dest_bitno);
				}
				occupancy = all_pieces_ne.rows[ne_diano];
				squares_on_ne =
					rsquares[file][occupancy] & ne_diamask & ~all_pieces_ne.rows[ne_diano];
				while(squares_on_ne){
					dest_bitno=my_bsf(squares_on_ne);
					to_square=ne_square_for_bit((ne_diano<<3)|dest_bitno);
					push_move(mvl,moving_piece,found_square,to_square,' ');
					squares_on_ne &= ~(0x1<<dest_bitno);
				}
			}
			all_own_pieces_except_pawns.whole &= ~(BITBOARD_UNIT<<bitno);
		}
	}
}

void generate_moves(Board *brd, Movelist *mvl){
	mvl->size=0;
	generate_promotions(brd,mvl);
	generate_captures(brd,mvl);
	generate_quiet_moves(brd,mvl);
}

void generate_nonquiescent_moves(Board *brd, Movelist *mvl){
	mvl->size=0;
	generate_promotions(brd,mvl);
	generate_captures(brd,mvl);
}

void generate_check_evasions(Board *brd, Movelist *mvl){
	Bitboard all_pieces,white_pieces,black_pieces,destsquares;
	Movelist threateners_list;
	int i,king_bitno,dest_bitno,threateners_bit,intermediate_bit,gapsize=0,
		threateners_direction_x,threateners_direction_y,sgn_x,sgn_y;
	const char *king_square,*to_square;
	char threatener,possible_opponent,threateners_square[3],intermediate_square[3];

	mvl->size=0;
	threateners_list.size=0;
	if(brd->whosmove=='w'){
		all_pieces.whole=totally_all_pieces(brd);
		white_pieces.whole=all_white_pieces(brd);
		king_bitno=my_bsf(brd->K.whole);
		king_square=square_for_bit(king_bitno);
		threats_to(brd,&threateners_list,'b',king_bitno,TRUE);
		if((threateners_list.size==1)||
			(threateners_list.size==4)){
			/* Only one threatener, 4 for promotions */
			threateners_square[0]=threateners_list.moves[0].move[0];
			threateners_square[1]=threateners_list.moves[0].move[1];
			threateners_square[2]=0;
			threateners_bit=bit_for_square(threateners_square);
			threatener=testsquare(brd,threateners_square);
			threats_to(brd,mvl,'w',threateners_bit,TRUE);
			if((threatener=='p')&&(brd->ep.whole)) {
				pthreats_to(brd,mvl,'w',my_bsf(brd->ep.whole),TRUE);
			}

			if((threatener=='q')||(threatener=='r')||(threatener=='b')){
				threateners_direction_x=threateners_square[0]-king_square[0];
				threateners_direction_y=threateners_square[1]-king_square[1];
				if(threateners_direction_x!=0) {
					sgn_x=abs(threateners_direction_x)/threateners_direction_x;
					gapsize=abs(threateners_direction_x);
				} else {
					sgn_x=0;
				}
				if(threateners_direction_y!=0) {
					sgn_y=abs(threateners_direction_y)/threateners_direction_y;
					gapsize=abs(threateners_direction_y);
				} else {
					sgn_y=0;
				}
				for(i=1;i<gapsize;i++){
					intermediate_square[0]=king_square[0]+sgn_x*i;
					intermediate_square[1]=king_square[1]+sgn_y*i;
					intermediate_square[2]=0;
					intermediate_bit=bit_for_square(intermediate_square);
					threats_to(brd,mvl,'w',intermediate_bit,FALSE);
				}
			}

			destsquares.whole = kmask_for_bit(king_bitno)& ~white_pieces.whole;
			while(destsquares.whole){
				dest_bitno=my_bsf(destsquares.whole);
				to_square=square_for_bit(dest_bitno);
				possible_opponent=testsquare(brd,to_square);
				if(strchr("qbnrp",possible_opponent)){
					push_move(mvl,'K',king_square,to_square,possible_opponent);
				} else {
					push_move(mvl,'K',king_square,to_square,' ');
				}
				destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
			}

		} else {
			/* Two threateners. Only king moves are possible */
			destsquares.whole = kmask_for_bit(king_bitno)& ~white_pieces.whole;
			while(destsquares.whole){
				dest_bitno=my_bsf(destsquares.whole);
				to_square=square_for_bit(dest_bitno);
				possible_opponent=testsquare(brd,to_square);
				if(strchr("qbnrp",possible_opponent)){
					push_move(mvl,'K',king_square,to_square,possible_opponent);
				} else {
					push_move(mvl,'K',king_square,to_square,' ');
				}
				destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
			}
		}
	} else {
		all_pieces.whole=totally_all_pieces(brd);
		black_pieces.whole=all_black_pieces(brd);
		king_bitno=my_bsf(brd->k.whole);
		king_square=square_for_bit(king_bitno);
		threats_to(brd,&threateners_list,'w',king_bitno,TRUE);
		if((threateners_list.size==1)||
			(threateners_list.size==4)){
			/* Only one threatener, 4 for promotions */
			threateners_square[0]=threateners_list.moves[0].move[0];
			threateners_square[1]=threateners_list.moves[0].move[1];
			threateners_square[2]=0;
			threateners_bit=bit_for_square(threateners_square);
			threatener=testsquare(brd,threateners_square);
			threats_to(brd,mvl,'b',threateners_bit,TRUE);
			if((threatener=='P')&&(brd->ep.whole)) {
				pthreats_to(brd,mvl,'b',my_bsf(brd->ep.whole),TRUE);
			}

			if((threatener=='Q')||(threatener=='R')||(threatener=='B')){
				threateners_direction_x=threateners_square[0]-king_square[0];
				threateners_direction_y=threateners_square[1]-king_square[1];
				if(threateners_direction_x!=0) {
					sgn_x=abs(threateners_direction_x)/threateners_direction_x;
					gapsize=abs(threateners_direction_x);
				} else {
					sgn_x=0;
				}
				if(threateners_direction_y!=0) {
					sgn_y=abs(threateners_direction_y)/threateners_direction_y;
					gapsize=abs(threateners_direction_y);
				} else {
					sgn_y=0;
				}
				for(i=1;i<gapsize;i++){
					intermediate_square[0]=king_square[0]+sgn_x*i;
					intermediate_square[1]=king_square[1]+sgn_y*i;
					intermediate_square[2]=0;
					intermediate_bit=bit_for_square(intermediate_square);
					threats_to(brd,mvl,'b',intermediate_bit,FALSE);
				}
			}

			destsquares.whole = kmask_for_bit(king_bitno)& ~black_pieces.whole;
			while(destsquares.whole){
				dest_bitno=my_bsf(destsquares.whole);
				to_square=square_for_bit(dest_bitno);
				possible_opponent=testsquare(brd,to_square);
				if(strchr("QBNRP",possible_opponent)){
					push_move(mvl,'k',king_square,to_square,possible_opponent);
				} else {
					push_move(mvl,'k',king_square,to_square,' ');
				}
				destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
			}

		} else {
			/* Two threateners. Only king moves are possible */
			destsquares.whole = kmask_for_bit(king_bitno)& ~black_pieces.whole;
			while(destsquares.whole){
				dest_bitno=my_bsf(destsquares.whole);
				to_square=square_for_bit(dest_bitno);
				possible_opponent=testsquare(brd,to_square);
				if(strchr("QBNRP",possible_opponent)){
					push_move(mvl,'k',king_square,to_square,possible_opponent);
				} else {
					push_move(mvl,'k',king_square,to_square,' ');
				}
				destsquares.whole &= ~(BITBOARD_UNIT<<dest_bitno);
			}
		}
	}
}

void movelistcpy(Movelist *old, Movelist *new){
	int i;
	new->size=old->size;
	for(i=0;i<old->size;i++){
		old->moves[i].moving_piece=new->moves[i].moving_piece;
		strncpy(old->moves[i].move,new->moves[i].move,6);
		old->moves[i].captured_piece=new->moves[i].captured_piece;
	}
}

void construct_legal_movelist(Board *brd, Movelist *pseudo_legal, Movelist *legal){
	Board test_board;
	int i;
	legal->size=0;
	for(i=0;i<pseudo_legal->size;i++){
		boardcpy(brd,&test_board);
		make_move(&test_board,&(pseudo_legal->moves[i]));
		if(!is_illegal(&test_board)){
			legal->moves[legal->size].moving_piece =
				pseudo_legal->moves[i].moving_piece;
			strncpy(legal->moves[legal->size].move,
				pseudo_legal->moves[i].move,6);
			legal->moves[legal->size].captured_piece =
				pseudo_legal->moves[i].captured_piece;
			legal->size++;
		}
	}
}

void init_notebook(Notebook *ntb){
	ntb->current_position=0;
	ntb->last_position=0;
}

void write_position(Board *brd, Notebook *ntb){
	char FEN_string[128];
	export_fen(brd,FEN_string);
	strncpy(ntb->positions[ntb->current_position].fen,FEN_string,120);
	ntb->positions[ntb->current_position].z.whole=brd->key.whole;
	ntb->positions[ntb->current_position].move_made[0]=0;
}

void write_move(Notebook *ntb, char *move){
	strncpy(ntb->positions[ntb->current_position].move_made, move, 6);
	ntb->current_position++;
	ntb->last_position=ntb->current_position;
}

void get_current_position(Board *brd, Notebook *ntb){
	import_fen(brd,ntb->positions[ntb->current_position].fen);
}

void reverse(Board *brd, Notebook *ntb, int moves){
	ntb->current_position-=moves;
	if(ntb->current_position<0){
		ntb->current_position=0;
	}
	get_current_position(brd,ntb);
}

void forward(Board *brd, Notebook *ntb, int moves){
	ntb->current_position+=moves;
	if(ntb->current_position>ntb->last_position){
		ntb->current_position=ntb->last_position;
	}
	get_current_position(brd,ntb);
}

void print_notebook_contents(Notebook *ntb){
	int i;
	for(i=0;i<ntb->last_position;i++){
		printf("%s\n%8lx : %8lx\n%5s",
		ntb->positions[i].fen,
		ntb->positions[i].z.halves[0],
		ntb->positions[i].z.halves[1],
		ntb->positions[i].move_made);
		if(i==ntb->current_position){
			printf(" <-\n");
		} else {
			printf("\n");
		}
	}
}

int is_check(Board *brd){
	int king_bitno;
	king_bitno=(brd->whosmove=='w') ? my_bsf(brd->K.whole) : my_bsf(brd->k.whole);
	return is_threat(brd,OTHERCOLOR(brd->whosmove),king_bitno);
}

int is_illegal(Board *brd){
	int king_bitno;
	king_bitno=(brd->whosmove=='w') ? my_bsf(brd->k.whole) : my_bsf(brd->K.whole);
	return is_threat(brd,brd->whosmove,king_bitno);
}

int is_mate(Board *brd, Movelist *mvl){
	if((mvl->size==0)&&(is_check(brd)))
		return TRUE;
	return FALSE;
}

int is_threefold_repetition(Notebook *ntb, Zobtrace *zt, int half_moves){
	Zobrist current_key;
	int i,occurrences,half_moves_left;
	if(half_moves<8)
		return FALSE; /* Can't be a threefold repetition */
	half_moves_left=half_moves;
	occurrences=0;
	if(zt!=NULL){
		/* Check the zobrist key trace first */
		current_key.whole=zt->zkeys[zt->size-1].whole;
		i=zt->size-2;
		while((i>=0)&&(half_moves_left>=0)){
			if(zkequals(current_key,zt->zkeys[i])){
				occurrences++;
				if(occurrences>=2){
					return TRUE; /* Threefold repetition */
				}
	     		}
			i--;half_moves_left--;
		}

		/* Then the notebook */
		i=ntb->current_position-1;
		while((i>=0)&&(half_moves_left>=0)){
			if(zkequals(current_key,ntb->positions[i].z)){
				occurrences++;
				if(occurrences>=2){
					return TRUE; /* Threefold repetition */
				}
			}
			i--;half_moves_left--;
		}
	} else {
		/* Only the notebook */
		current_key.whole=ntb->positions[ntb->current_position].z.whole;
		i=ntb->current_position-1;
		while((i>=0)&&(half_moves_left>=0)){
			if(zkequals(current_key,ntb->positions[i].z)){
				occurrences++;
				if(occurrences>=2){
					return TRUE; /* Threefold repetition */
				}
			}
			i--;half_moves_left--;
		}
	}
  	return FALSE; /* No threefold repetition found */
}

int compare_move_values(const void *first_move, const void *second_move){
	Move_node *fmove,*smove;
	fmove=(Move_node *)first_move;
	smove=(Move_node *)second_move;
	if(fmove->approx_move_value<smove->approx_move_value)
		return 1;
	if(fmove->approx_move_value>smove->approx_move_value)
		return -1;
	return 0;
}
