예제 #1
0
int main(int argc, char **argv)
{
	my_srand(12345);
	unsigned iterations = 5000000;
	if (argc > 1)
		iterations = atoi(argv[1]);

	printf("Initialize...\n");
	init();
	size_t d;
	for (d = 0; d < sizeof(data)/sizeof(data[0]); ++d) {
		unsigned long long datum = 0;
		switch (my_rand() % 4) {
		case 3:  datum |= ((unsigned long long)my_rand() & 0xff) << 24;
		case 2:  datum |= ((unsigned long long)my_rand() & 0xff) << 16;
		case 1:  datum |= ((unsigned long long)my_rand() & 0xff) << 8;
		default: datum |= ((unsigned long long)my_rand() & 0xff);
		}
		data[d] = datum;
	}
	printf("ok, runing %u iterations\n", iterations);
	unsigned final_checksum = 0;
	unsigned i;
	for (i = 0; i < iterations; ++i) {
		unsigned checksum = 0;
		for (d = 0; d < sizeof(data)/sizeof(data[0]); ++d) {
			checksum += FirstOne(data[d]);
		}
		final_checksum = checksum;
	}
	printf("checksum %u\n", final_checksum);
	return 0;
}
예제 #2
0
int getPassedPawnScore(ChessBoard * board, bool white) {
	BITBOARD pawns = (white) ? board->whitePawns : board->blackPawns;
	BITBOARD originalPawns = pawns;
	BITBOARD otherPawns = (white) ? board->blackPawns : board->whitePawns;
	BITBOARD* doubledPawnMask = (white) ? whiteDoubledPawnMask : blackDoubledPawnMask;
	BITBOARD* passedPawnMask = (white) ? whitePassedPawnMask : blackPassedPawnMask;
	int* passedPawnRankScale = (white) ? EvalParameters::whitePassedPawnRankScale : EvalParameters::blackPassedPawnRankScale;

	int passedPawnScore = 0;

	while (pawns != 0) {
		short pawnOffset = FirstOne(pawns);
		pawns ^= offset_to_mask(pawnOffset);

		if ((passedPawnMask[pawnOffset] & otherPawns) == 0) {
			// pawn is passed.  give bonus

		        // check if pawn is doubled
                        BITBOARD isDoubled = doubledPawnMask[pawnOffset] & originalPawns;

			if (isDoubled == 0) {
			  if (board->gamePhase == PHASE_ENDGAME) {
			    passedPawnScore += EvalParameters::passedPawnBonus * passedPawnRankScale[8 - Rank(pawnOffset)];
			  }
			  else {
			    passedPawnScore += (1/4.0) * EvalParameters::passedPawnBonus * passedPawnRankScale[8 - Rank(pawnOffset)];
			  }
			}

			// no passed pawn bonus if pawn is doubled
		}
	}

	return passedPawnScore;
}
예제 #3
0
int getCenterControlScore(ChessBoard * board, bool white) {
	int whiteCenterScore = 0;
	int blackCenterScore = 0;

	BITBOARD iterateCenterSquares = centerSquares;
	while(iterateCenterSquares != 0) {
		short centerSquare = FirstOne(iterateCenterSquares);
		iterateCenterSquares ^= offset_to_mask(centerSquare);
		BITBOARD attackBitboard = get_attacksto_bitboard(board, centerSquare);
		short whiteAttacks = NumOnes(attackBitboard & board->whitePieces);
		short blackAttacks = NumOnes(attackBitboard & board->blackPieces);
		short contents = board->boardContents[centerSquare];
		if (contents != EMPTY) {
			if (IsPieceWhite(contents))
				whiteAttacks += 2;
			else
				blackAttacks += 2;
		}
		whiteCenterScore += whiteAttacks * EvalParameters::whiteCenterControlScale[centerSquare];
		blackCenterScore += blackAttacks * EvalParameters::blackCenterControlScale[centerSquare];
	}

	if (white)
		return whiteCenterScore - blackCenterScore;
	else
		return blackCenterScore - whiteCenterScore;
}
예제 #4
0
BITBOARD ValidateComputeRookAttacks(int square)
{
  BITBOARD attacks, temp_attacks;
  BITBOARD temp1, temp8;
  attacks=rook_attacks[square];
  temp_attacks=And(attacks,Compl(Occupied));
  temp_attacks=Compl(Or(temp_attacks,Compl(rook_attacks[square])));
  temp1=And(temp_attacks,plus1dir[square]);
  temp8=And(temp_attacks,plus8dir[square]);
  attacks=Xor(attacks,plus1dir[FirstOne(temp1)]);
  attacks=Xor(attacks,plus8dir[FirstOne(temp8)]);
  temp1=And(temp_attacks,minus1dir[square]);
  temp8=And(temp_attacks,minus8dir[square]);
  attacks=Xor(attacks,minus1dir[LastOne(temp1)]);
  attacks=Xor(attacks,minus8dir[LastOne(temp8)]);
  return(attacks);
}
예제 #5
0
BITBOARD ValidateComputeBishopAttacks(int square)
{
  BITBOARD attacks, temp_attacks;
  BITBOARD temp7, temp9;
  attacks=bishop_attacks[square];
  temp_attacks=And(attacks,Compl(Occupied));
  temp_attacks=Compl(Or(temp_attacks,Compl(bishop_attacks[square])));
  temp7=And(temp_attacks,plus7dir[square]);
  temp9=And(temp_attacks,plus9dir[square]);
  attacks=Xor(attacks,plus7dir[FirstOne(temp7)]);
  attacks=Xor(attacks,plus9dir[FirstOne(temp9)]);
  temp7=And(temp_attacks,minus7dir[square]);
  temp9=And(temp_attacks,minus9dir[square]);
  attacks=Xor(attacks,minus7dir[LastOne(temp7)]);
  attacks=Xor(attacks,minus9dir[LastOne(temp9)]);
  return(attacks);
}
예제 #6
0
파일: rtbgen.c 프로젝트: RyanTaker/tb
// check whether all moves end up in wins for the opponent
// if we are here, all captures are losing
static int check_loss(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p)
{
  int sq;
  long64 idx, idx2;
  bitboard bb;
  int best = LOSS_IN_ONE;

  int k = *pcs++;
  if (k == 0) { // white king
    bb = WhiteKingMoves;
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove0(idx0, sq);
      int v = win_loss[table[idx2]];
      if (!v) return 0;
      if (v < best) best = v;
      ClearFirst(bb);
    }
  } else { // otherwise k == 1, i.e. black king
    bb = BlackKingMoves;
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove1(idx0, sq);
      int v = win_loss[table[idx2]];
      if (!v) return 0;
      if (v < best) best = v;
      ClearFirst(bb);
    }
  }
  while ((k = *pcs++) >= 0) {
    bb = PieceMoves(p[k], pt[k], occ);
    idx = idx0 & ~mask[k];
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove2(idx, k, sq);
      int v = win_loss[table[idx2]];
      if (!v) return 0;
      if (v < best) best = v;
      ClearFirst(bb);
    }
  }

  return best;
}
예제 #7
0
파일: rtbgen.c 프로젝트: RyanTaker/tb
static int check_mate(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p)
{
  int sq;
  long64 idx, idx2;
  bitboard bb;

  int k = *pcs++;
  if (k == 0) { // white king
    bb = WhiteKingMoves;
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove0(idx0, sq);
      if (table[idx2] != ILLEGAL) return 0;
      ClearFirst(bb);
    }
  } else { // otherwise k == 1, i.e. black king
    bb = BlackKingMoves;
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove1(idx0, sq);
      if (table[idx2] != ILLEGAL) return 0;
      ClearFirst(bb);
    }
  }
  while ((k = *pcs++) >= 0) {
    bb = PieceMoves(p[k], pt[k], occ);
    idx = idx0 & ~mask[k];
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove2(idx, k, sq);
      if (table[idx2] != ILLEGAL) return 0;
      ClearFirst(bb);
    }
  }

  return 1;
}
예제 #8
0
int getDoubledPawnPenalty(ChessBoard* board, bool white) {
  BITBOARD pawns = (white) ? board->whitePawns :  board->blackPawns;
  BITBOARD originalPawns = pawns;
  BITBOARD* doubledPawnMask = (white) ? whiteDoubledPawnMask : blackDoubledPawnMask;

  int doubledPawnPenalty = 0;

  while(pawns != 0) {
    short pawnOffset = FirstOne(pawns);
    pawns ^= offset_to_mask(pawnOffset);
    
    BITBOARD maskResult = doubledPawnMask[pawnOffset] & originalPawns;

    if (maskResult != 0) {
      doubledPawnPenalty += EvalParameters::doubledPawnPenalty * NumOnes(maskResult);
    }
  }

  return doubledPawnPenalty;
}
예제 #9
0
// captures should be taken care of already
int check_mate_pieces(int *pcs, long64 idx0, ubyte *table, bitboard occ, int *p)
{
  int sq;
  long64 idx, idx2;
  bitboard bb;

  do {
    int k = *pcs;
    bb = PieceMoves(p[k], pt[k], occ);
    idx = idx0 & ~mask[k];
    while (bb) {
      sq = FirstOne(bb);
      idx2 = MakeMove(idx, k, sq);
      if (table[idx2] < WDL_ILLEGAL) return 0;
      ClearFirst(bb);
    }
  } while (*(++pcs) >= 0);

  return 1;
}
예제 #10
0
파일: sprobe.c 프로젝트: syzygy1/tb
static int probe_tb2(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta)
{
  int i, j;
  bitboard player_att[5];
  bitboard opp_att[5];

  // first try captures
  if (opp->num > 1) {
    int capts = 0;
    for (i = 0; i < player->num; i++) {
      int from = player->pos[i];
      bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ);
      player_att[i] = bb;
      bb &= opp_occ;
      if (bb) {
	capts = 1;
	opp->num--;
	bitboard occ2 = player_occ ^ bit[from];
	do {
	  int to = FirstOne(bb);
	  player->pos[i] = to;
	  for (j = 0; opp->pos[j] != to; j++);
	  int tmp_type = opp->type[j];
	  opp->type[j] = opp->type[opp->num];
	  opp->pos[j] = opp->pos[opp->num];
#ifdef HAS_PAWNS
	  if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) {
	    int t = player->type[i];
	    int m;
	    for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
	      player->type[i] = t + m;
	      int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
	      if (v > alpha) {
		alpha = v;
		if (alpha >= beta) break;
	      }
	    }
	    player->type[i] = t;
	  } else {
#endif
	    int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
	    if (v > alpha)
	      alpha = v;
#ifdef HAS_PAWNS
	  }
#endif
	  opp->type[j] = tmp_type;
	  opp->pos[j] = to;
	  if (alpha >= beta) {
	    player->pos[i] = from;
	    opp->num++;
	    return alpha;
	  }
	  ClearFirst(bb);
	} while (bb);
	player->pos[i] = from;
	opp->num++;
      }
    }
    if (capts) return alpha;
  } else {
    for (i = 0; i < player->num; i++) {
      bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ);
      player_att[i] = bb;
      if (bb & opp_occ)
	return -2;
    }
  }

#if 1
  if (player->num + opp->num < 6)
    goto skip_threats;
#endif

  // now try threats. there are two cases
  bitboard atts = 0ULL;
  for (i = 0; i < opp->num; i++) {
    opp_att[i] = PieceRange(opp->pos[i], opp->type[i], player_occ | opp_occ);
    atts |= opp_att[i];
  }
  // first case: opponent currently is not attacking any pieces
  // we only need to consider moves moving into opponent attacks
  if (!(atts & player_occ)) {
    if (player->num > 1) {
      player->num--;
      for (i = 0; i <= player->num; i++) {
#ifdef HAS_PAWNS
	if ((player->type[i] & 0x07) == 1) continue;
#endif
	bitboard bb = player_att[i] & atts;
	if (!bb) continue;
	int pos = player->pos[i];
	int type = player->type[i];
	player->pos[i] = player->pos[player->num];
	player->type[i] = player->type[player->num];
	do {
	  int sq = FirstOne(bb);
	  int beta2 = beta;
	  for (j = 0; j < opp->num; j++) {
	    if (!(bit[sq] & opp_att[j])) continue;
	    int tmp_pos = opp->pos[j];
	    opp->pos[j] = sq;
#ifdef HAS_PAWNS
	    if ((opp->type[j] & 0x07) == PAWN && ((sq + 0x08) & 0x30) == 0) {
	      int t = opp->type[j];
	      int m;
	      for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
		opp->type[j] = t + m;
		int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2);
		if (v < beta2) {
		  beta2 = v;
		  if (beta2 <= alpha)
		    break;
		}
	      }
	      opp->type[j] = t;
	    } else {
#endif
	      int v = probe_tb2(player, opp, player_occ ^ bit[pos], opp_occ ^ bit[sq] ^ bit[tmp_pos], alpha, beta2);
	      if (v < beta2)
		beta2 = v;
#ifdef HAS_PAWNS
	    }
#endif
	    opp->pos[j] = tmp_pos;
	    if (beta2 <= alpha) break;
	  }
	  if (beta2 > alpha) {
	    if (beta2 >= beta) {
	      player->pos[i] = pos;
	      player->type[i] = type;
	      player->num++;
	      return beta2;
	    }
	    alpha = beta2;
	  }
	  ClearFirst(bb);
	} while (bb);
	player->pos[i] = pos;
	player->type[i] = type;
      }
      player->num++;
    } else {
      for (i = 0; i < player->num; i++) {
#ifdef HAS_PAWNS
	if ((player->type[i] & 0x07) == 1) continue;
#endif
	if (player_att[i] & atts) return 2;
      }
    }
  } else { // second case: just try all moves
    for (i = 0; i < player->num; i++) {
#ifdef HAS_PAWNS
      if ((player->type[i] & 0x07) == 1) continue;
#endif
      bitboard bb = player_att[i] & ~player_occ;
      if (bb) {
	int from = player->pos[i];
	do {
	  int capts;
	  int to = FirstOne(bb);
	  player->pos[i] = to;
	  int v = -probe_tb_capts(opp, player, opp_occ, player_occ ^ bit[from] ^ bit[to], -beta, -alpha, &capts);
	  if (capts && v > alpha) {
	    if (v >= beta) {
	      player->pos[i] = from;
	      return v;
	    }
	    alpha = v;
	  }
	  ClearFirst(bb);
	} while (bb);
	player->pos[i] = from;
      }
    }
  }

  int pieces[6];
  int pos[6];
skip_threats:
  for (i = 0; i < player->num; i++) {
    pieces[i] = player->type[i];
    pos[i] = player->pos[i];
  }
  for (j = 0; j < opp->num; j++, i++) {
    pieces[i] = opp->type[j];
    pos[i] = opp->pos[j];
  }
  for (; i < numpcs; i++)
    pieces[i] = 0;
  int v = probe_table(pieces, pos, pieces[0] < 8);
  return alpha > v ? alpha : v;
}
예제 #11
0
void ValidatePosition(int ply, int move, char *caller)
{
  BITBOARD temp, temp1, temp_occ, temp_occ_rl90, temp_occ_rl45;
  BITBOARD temp_occ_rr45, temp_occx, cattacks, rattacks;
  int i,square,error;
  int temp_score;
/*
  first, test w_occupied and b_occupied
*/
  error=0;
  temp_occ=Or(Or(Or(Or(Or(WhitePawns,WhiteKnights),WhiteBishops),
                    WhiteRooks),WhiteQueens),WhiteKing);
  if(Xor(WhitePieces,temp_occ)) {
    Print(1,"ERROR white occupied squares is bad!\n");
    Display2BitBoards(temp_occ,WhitePieces);
    error=1;
  }
  temp_occ=Or(Or(Or(Or(Or(BlackPawns,BlackKnights),BlackBishops),
                    BlackRooks),BlackQueens),BlackKing);
  if(Xor(BlackPieces,temp_occ)) {
    Print(1,"ERROR black occupied squares is bad!\n");
    Display2BitBoards(temp_occ,BlackPieces);
    error=1;
  }
/*
  now test rotated occupied bitboards.
*/
  temp_occ_rl90=0;
  temp_occ_rl45=0;
  temp_occ_rr45=0;
  for (i=0;i<64;i++) {
    if (PieceOnSquare(i)) {
      temp_occ_rl90=Or(temp_occ_rl90,set_mask_rl90[i]);
      temp_occ_rl45=Or(temp_occ_rl45,set_mask_rl45[i]);
      temp_occ_rr45=Or(temp_occ_rr45,set_mask_rr45[i]);
    }
  }
  if(Xor(OccupiedRL90,temp_occ_rl90)) {
    Print(1,"ERROR occupied squares (rotated left 90) is bad!\n");
    Display2BitBoards(temp_occ_rl90,OccupiedRL90);
    error=1;
  }
  if(Xor(OccupiedRL45,temp_occ_rl45)) {
    Print(1,"ERROR occupied squares (rotated left 45) is bad!\n");
    Display2BitBoards(temp_occ_rl45,OccupiedRL45);
    error=1;
  }
  if(Xor(OccupiedRR45,temp_occ_rr45)) {
    Print(1,"ERROR occupied squares (rotated right 45) is bad!\n");
    Display2BitBoards(temp_occ_rr45,OccupiedRR45);
    error=1;
  }
/*
  now test bishops_queens and rooks_queens
*/
  temp_occ=Or(Or(Or(WhiteBishops,WhiteQueens),BlackBishops),
              BlackQueens);
  if(Xor(BishopsQueens,temp_occ)) {
    Print(1,"ERROR bishops_queens is bad!\n");
    Display2BitBoards(temp_occ,BishopsQueens);
    error=1;
  }
    temp_occ=Or(Or(Or(WhiteRooks,WhiteQueens),BlackRooks),
                BlackQueens);
  if(Xor(RooksQueens,temp_occ)) {
    Print(1,"ERROR rooks_queens is bad!\n");
    Display2BitBoards(temp_occ,RooksQueens);
    error=1;
  }
/*
  check individual piece bit-boards to make sure two pieces
  don't occupy the same square (bit)
*/
    temp_occ=Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(Xor(
       WhitePawns,WhiteKnights),WhiteBishops),WhiteRooks),
       WhiteQueens),BlackPawns),BlackKnights),BlackBishops),
       BlackRooks),BlackQueens),WhiteKing),BlackKing);
    temp_occx=Or(Or(Or(Or(Or(Or(Or(Or(Or(Or(Or(
       WhitePawns,WhiteKnights),WhiteBishops),WhiteRooks),
       WhiteQueens),BlackPawns),BlackKnights),BlackBishops),
       BlackRooks),BlackQueens),WhiteKing),BlackKing);
    if(Xor(temp_occ,temp_occx)) {
      Print(1,"ERROR two pieces on same square\n");
      error=1;
    }
/*
  test material_evaluation
*/
  temp_score=PopCnt(WhitePawns)*PAWN_VALUE;
  temp_score-=PopCnt(BlackPawns)*PAWN_VALUE;
  temp_score+=PopCnt(WhiteKnights)*KNIGHT_VALUE;
  temp_score-=PopCnt(BlackKnights)*KNIGHT_VALUE;
  temp_score+=PopCnt(WhiteBishops)*BISHOP_VALUE;
  temp_score-=PopCnt(BlackBishops)*BISHOP_VALUE;
  temp_score+=PopCnt(WhiteRooks)*ROOK_VALUE;
  temp_score-=PopCnt(BlackRooks)*ROOK_VALUE;
  temp_score+=PopCnt(WhiteQueens)*QUEEN_VALUE;
  temp_score-=PopCnt(BlackQueens)*QUEEN_VALUE;
  if(temp_score != Material) {
    Print(1,"ERROR  material_evaluation is wrong, good=%d, bad=%d\n",
           temp_score,Material);
    error=1;
  }
  temp_score=PopCnt(WhiteKnights)*knight_v;
  temp_score+=PopCnt(WhiteBishops)*bishop_v;
  temp_score+=PopCnt(WhiteRooks)*rook_v;
  temp_score+=PopCnt(WhiteQueens)*queen_v;
  if(temp_score != TotalWhitePieces) {
    Print(1,"ERROR  white_pieces is wrong, good=%d, bad=%d\n",
           temp_score,TotalWhitePieces);
    error=1;
  }
  temp_score=PopCnt(WhitePawns);
  if(temp_score != TotalWhitePawns) {
    Print(1,"ERROR  white_pawns is wrong, good=%d, bad=%d\n",
           temp_score,TotalWhitePawns);
    error=1;
  }
  temp_score=PopCnt(BlackKnights)*knight_v;
  temp_score+=PopCnt(BlackBishops)*bishop_v;
  temp_score+=PopCnt(BlackRooks)*rook_v;
  temp_score+=PopCnt(BlackQueens)*queen_v;
  if(temp_score != TotalBlackPieces) {
    Print(1,"ERROR  black_pieces is wrong, good=%d, bad=%d\n",
           temp_score,TotalBlackPieces);
    error=1;
  }
  temp_score=PopCnt(BlackPawns);
  if(temp_score != TotalBlackPawns) {
    Print(1,"ERROR  black_pawns is wrong, good=%d, bad=%d\n",
           temp_score,TotalBlackPawns);
    error=1;
  }
/*
  now test the board[...] to make sure piece values are correct.
*/
/*
   test pawn locations
*/
  temp=WhitePawns;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != pawn) {
      Print(1,"ERROR!  board[%d]=%d, should be 1\n",square,
            PieceOnSquare(square));
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackPawns;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -pawn) {
      Print(1,"ERROR!  board[%d]=%d, should be -1\n",square,
            PieceOnSquare(square));
      error=1;
    }
    Clear(square,temp);
  }
/*
   test knight locations
*/
  temp=WhiteKnights;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != knight) {
      Print(1,"ERROR!  board[%d]=%d, should be 2\n",square,
            PieceOnSquare(square));
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackKnights;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -knight) {
      Print(1,"ERROR!  board[%d]=%d, should be -2\n",square,
            PieceOnSquare(square));
      error=1;
    }
    Clear(square,temp);
  }
/*
   test bishop locations
*/
  temp=WhiteBishops;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != bishop) {
      Print(1,"ERROR!  board[%d]=%d, should be 3\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksBishop(square);
    cattacks=ValidateComputeBishopAttacks(square);
    if (rattacks != cattacks) {
      Print(1,"ERROR!  bishop attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackBishops;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -bishop) {
      Print(1,"ERROR!  board[%d]=%d, should be -3\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksBishop(square);
    cattacks=ValidateComputeBishopAttacks(square);
    if (rattacks != cattacks) {
      Print(1,"ERROR!  bishop attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
/*
   test rook locations
*/
  temp=WhiteRooks;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != rook) {
      Print(1,"ERROR!  board[%d]=%d, should be 4\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksRook(square);
    cattacks=ValidateComputeRookAttacks(square);
    if (rattacks != cattacks) {
      Print(1,"ERROR!  Rook attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackRooks;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -rook) {
      Print(1,"ERROR!  board[%d]=%d, should be -4\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksRook(square);
    cattacks=ValidateComputeRookAttacks(square);
    if (rattacks != cattacks) {
      Print(1,"ERROR!  Rook attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
/*
   test queen locations
*/
  temp=WhiteQueens;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != queen) {
      Print(1,"ERROR!  board[%d]=%d, should be 5\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksQueen(square);
    cattacks=Or(ValidateComputeRookAttacks(square),ValidateComputeBishopAttacks(square));
    if (rattacks != cattacks) {
      Print(1,"ERROR!  queen attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackQueens;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -queen) {
      Print(1,"ERROR!  board[%d]=%d, should be -5\n",square,
            PieceOnSquare(square));
      error=1;
    }
    rattacks=AttacksQueen(square);
    cattacks=Or(ValidateComputeRookAttacks(square),ValidateComputeBishopAttacks(square));
    if (rattacks != cattacks) {
      Print(1,"ERROR!  queen attacks wrong, square=%d\n",square);
      Display2BitBoards(rattacks,cattacks);
      error=1;
    }
    Clear(square,temp);
  }
/*
   test king locations
*/
  temp=WhiteKing;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != king) {
      Print(1,"ERROR!  board[%d]=%d, should be 6\n",square,
            PieceOnSquare(square));
      error=1;
    }
    if (WhiteKingSQ != square) {
      Print(1,"ERROR!  white_king is %d, should be %d\n",
            WhiteKingSQ,square);
      error=1;
    }
    Clear(square,temp);
  }
  temp=BlackKing;
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square) != -king) {
      Print(1,"ERROR!  board[%d]=%d, should be -6\n",square,
            PieceOnSquare(square));
      error=1;
    }
    if (BlackKingSQ != square) {
      Print(1,"ERROR!  black_king is %d, should be %d\n",
            BlackKingSQ,square);
      error=1;
    }
    Clear(square,temp);
  }
/*
   test board[i] fully now.
*/
  for (i=0;i<64;i++)
  switch (PieceOnSquare(i)) {
    case -king:
      if (!And(BlackKing,set_mask[i])) {
        Print(1,"ERROR!  b_king/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case -queen:
      if (!And(BlackQueens,set_mask[i])) {
        Print(1,"ERROR!  b_queen/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case -rook:
      if (!And(BlackRooks,set_mask[i])) {
        Print(1,"ERROR!  b_rook/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case -bishop:
      if (!And(BlackBishops,set_mask[i])) {
        Print(1,"ERROR!  b_bishop/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case -knight:
      if (!And(BlackKnights,set_mask[i])) {
        Print(1,"ERROR!  b_knight/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case -pawn:
      if (!And(BlackPawns,set_mask[i])) {
        Print(1,"ERROR!  b_pawn/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case king:
      if (!And(WhiteKing,set_mask[i])) {
        Print(1,"ERROR!  w_king/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case queen:
      if (!And(WhiteQueens,set_mask[i])) {
        Print(1,"ERROR!  w_queen/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case rook:
      if (!And(WhiteRooks,set_mask[i])) {
        Print(1,"ERROR!  w_rook/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case bishop:
      if (!And(WhiteBishops,set_mask[i])) {
        Print(1,"ERROR!  w_bishop/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case knight:
      if (!And(WhiteKnights,set_mask[i])) {
        Print(1,"ERROR!  w_knight/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
    case pawn:
      if (!And(WhitePawns,set_mask[i])) {
        Print(1,"ERROR!  w_pawn/board[%d] don't agree!\n",i);
        error=1;
      }
      break;
  }
/*
   test empty squares now
*/
  temp=Compl(Or(temp_occ,temp_occx));
  while(temp) {
    square=FirstOne(temp);
    if (PieceOnSquare(square)) {
      Print(1,"ERROR!  board[%d]=%d, should be 0\n",square,
            PieceOnSquare(square));
      error=1;
    }
    Clear(square,temp);
  }
/*
   test total piece count now
*/
  temp=PopCnt(Occupied);
  if (temp != TotalPieces) {
    Print(1,"ERROR!  TotalPieces is wrong, correct=%d  bad=%d\n",
          temp,TotalPieces);
    error=1;
  }
/*
   test hash key
*/
  temp=0;
  temp1=0;
  for (i=0;i<64;i++) {
    switch (PieceOnSquare(i)) {
      case king:
        temp=Xor(temp,w_king_random[i]);
        break;
      case queen:
        temp=Xor(temp,w_queen_random[i]);
        break;
      case rook:
        temp=Xor(temp,w_rook_random[i]);
        break;
      case bishop:
        temp=Xor(temp,w_bishop_random[i]);
        break;
      case knight:
        temp=Xor(temp,w_knight_random[i]);
        break;
      case pawn:
        temp=Xor(temp,w_pawn_random[i]);
        temp1=Xor(temp1,w_pawn_random[i]);
        break;
      case -pawn:
        temp=Xor(temp,b_pawn_random[i]);
        temp1=Xor(temp1,b_pawn_random[i]);
        break;
      case -knight:
        temp=Xor(temp,b_knight_random[i]);
        break;
      case -bishop:
        temp=Xor(temp,b_bishop_random[i]);
        break;
      case -rook:
        temp=Xor(temp,b_rook_random[i]);
        break;
      case -queen:
        temp=Xor(temp,b_queen_random[i]);
        break;
      case -king:
        temp=Xor(temp,b_king_random[i]);
        break;
      default:
        break;
    }
  }
  if (EnPassant(ply)) HashEP(EnPassant(ply),temp);
  if (!(WhiteCastle(ply)&1)) HashCastleW(0,temp);
  if (!(WhiteCastle(ply)&2)) HashCastleW(1,temp);
  if (!(BlackCastle(ply)&1)) HashCastleB(0,temp);
  if (!(BlackCastle(ply)&2)) HashCastleB(1,temp);
  if(Xor(temp,HashKey)) {
    Print(1,"ERROR!  hash_key is bad.\n");
    error=1;
  }
  if(Xor(temp1,PawnHashKey)) {
    Print(1,"ERROR!  pawn_hash_key is bad.\n");
    error=1;
  }
  if (error) {
/*
    Print(0,"active path:\n");
    for (i=1;i<=ply;i++)
      DisplayChessMove("move=",move);
*/
    Print(0,"current move:\n");
    DisplayChessMove("move=",move);
    DisplayChessBoard(stdout,search);
    Print(0,"called from %s, ply=%d\n",caller,ply);
    Print(0,"node=%d\n",nodes_searched+q_nodes_searched);
    exit(1);
  }
}
예제 #12
0
파일: IntUnion.c 프로젝트: C0deZLee/IntFlow
int main() {
  int a = FirstOne(12345678);
  return 0;
}
예제 #13
0
/*
********************************************************************************
*                                                                              *
*   Search() is the recursive routine used to implement the alpha/beta         *
*   negamax search (similar to minimax but simpler to code.)  Search() is      *
*   called whenever there is "depth" remaining so that all moves are subject   *
*   to searching, or when the side to move is in check, to make sure that this *
*   side isn't mated.  Search() recursively calls itself until depth is ex-    *
*   hausted, at which time it calls Quiesce() instead.                         *
*                                                                              *
********************************************************************************
*/
int Search(int alpha, int beta, int wtm, int depth, int ply, int do_null)
{
  register int first_move=1;
  register BITBOARD save_hash_key;
  register int initial_alpha, value;
  register int extensions;
/*
 ----------------------------------------------------------
|                                                          |
|   check to see if we have searched enough nodes that it  |
|   is time to peek at how much time has been used, or if  |
|   is time to check for operator keyboard input.  this is |
|   usually enough nodes to force a time/input check about |
|   once per second, except when the target time per move  |
|   is very small, in which case we try to check the time  |
|   at least 10 times during the search.                   |
|                                                          |
 ----------------------------------------------------------
*/
  if (ply >= MAXPLY-2) return(beta);
  nodes_searched++;
  if (--next_time_check <= 0) {
    next_time_check=nodes_between_time_checks;
    if (CheckInput()) Interrupt(ply);
    time_abort+=TimeCheck(0);
    if (time_abort) {
      abort_search=1;
      return(0);
    }
  }
/*
 ----------------------------------------------------------
|                                                          |
|   check for draw by repetition.                          |
|                                                          |
 ----------------------------------------------------------
*/
  if (RepetitionCheck(ply,wtm)) {
    value=(wtm==root_wtm) ? DrawScore() : -DrawScore();
    if (value < beta) SavePV(ply,value,0);
#if !defined(FAST)
    if(ply <= trace_level) printf("draw by repetition detected, ply=%d.\n",ply);
#endif
    return(value);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now call LookUp() to see if this position has been     |
|   searched before.  if so, we may get a real score,      |
|   produce a cutoff, or get nothing more than a good move |
|   to try first.  there are four cases to handle:         |
|                                                          |
|   1. LookUp() returned "EXACT_SCORE" if this score is    |
|   greater than beta, return beta.  otherwise, return the |
|   score.  In either case, no further searching is needed |
|   from this position.  note that lookup verified that    |
|   the table position has sufficient "draft" to meet the  |
|   requirements of the current search depth remaining.    |
|                                                          |
|   2.  LookUp() returned "LOWER_BOUND" which means that   |
|   when this position was searched previously, every move |
|   was "refuted" by one of its descendents.  as a result, |
|   when the search was completed, we returned alpha at    |
|   that point.  we simply return alpha here as well.      |
|                                                          |
|   3.  LookUp() returned "UPPER_BOUND" which means that   |
|   when we encountered this position before, we searched  |
|   one branch (probably) which promptly refuted the move  |
|   at the previous ply.                                   |
|                                                          |
|   4.  LookUp() returned "AVOID_NULL_MOVE" which means    |
|   the hashed score/bound was no good, but it indicated   |
|   that trying a null-move in this position will be a     |
|   waste of time.                                         |
|                                                          |
 ----------------------------------------------------------
*/
  switch (LookUp(ply,depth,wtm,&alpha,beta)) {
    case EXACT_SCORE:
      if(alpha >= beta) return(beta);
      else {
        SavePV(ply,alpha,1);
        return(alpha);
      }
    case LOWER_BOUND:
      return(alpha);
    case UPPER_BOUND:
      return(beta);
    case AVOID_NULL_MOVE:
      do_null=0;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now it's time to try a probe into the endgame table-   |
|   base files.  this is done if (a) the previous move was |
|   a capture or promotion, unless we are at very shallow  |
|   plies (<4) in the search; (b) there are less than 5    |
|   pieces left (currently all interesting 4 piece endings |
|   are available.)                                        |
|                                                          |
 ----------------------------------------------------------
*/
#if defined(TABLEBASES)
  if (TotalPieces < 5) do {
    register int wpawn, bpawn;
    int tb_value;
    if (TotalWhitePawns && TotalBlackPawns) {
      wpawn=FirstOne(WhitePawns);
      bpawn=FirstOne(BlackPawns);
      if (FileDistance(wpawn,bpawn) == 1) {
        if(((Rank(wpawn)==1) && (Rank(bpawn)>2)) ||
           ((Rank(bpawn)==6) && (Rank(wpawn)<5)) || 
           EnPassant(ply)) break;
      }
    }
    tb_probes++;
    if (EGTBScore(ply, wtm, &tb_value)) {
      tb_probes_successful++;
      alpha=tb_value;
      if (abs(alpha) > MATE-100) alpha+=(alpha > 0) ? -(ply-1) : +(ply-1);
      else if (alpha == 0) alpha=(wtm==root_wtm) ? DrawScore() : -DrawScore();
      if(alpha >= beta) return(beta);
      else {
        SavePV(ply,alpha,2);
        return(alpha);
      }
    }
  } while(0);
# endif
/*
 ----------------------------------------------------------
|                                                          |
|   initialize.                                            |
|                                                          |
 ----------------------------------------------------------
*/
  in_check[ply+1]=0;
  extended_reason[ply+1]=no_extension;
  initial_alpha=alpha;
  last[ply]=last[ply-1];
  killer_count1[ply+1]=0;
  killer_count2[ply+1]=0;
/*
 ----------------------------------------------------------
|                                                          |
|  first, we try a null move to see if we can get a quick  |
|  cutoff with only a little work.  this operates as       |
|  follows.  instead of making a legal move, the side on   |
|  move 'passes' and does nothing.  the resulting position |
|  is searched to a shallower depth than normal (usually   |
|  one ply less but settable by the operator) this should  |
|  result in a cutoff or at least should set the lower     |
|  bound better since anything should be better than not   |
|  doing anything.                                         |
|                                                          |
|  this is skipped for any of the following reasons:       |
|                                                          |
|  1.  the side on move is in check.  the null move        |
|      results in an illegal position.                     |
|  2.  no more than one null move can appear in succession |
|      or else the search will degenerate into nothing.    |
|  3.  the side on move has little material left making    |
|      zugzwang positions more likely.                     |
|                                                          |
 ----------------------------------------------------------
*/
# if defined(NULL_MOVE_DEPTH)
  if (do_null && !in_check[ply] && 
      ((wtm) ? TotalWhitePieces : TotalBlackPieces)>2) {
    current_move[ply]=0;
    current_phase[ply]=NULL_MOVE;
#if !defined(FAST)
    if (ply <= trace_level)
      SearchTrace(ply,depth,wtm,alpha,beta,"Search",0);
#endif
    position[ply+1]=position[ply];
    Rule50Moves(ply+1)++;
    save_hash_key=HashKey;
    if (EnPassant(ply)) {
      HashEP(EnPassant(ply+1),HashKey);
      EnPassant(ply+1)=0;
    }
    if ((depth-NULL_MOVE_DEPTH-INCREMENT_PLY) >= INCREMENT_PLY)
      value=-Search(-beta,-alpha,ChangeSide(wtm),depth-NULL_MOVE_DEPTH-INCREMENT_PLY,ply+1,NO_NULL);
    else 
      value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
    HashKey=save_hash_key;
    if (abort_search) return(0);
    if (value >= beta) {
      StoreRefutation(ply,depth,wtm,beta);
      return(beta);
    }
  }
# endif
/*
 ----------------------------------------------------------
|                                                          |
|   if there is no best move from the hash table, and this |
|   is a PV node, then we need a good move to search       |
|   first.  while killers and history moves are good, they |
|   are not "good enough".  the simplest action is to try  |
|   a shallow search (depth-2) to get a move.  note that   |
|   when we call Search() with depth-2, it, too, will      |
|   not have a hash move, and will therefore recursively   |
|   continue this process, hence the name "internal        |
|   iterative deepening."                                  |
|                                                          |
 ----------------------------------------------------------
*/
  next_status[ply].phase=FIRST_PHASE;
  if (hash_move[ply]==0 && (depth > 2*INCREMENT_PLY) &&
      (((ply & 1) && alpha == root_alpha && beta == root_beta) ||
      (!(ply & 1) && alpha == -root_beta && beta == -root_alpha))) {
    current_move[ply]=0;
    value=Search(alpha,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL);
    if (abort_search) return(0);
    if (value <= alpha) {
      value=Search(-MATE,beta,wtm,depth-2*INCREMENT_PLY,ply,DO_NULL);
      if (abort_search) return(0);
    }
    else if (value < beta) {
      if ((int) pv[ply-1].path_length >= ply) hash_move[ply]=pv[ply-1].path[ply];
    }
    else hash_move[ply]=current_move[ply];
    last[ply]=last[ply-1];
    next_status[ply].phase=FIRST_PHASE;
  }
/*
 ----------------------------------------------------------
|                                                          |
|   now iterate through the move list and search the       |
|   resulting positions.  note that Search() culls any     |
|   move that is not legal by using Check().  the special  |
|   case is that we must find one legal move to search to  |
|   confirm that it's not a mate or draw.                  |
|                                                          |
 ----------------------------------------------------------
*/
  while ((current_phase[ply]=(in_check[ply]) ? NextEvasion(ply,wtm) : 
                                               NextMove(depth,ply,wtm))) {
    extended_reason[ply]&=check_extension;
#if !defined(FAST)
    if (ply <= trace_level) SearchTrace(ply,depth,wtm,alpha,beta,"Search",current_phase[ply]);
#endif
/*
 ----------------------------------------------------------
|                                                          |
|   if two successive moves are capture / re-capture so    |
|   that the material score is restored, extend the search |
|   by one ply on the re-capture since it is pretty much   |
|   forced and easy to analyze.                            |
|                                                          |
 ----------------------------------------------------------
*/
    extensions=-INCREMENT_PLY;
    if (Captured(current_move[ply]) && Captured(current_move[ply-1]) &&
        To(current_move[ply-1]) == To(current_move[ply]) &&
        (p_values[Captured(current_move[ply-1])+7] == 
         p_values[Captured(current_move[ply])+7] ||
         Promote(current_move[ply-1])) &&
        !(extended_reason[ply-1]&recapture_extension)) {
      extended_reason[ply]|=recapture_extension;
      recapture_extensions_done++;
      extensions+=RECAPTURE;
    }
/*
 ----------------------------------------------------------
|                                                          |
|   if we push a passed pawn, we need to look deeper to    |
|   see if it is a legitimate threat.                      |
|                                                          |
 ----------------------------------------------------------
*/
    if (Piece(current_move[ply])==pawn && !FutileAhead(wtm) &&
         ((wtm && To(current_move[ply])>H5 && TotalBlackPieces<16 &&
          !And(mask_pawn_passed_w[To(current_move[ply])],BlackPawns)) ||
         (!wtm && To(current_move[ply])<A4 && TotalWhitePieces<16 &&
          !And(mask_pawn_passed_b[To(current_move[ply])],WhitePawns)) ||
         push_extensions[To(current_move[ply])]) &&
         Swap(From(current_move[ply]),To(current_move[ply]),wtm) >= 0) {
      extended_reason[ply]|=passed_pawn_extension;
      passed_pawn_extensions_done++;
      extensions+=PASSED_PAWN_PUSH;
    }
/*
 ----------------------------------------------------------
|                                                          |
|   now make the move and search the resulting position.   |
|   if we are in check, the current move must be legal     |
|   since NextEvasion ensures this, otherwise we have to   |
|   make sure the side-on-move is not in check after the   |
|   move to weed out illegal moves and save time.          |
|                                                          |
 ----------------------------------------------------------
*/
    MakeMove(ply,current_move[ply],wtm);
    if (in_check[ply] || !Check(wtm)) {
/*
 ----------------------------------------------------------
|                                                          |
|   if the move to be made checks the opponent, then we    |
|   need to remember that he's in check and also extend    |
|   the depth by one ply for him to get out.               |
|                                                          |
 ----------------------------------------------------------
*/
      if (Check(ChangeSide(wtm))) {
        in_check[ply+1]=1;
        extended_reason[ply+1]=check_extension;
        check_extensions_done++;
        extensions+=IN_CHECK;
      }
      else {
        in_check[ply+1]=0;
        extended_reason[ply+1]=no_extension;
      }
/*
 ----------------------------------------------------------
|                                                          |
|   now we toss in the "razoring" trick, which simply says |
|   if we are doing fairly badly, we can reduce the depth  |
|   an additional ply, if there was nothing at the current |
|   ply that caused an extension.                          |
|                                                          |
 ----------------------------------------------------------
*/
      if (depth < 3*INCREMENT_PLY && !in_check[ply] &&
          extensions == -INCREMENT_PLY) {
        register int val=(wtm) ? Material : -Material;
        if (val+1500 < alpha) extensions-=INCREMENT_PLY;
      }
/*
 ----------------------------------------------------------
|                                                          |
|   if there's only one legal move, extend the search one  |
|   additional ply since this node is very easy to search. |
|                                                          |
 ----------------------------------------------------------
*/
      if (first_move) {
        if (last[ply]-last[ply-1] == 1) {
          extended_reason[ply]|=one_reply_extension;
          one_reply_extensions_done++;
          extensions+=ONE_REPLY_TO_CHECK;
        }
        if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
          value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
        else {
          value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
        }
        if (abort_search) {
          UnMakeMove(ply,current_move[ply],wtm);
          return(0);
        }
        first_move=0;
      }
      else {
        if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
          value=-Search(-alpha-1,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
        else {
          value=-Quiesce(-alpha-1,-alpha,ChangeSide(wtm),ply+1);
        }
        if (abort_search) {
          UnMakeMove(ply,current_move[ply],wtm);
          return(0);
        }
        if (value>alpha && value<beta) {
          if (depth+MaxExtensions(extensions) >= INCREMENT_PLY)
            value=-Search(-beta,-alpha,ChangeSide(wtm),depth+MaxExtensions(extensions),ply+1,DO_NULL);
          else 
            value=-Quiesce(-beta,-alpha,ChangeSide(wtm),ply+1);
          if (abort_search) {
            UnMakeMove(ply,current_move[ply],wtm);
            return(0);
          }
        }
      }
      if (value > alpha) {
        if(value >= beta) {
          HistoryRefutation(ply,depth,wtm);
          UnMakeMove(ply,current_move[ply],wtm);
          StoreRefutation(ply,depth,wtm,beta);
          return(beta);
        }
        alpha=value;
      }
    }
    UnMakeMove(ply,current_move[ply],wtm);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   all moves have been searched.  if none were legal,     |
|   return either MATE or DRAW depending on whether the    |
|   side to move is in check or not.                       |
|                                                          |
 ----------------------------------------------------------
*/
  if (first_move == 1) {
    value=(Check(wtm)) ? -(MATE-ply) :
                         ((wtm==root_wtm) ? DrawScore() : -DrawScore());
    if(value > beta) value=beta;
    else if (value < alpha) value=alpha;
    if (value >=alpha && value <beta) {
      SavePV(ply,value,0);
#if !defined(FAST)
      if (ply <= trace_level) printf("Search() no moves!  ply=%d\n",ply);
#endif
    }
    return(value);
  }
  else {
    if (alpha != initial_alpha) {
      memcpy(&pv[ply-1].path[ply],&pv[ply].path[ply],(pv[ply].path_length-ply+1)*4);
      memcpy(&pv[ply-1].path_hashed,&pv[ply].path_hashed,3);
      pv[ply-1].path[ply-1]=current_move[ply-1];
      HistoryBest(ply,depth,wtm);
    }
    StoreBest(ply,depth,wtm,alpha,initial_alpha);
/*
 ----------------------------------------------------------
|                                                          |
|   if the 50-move rule is drawing close, then adjust the  |
|   score to reflect the impending draw.                   |
|                                                          |
 ----------------------------------------------------------
*/
    if (Rule50Moves(ply) > 99) {
      value=(wtm==root_wtm) ? DrawScore() : -DrawScore();
      if (value < beta) SavePV(ply,value,0);
#if !defined(FAST)
      if(ply <= trace_level) printf("draw by 50-move rule detected, ply=%d.\n",ply);
#endif
      return(value);
    }
    return(alpha);
  }
}
예제 #14
0
void preprocessEvalInformation(ChessBoard * board) {
	// store the positions of the chess pieces into the eval info
	BITBOARD occupied = board->occupied;
	while (occupied != 0) {
		short nextOffset = FirstOne(occupied);
		occupied ^= offset_to_mask(nextOffset);

		switch (board->boardContents[nextOffset]) {
			case PAWN_WHITE:
				board->eval->whitePawns[board->eval->whitePawnsNum] = nextOffset;
				++board->eval->whitePawnsNum;
				break;
			case KNIGHT_WHITE:
				board->eval->whiteKnights[board->eval->whiteKnightsNum] = nextOffset;
				++board->eval->whiteKnightsNum;
				break;
			case BISHOP_WHITE:
				board->eval->whiteBishops[board->eval->whiteBishopsNum] = nextOffset;
				++board->eval->whiteBishopsNum;
				break;
			case ROOK_WHITE:
				board->eval->whiteRooks[board->eval->whiteRooksNum] = nextOffset;
				++board->eval->whiteRooksNum;
				break;
			case QUEEN_WHITE:
				board->eval->whiteQueens[board->eval->whiteQueensNum] = nextOffset;
				++board->eval->whiteQueensNum;
				break;
			case PAWN_BLACK:
				board->eval->blackPawns[board->eval->blackPawnsNum] = nextOffset;
				++board->eval->blackPawnsNum;
				break;
			case KNIGHT_BLACK:
				board->eval->blackKnights[board->eval->blackKnightsNum] = nextOffset;
				++board->eval->blackKnightsNum;
				break;
			case BISHOP_BLACK:
				board->eval->blackBishops[board->eval->blackBishopsNum] = nextOffset;
				++board->eval->blackBishopsNum;
				break;
			case ROOK_BLACK:
				board->eval->blackRooks[board->eval->blackRooksNum] = nextOffset;
				++board->eval->blackRooksNum;
				break;
			case QUEEN_BLACK:
				board->eval->blackQueens[board->eval->blackQueensNum] = nextOffset;
				++board->eval->blackQueensNum;
				break;
		}
	}

	board->eval->pieceWhiteMaterialScore = 
		board->eval->whiteKnightsNum * EvalParameters::KnightScore + 
		board->eval->whiteBishopsNum * EvalParameters::BishopScore + 
		board->eval->whiteRooksNum * EvalParameters::RookScore + 
	        board->eval->whiteQueensNum * EvalParameters::QueenScore
	  ;

	board->eval->rawWhiteMaterialScore = 
	  board->eval->pieceWhiteMaterialScore + 
	  board->eval->whitePawnsNum * EvalParameters::PawnScore
		;

	board->eval->pieceBlackMaterialScore = 
		board->eval->blackKnightsNum * EvalParameters::KnightScore + 
		board->eval->blackBishopsNum * EvalParameters::BishopScore + 
		board->eval->blackRooksNum * EvalParameters::RookScore + 
		board->eval->blackQueensNum * EvalParameters::QueenScore 
		;

	board->eval->rawBlackMaterialScore =
	  board->eval->pieceBlackMaterialScore + 
	  board->eval->blackPawnsNum * EvalParameters::PawnScore
	  ;

	setGamePhase(board);
}
예제 #15
0
파일: sprobe.c 프로젝트: syzygy1/tb
static int probe_tb_capts(struct Player *player, struct Player *opp, bitboard player_occ, bitboard opp_occ, int alpha, int beta, int *capts)
{
  int i, j;

  *capts = 0;

  if (opp->num > 1) {
    for (i = 0; i < player->num; i++) {
      int from = player->pos[i];
      bitboard bb = PieceRange(from, player->type[i], player_occ | opp_occ) & opp_occ;
      if (bb) {
	*capts = 1;
	opp->num--;
	bitboard occ2 = player_occ ^ bit[from];
	do {
	  int to = FirstOne(bb);
	  player->pos[i] = to;
	  for (j = 0; opp->pos[j] != to; j++);
	  int tmp_type = opp->type[j];
	  opp->type[j] = opp->type[opp->num];
	  opp->pos[j] = opp->pos[opp->num];
#ifdef HAS_PAWNS
	  // FIXME: optimise
	  if ((player->type[i] & 0x07) == PAWN && ((to + 0x08) & 0x30) == 0) {
	    int t = player->type[i];
	    int m;
	    for (m = KING - PAWN; m >= KNIGHT - PAWN; m--) {
	      player->type[i] = t + m;
	      int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
	      if (v > alpha) {
		alpha = v;
		if (alpha >= beta) break;
	      }
	    }
	    player->type[i] = t;
	  } else {
#endif
	    int v = -probe_tb2(opp, player, opp_occ ^ bit[to], occ2 ^ bit[to], -beta, -alpha);
	    if (v > alpha)
	      alpha = v;
#ifdef HAS_PAWNS
	  }
#endif
	  opp->type[j] = tmp_type;
	  opp->pos[j] = to;
	  if (alpha >= beta) {
	    player->pos[i] = from;
	    opp->num++;
	    return alpha;
	  }
	  ClearFirst(bb);
	} while (bb);
	player->pos[i] = from;
	opp->num++;
      }
    }
  } else {
    for (i = 0; i < player->num; i++) {
      bitboard bb = PieceRange(player->pos[i], player->type[i], player_occ) & opp_occ;
      if (bb) {
	*capts = 1;
	return -2;
      }
    }
  }

  return alpha;
}
void InitializeAttackBoards(void)
{

  int i, j, frank, ffile, trank, tfile;
  int sq, lastsq;
  int knightsq[8]={-17,-15,-10,-6,6,10,15,17};
  int bishopsq[4]={-9,-7,7,9};
  int rooksq[4]={-8,-1,1,8};
  BITBOARD sqs;
/*
   initialize pawn attack boards
*/
  for(i=0;i<64;i++) {
    w_pawn_attacks[i]=0;
    if (i < 56)
      for(j=2;j<4;j++) {
        sq=i+bishopsq[j];
        if((abs(sq/8-i/8)==1) && 
           (abs((sq&7) - (i&7))==1) &&
              (sq < 64) && (sq > -1)) 
          w_pawn_attacks[i]=Or(w_pawn_attacks[i],Shiftr(mask_1,sq));
      }
    b_pawn_attacks[i]=0;
    if (i > 7)
      for(j=0;j<2;j++) {
        sq=i+bishopsq[j];
        if((abs(sq/8-i/8)==1) && 
           (abs((sq&7)-(i&7))==1) &&
              (sq < 64) && (sq > -1)) 
          b_pawn_attacks[i]=Or(b_pawn_attacks[i],Shiftr(mask_1,sq));
      }
  }
/*
   initialize knight attack board 
*/
  for(i=0;i<64;i++) {
    knight_attacks[i]=0;
    frank=i/8;
    ffile=i&7;
    for(j=0;j<8;j++) {
      sq=i+knightsq[j];
      if((sq < 0) || (sq > 63)) continue;
      trank=sq/8;
      tfile=sq&7;
      if((abs(frank-trank) > 2) || 
         (abs(ffile-tfile) > 2)) continue;
      knight_attacks[i]=Or(knight_attacks[i],Shiftr(mask_1,sq));
    }
  }
/*
   initialize bishop/queen attack boards and masks
*/
  for(i=0;i<64;i++) {
    bishop_attacks[i]=0;
    for(j=0;j<4;j++) {
      sq=i;
      lastsq=sq;
      sq=sq+bishopsq[j];
      while((abs(sq/8-lastsq/8)==1) && 
            (abs((sq&7)-(lastsq&7))==1) &&
            (sq < 64) && (sq > -1)) {
        bishop_attacks[i]=Or(bishop_attacks[i],Shiftr(mask_1,sq));
        queen_attacks[i]=Or(queen_attacks[i],Shiftr(mask_1,sq));
        if(bishopsq[j]==7)
          plus7dir[i]=Or(plus7dir[i],Shiftr(mask_1,sq));
        else if(bishopsq[j]==9)
          plus9dir[i]=Or(plus9dir[i],Shiftr(mask_1,sq));
        else if(bishopsq[j]==-7)
          minus7dir[i]=Or(minus7dir[i],Shiftr(mask_1,sq));
        else
          minus9dir[i]=Or(minus9dir[i],Shiftr(mask_1,sq));
        lastsq=sq;
        sq=sq+bishopsq[j];
      }
    }
  }
  plus1dir[64]=0;
  plus7dir[64]=0;
  plus8dir[64]=0;
  plus9dir[64]=0;
  minus1dir[64]=0;
  minus7dir[64]=0;
  minus8dir[64]=0;
  minus9dir[64]=0;
/*
   initialize rook/queen attack boards
*/
  for(i=0;i<64;i++) {
    rook_attacks[i]=0;
    for(j=0;j<4;j++) {
      sq=i;
      lastsq=sq;
      sq=sq+rooksq[j];
      while((((abs(sq/8-lastsq/8)==1) && 
             (abs((sq&7)-(lastsq&7))==0)) || 
            ((abs(sq/8-lastsq/8)==0) && 
             (abs((sq&7)-(lastsq&7))==1))) &&
            (sq < 64) && (sq > -1)) {
        rook_attacks[i]=Or(rook_attacks[i],Shiftr(mask_1,sq));
        queen_attacks[i]=Or(queen_attacks[i],Shiftr(mask_1,sq));
        if(rooksq[j]==1)
          plus1dir[i]=Or(plus1dir[i],Shiftr(mask_1,sq));
        else if(rooksq[j]==8)
          plus8dir[i]=Or(plus8dir[i],Shiftr(mask_1,sq));
        else if(rooksq[j]==-1)
          minus1dir[i]=Or(minus1dir[i],Shiftr(mask_1,sq));
        else
          minus8dir[i]=Or(minus8dir[i],Shiftr(mask_1,sq));
        lastsq=sq;
        sq=sq+rooksq[j];
      }
    }
  }
/*
   initialize king attack board 
*/
  for(i=0;i<64;i++) {
    king_attacks[i]=0;
    king_attacks_1[i]=0;
    king_attacks_2[i]=0;
    for (j=0;j<64;j++) {
      if (Distance(i,j) == 1)
        king_attacks[i]=Or(king_attacks[i],set_mask[j]);
      if (Distance(i,j) <= 1)
        king_attacks_1[i]=Or(king_attacks_1[i],set_mask[j]);
      if (Distance(i,j) <= 2)
        king_attacks_2[i]=Or(king_attacks_2[i],set_mask[j]);
    }
  }
/*
  direction[sq1][sq2] gives the "move direction" to move from
  sq1 to sq2.  obstructed[sq1][sq2] gives a bit vector that indicates
  which squares must be unoccupied in order for <sq1> to attack <sq2>,
  assuming a sliding piece is involved.  to use this, you simply have
  to Or(obstructed[sq1][sq2],occupied_squares) and if the result is 
  "0" then a sliding piece on sq1 would attack sq2 and vice-versa.
*/
  for (i=0;i<64;i++) {
    for (j=0;j<64;j++)
      obstructed[i][j]=(BITBOARD) -1;
    sqs=plus1dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=1;
      obstructed[i][j]=Xor(plus1dir[i],plus1dir[j-1]);
      Clear(j,sqs);
    }
    sqs=plus7dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=7;
      obstructed[i][j]=Xor(plus7dir[i],plus7dir[j-7]);
      Clear(j,sqs);
    }
    sqs=plus8dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=8;
      obstructed[i][j]=Xor(plus8dir[i],plus8dir[j-8]);
      Clear(j,sqs);
    }
    sqs=plus9dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=9;
      obstructed[i][j]=Xor(plus9dir[i],plus9dir[j-9]);
      Clear(j,sqs);
    }
    sqs=minus1dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=-1;
      obstructed[i][j]=Xor(minus1dir[i],minus1dir[j+1]);
      Clear(j,sqs);
    }
    sqs=minus7dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=-7;
      obstructed[i][j]=Xor(minus7dir[i],minus7dir[j+7]);
      Clear(j,sqs);
    }
    sqs=minus8dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=-8;
      obstructed[i][j]=Xor(minus8dir[i],minus8dir[j+8]);
      Clear(j,sqs);
    }
    sqs=minus9dir[i];
    while (sqs) {
      j=FirstOne(sqs);
      directions[i][j]=-9;
      obstructed[i][j]=Xor(minus9dir[i],minus9dir[j+9]);
      Clear(j,sqs);
    }
  }
  {
    int diag_sq[64] = {                0,
                                     1,  0,
                                   2,  1,  0,
                                 3,  2,  1,  0,
                               4,  3,  2,  1,  0,
                             5,  4,  3,  2,  1,  0,
                           6,  5,  4,  3,  2,  1,  0,
                         7,  6,  5,  4,  3,  2,  1,  0,
                           6,  5,  4,  3,  2,  1,  0,
                             5,  4,  3,  2,  1,  0,
                               4,  3,  2,  1,  0,
                                 3,  2,  1,  0,
                                   2,  1,  0,
                                     1,  0,
                                       0 };

    int bias_rl45[64] = {              0,
                                     1,  1,
                                   3,  3,  3,
                                 6,  6,  6,  6,
                              10, 10, 10, 10, 10,
                            15, 15, 15, 15, 15, 15,
                          21, 21, 21, 21, 21, 21, 21,
                        28, 28, 28, 28, 28, 28, 28, 28,
                          36, 36, 36, 36, 36, 36, 36,
                            43, 43, 43, 43, 43, 43,
                              49, 49, 49, 49, 49,
                                54, 54, 54, 54,
                                  58, 58, 58,
                                    61, 61,
                                      63 };
    int square, pcs, attacks;
    int rsq, tsq;
    int mask;

/*
  initialize the rotated attack board that is based on the
  normal chess 
*/
    for (square=0;square<64;square++) {
      for (i=0;i<256;i++) {
        rook_attacks_r0[square][i]=0;
        rook_mobility_r0[square][i]=0;
      }
      for (pcs=0;pcs<256;pcs++) {
        attacks=InitializeFindAttacks(7-File(square),pcs,8);
        while (attacks) {
          sq=first_ones_8bit[attacks];
          rook_attacks_r0[square][pcs]=
            Or(rook_attacks_r0[square][pcs],set_mask[(square&56)+sq]);
          attacks=attacks&(~(1<<(7-sq)));
        }
        rook_mobility_r0[square][pcs]=PopCnt(rook_attacks_r0[square][pcs]);
      }
    }
/*
  initialize the rotated attack board that is based on one that
  rotated left 90 degrees (which lines up a file horizontally,
  rather than its normal vertical orientation.)
*/
    for (square=0;square<64;square++) {
      for (i=0;i<256;i++) {
        rook_attacks_rl90[square][i]=0;
        rook_mobility_rl90[square][i]=0;
      }
      for (pcs=0;pcs<256;pcs++) {
        attacks=InitializeFindAttacks(Rank(square),pcs,8);
        while (attacks) {
          sq=first_ones_8bit[attacks];
          rook_attacks_rl90[square][pcs]=
            Or(rook_attacks_rl90[square][pcs],
               set_mask[init_r90[((square&7)<<3)+sq]]);
          attacks=attacks&(~(1<<(7-sq)));
        }
        rook_mobility_rl90[square][pcs]=PopCnt(rook_attacks_rl90[square][pcs]);
      }
    }
/*
  initialize the rotated attack board that is based on one that is 
  rotated left 45 degrees (which lines up the (a8-h1) diagonal 
  horizontally.
*/
    for (square=0;square<64;square++) {
      for (i=0;i<256;i++) {
        bishop_attacks_rl45[square][i]=0;
        bishop_mobility_rl45[square][i]=0;
      }
      for (pcs=0;pcs<(1<<diagonal_length[init_l45[square]]);pcs++) {
        rsq=init_l45[square];
        tsq=diag_sq[rsq];
        attacks=InitializeFindAttacks(tsq,pcs,diagonal_length[rsq])<<
                          (8-diagonal_length[rsq]);
        while (attacks) {
          sq=first_ones_8bit[attacks];
          bishop_attacks_rl45[square][pcs]=
            Or(bishop_attacks_rl45[square][pcs],
               set_mask[init_ul45[sq+bias_rl45[rsq]]]);
          attacks=attacks&(~(1<<(7-sq)));
        }
      }
      mask=(1<<diagonal_length[init_l45[square]])-1;
      for (pcs=0;pcs<256;pcs++) {
        if ((pcs&mask) != pcs)
          bishop_attacks_rl45[square][pcs]=
            bishop_attacks_rl45[square][pcs&mask];
        bishop_mobility_rl45[square][pcs]=
          PopCnt(bishop_attacks_rl45[square][pcs]);
      }
    }
/*
  initialize the rotated attack board that is based on one that is 
  rotated right 45 degrees (which lines up the (a1-h8) diagonal
  horizontally,
*/
    for (square=0;square<64;square++) {
      for (i=0;i<256;i++) {
        bishop_attacks_rr45[square][i]=0;
        bishop_mobility_rr45[square][i]=0;
      }
      for (pcs=0;pcs<(1<<diagonal_length[init_r45[square]]);pcs++) {
        rsq=init_r45[square];
        tsq=diag_sq[rsq];
        attacks=InitializeFindAttacks(tsq,pcs,diagonal_length[rsq])<<
                          (8-diagonal_length[rsq]);
        while (attacks) {
          sq=first_ones_8bit[attacks];
          bishop_attacks_rr45[square][pcs]=
            Or(bishop_attacks_rr45[square][pcs],
               set_mask[init_ur45[sq+bias_rl45[rsq]]]);
          attacks=attacks&(~(1<<(7-sq)));
        }
      }
      mask=(1<<diagonal_length[init_r45[square]])-1;
      for (pcs=0;pcs<256;pcs++) {
        if ((pcs&mask) != pcs)
          bishop_attacks_rr45[square][pcs]=
            bishop_attacks_rr45[square][pcs&mask];
        bishop_mobility_rr45[square][pcs]=
          PopCnt(bishop_attacks_rr45[square][pcs]);
      }
    }
  }
}
/*
********************************************************************************
*                                                                              *
*   Swap() is used to analyze capture moves to see whether or not they appear  *
*   to be profitable.  the basic algorithm is extremely fast since it uses the *
*   bitmaps to determine which squares are attacking the [target] square.      *
*                                                                              *
*   the algorithm is quite simple.  using the attack bitmaps, we enumerate all *
*   the pieces that are attacking [target] for either side.  then we simply    *
*   use the lowest piece (value) for the correct side to capture on [target].  *
*   we continually "flip" sides taking the lowest piece each time.             *
*                                                                              *
*   as a piece is used, if it is a sliding piece (pawn, bishop, rook or queen) *
*   we "peek" behind it to see if it is attacked by a sliding piece in the     *
*   direction away from the piece being captured.  if so, and that sliding     *
*   piece moves in this direction, then it is added to the list of attackers   *
*   since its attack has been "uncovered" by moving the capturing piece.       *
*                                                                              *
********************************************************************************
*/
int Swap(int source, int target, int wtm)
{
  register BITBOARD attacks;
  register int attacked_piece;
  register int square, direction;
  register int sign, color, next_capture=1;
  int swap_list[32];
/*
 ----------------------------------------------------------
|                                                          |
|   determine which squares attack <target> for each side. |
|                                                          |
 ----------------------------------------------------------
*/
  attacks=AttacksTo(target);
/*
 ----------------------------------------------------------
|                                                          |
|   initialize by placing the piece on <target> first in   |
| the list as it is being captured to start things off.    |
|                                                          |
 ----------------------------------------------------------
*/
  attacked_piece=p_values[PieceOnSquare(target)+7];
/*
 ----------------------------------------------------------
|                                                          |
|   the first piece to capture on <target> is the piece    |
|   standing on <source>.                                  |
|                                                          |
 ----------------------------------------------------------
*/
  color=ChangeSide(wtm);
  swap_list[0]=attacked_piece;
  sign=-1;
  attacked_piece=p_values[PieceOnSquare(source)+7];
  Clear(source,attacks);
  direction=directions[target][source];
  if (direction) attacks=SwapXray(attacks,source,direction);
/*
 ----------------------------------------------------------
|                                                          |
|   now pick out the least valuable piece for the correct  |
|   side that is bearing on <target>.  as we find one, we  |
|   call SwapXray() to add the piece behind this piece     |
|   that is indirectly bearing on <target> (if any).       |
|                                                          |
 ----------------------------------------------------------
*/
  while (attacks) {
    if (color) {
      if (And(WhitePawns,attacks))
        square=FirstOne(And(WhitePawns,attacks));
      else if (And(WhiteKnights,attacks))
        square=FirstOne(And(WhiteKnights,attacks));
      else if (And(WhiteBishops,attacks))
        square=FirstOne(And(WhiteBishops,attacks));
      else if (And(WhiteRooks,attacks))
        square=FirstOne(And(WhiteRooks,attacks));
      else if (And(WhiteQueens,attacks))
        square=FirstOne(And(WhiteQueens,attacks));
      else if (And(WhiteKing,attacks))
        square=WhiteKingSQ;
      else break;
    }
    else {
      if (And(BlackPawns,attacks))
        square=FirstOne(And(BlackPawns,attacks));
      else if (And(BlackKnights,attacks))
        square=FirstOne(And(BlackKnights,attacks));
      else if (And(BlackBishops,attacks))
        square=FirstOne(And(BlackBishops,attacks));
      else if (And(BlackRooks,attacks))
        square=FirstOne(And(BlackRooks,attacks));
      else if (And(BlackQueens,attacks))
        square=FirstOne(And(BlackQueens,attacks));
      else if (And(BlackKing,attacks))
        square=BlackKingSQ;
      else break;
    }
/*
 ------------------------------------------------
|                                                |
|  located the least valuable piece bearing on   |
|  <target>.  remove it from the list and then   |
|  find out if a sliding piece behind it attacks |
|  through this piece.                           |
|                                                |
 ------------------------------------------------
*/
    swap_list[next_capture]=swap_list[next_capture-1]+sign*attacked_piece;
    attacked_piece=p_values[PieceOnSquare(square)+7];
    Clear(square,attacks);
    direction=directions[target][square];
    if (direction) attacks=SwapXray(attacks,square,direction);
    next_capture++;
    sign=-sign;
    color=ChangeSide(color);
  }
/*
 ----------------------------------------------------------
|                                                          |
|   starting at the end of the sequence of values, use a   |
|   "minimax" like procedure to decide where the captures  |
|   will stop.                                             |
|                                                          |
 ----------------------------------------------------------
*/
  next_capture--;
  if(next_capture&1) sign=-1;
  else sign=1;
  while (next_capture) {
    if (sign < 0) {
      if(swap_list[next_capture] <= swap_list[next_capture-1])
         swap_list[next_capture-1]=swap_list[next_capture];
    }
    else {
      if(swap_list[next_capture] >= swap_list[next_capture-1])
       swap_list[next_capture-1]=swap_list[next_capture];
    }
    next_capture--;
    sign=-sign;
  }
  return (swap_list[0]);
}
예제 #18
0
void FindGoodCatRules(Node *n,int VarI, int *RuleInd,int &firstone)
// finds out which categorical rule using VarI are good.
// a good rule is one that does not result in logically empty bottom nodes
//n: the node at which the rule is to be set
//VarI: the variable ~ the rule
//RuleInd: integer vector whose length is the number of possible rules 2^(NR-1) - 1
//	on exit 1 if rule ok 0 otherwise, already allocated
//firstone: first category still "alive" at node n, depends on tree above n
{

	int i,j;

	int NR = RuleNum[VarI];
	int *sel = new int [NR+1];
	int numrul =  (int)pow(2.0,NR-1)-1;
	for(i=1;i<=numrul;i++) RuleInd[i]=0;

	int *cats = new int [NR+1];
	GetSetCats(n,VarI,cats);
	firstone = FirstOne(NR,cats);
	if(!firstone) {
		Rprintf("error in FindGoodCatRule: no availble cats\n");
	} else {
		sel[firstone]=1;
	}

	int *sel1 = new int [NR-1+1];

	NodeP *lbotvec;
	int lnbot;
	MakeBotVec(n->LeftC,&lbotvec,&lnbot); //note lbotvec allocated here
	int *lfcount=new int [lnbot+1]; //allocation

	NodeP *rbotvec;
	int rnbot;
	MakeBotVec(n->RightC,&rbotvec,&rnbot); //note rbotvec allocated here
	int *rfcount=new int [rnbot+1]; //allocation

	
	// for eachrule see if it is any good
	// you do this be sending the categories left or right according to the rule
	// and checking to make sure that no bottom nodes are empty
	for(i=0;i<numrul;i++) {

		indtd(NR-1,i,sel1);
		
		for(j=1;j<firstone;j++) sel[j]=sel1[j];
		for(j=(firstone+1);j<=NR;j++) sel[j] = sel1[j-1];
		
		for(j=1;j<=lnbot;j++) lfcount[j]=0;
		for(j=1;j<=rnbot;j++) rfcount[j]=0;

		for(j=1;j<=NR;j++) {
			if(cats[j]) {
				if(sel[j]) {
					CatFindBots(n->RightC,VarI,j,rbotvec,rfcount);
				} else {
					CatFindBots(n->LeftC,VarI,j,lbotvec,lfcount);
				}
			}
			if((NoZero(lnbot,lfcount)) && (NoZero(rnbot,rfcount))) {
				RuleInd[i+1]=1;
				break;
			}
		}		
		
	}

	delete [] sel;
	delete [] sel1;
	delete [] cats;
	delete [] lbotvec;
	delete [] rbotvec;
	delete [] lfcount;
	delete [] rfcount;
}