Exemple #1
0
void PawnEntry::Read(const Position& pos)
{
	U64 x;
	FLD f;
	int file, rank;

	m_pawnHash = pos.PawnHash();
	m_score = 0;
	m_passed[WHITE] = m_passed[BLACK] = 0;

	for (file = 0; file < 10; ++file)
	{
		m_ranks[file][WHITE] = 0;
		m_ranks[file][BLACK] = 7;
	}

	x = pos.Bits(PW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		file = Col(f) + 1;
		rank = Row(f);
		if (rank > m_ranks[file][WHITE])
			m_ranks[file][WHITE] = rank;
	}

	x = pos.Bits(PB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		file = Col(f) + 1;
		rank = Row(f);
		if (rank < m_ranks[file][BLACK])
			m_ranks[file][BLACK] = rank;
	}

	x = pos.Bits(PW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		file = Col(f) + 1;
		rank = Row(f);

		m_score += PSQ_P[f];
		if (m_ranks[file][BLACK] == 7)
		{
			if (m_ranks[file - 1][BLACK] >= rank && m_ranks[file + 1][BLACK] >= rank)
				m_passed[WHITE] |= Bitboard::Single(f);
		}

		if (rank != m_ranks[file][WHITE])
			m_score += PawnDoubled;

		if (m_ranks[file - 1][WHITE] == 0 && m_ranks[file + 1][WHITE] == 0)
			m_score += PawnIsolated;
		else if (m_ranks[file - 1][WHITE] < rank && m_ranks[file + 1][WHITE] < rank)
			m_score += PawnBackwards;
	}

	x = pos.Bits(PB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		file = Col(f) + 1;
		rank = Row(f);

		m_score -= PSQ_P[FLIP[f]];
		if (m_ranks[file][WHITE] == 0)
		{
			if (m_ranks[file - 1][WHITE] <= rank && m_ranks[file + 1][WHITE] <= rank)
				m_passed[BLACK] |= Bitboard::Single(f);
		}

		if (rank != m_ranks[file][BLACK])
			m_score -= PawnDoubled;

		if (m_ranks[file - 1][BLACK] == 7 && m_ranks[file + 1][BLACK] == 7)
			m_score -= PawnIsolated;
		else if (m_ranks[file - 1][BLACK] > rank && m_ranks[file + 1][BLACK] > rank)
			m_score -= PawnBackwards;
	}
}
Exemple #2
0
EVAL_ESTIMATION EstimateDraw(const Position& pos)
{
	static const int FIELD_COLOR[64] =
	{
		0, 1, 0, 1, 0, 1, 0, 1,
		1, 0, 1, 0, 1, 0, 1, 0,
		0, 1, 0, 1, 0, 1, 0, 1,
		1, 0, 1, 0, 1, 0, 1, 0,
		0, 1, 0, 1, 0, 1, 0, 1,
		1, 0, 1, 0, 1, 0, 1, 0,
		0, 1, 0, 1, 0, 1, 0, 1,
		1, 0, 1, 0, 1, 0, 1, 0
	};

	// KBP-K

	if (pos.MatIndex(WHITE) == 3 && pos.Count(PW) == 1)
	{
		if (pos.MatIndex(BLACK) == 0 && pos.Count(PB) == 0)
		{
			FLD pawn = Bitboard::LSB(pos.Bits(PW));
			FLD bishop = Bitboard::LSB(pos.Bits(BW));
			FLD king = pos.King(BLACK);
			if (Col(pawn) == 0)
			{
				if (FIELD_COLOR[A8] != FIELD_COLOR[bishop])
				{
					if (king == A8 || king == A7 || king == B8 || king == B7)
						return EVAL_PRACTICAL_DRAW;
				}
			}
			if (Col(pawn) == 7)
			{
				if (FIELD_COLOR[H8] != FIELD_COLOR[bishop])
				{
					if (king == H8 || king == H7 || king == G8 || king == G7)
						return EVAL_PRACTICAL_DRAW;
				}
			}
		}
	}

	if (pos.MatIndex(BLACK) == 3 && pos.Count(PB) == 1)
	{
		if (pos.MatIndex(WHITE) == 0 && pos.Count(PW) == 0)
		{
			FLD pawn = Bitboard::LSB(pos.Bits(PB));
			FLD bishop = Bitboard::LSB(pos.Bits(BB));
			FLD king = pos.King(WHITE);
			if (Col(pawn) == 0)
			{
				if (FIELD_COLOR[A1] != FIELD_COLOR[bishop])
				{
					if (king == A1 || king == A2 || king == B1 || king == B2)
						return EVAL_PRACTICAL_DRAW;
				}
			}
			if (Col(pawn) == 7)
			{
				if (FIELD_COLOR[H1] != FIELD_COLOR[bishop])
				{
					if (king == H1 || king == H2 || king == G1 || king == G2)
						return EVAL_PRACTICAL_DRAW;
				}
			}
		}
	}

	// KB-KB

	if (pos.MatIndex(WHITE) == 3 && pos.MatIndex(BLACK) == 3)
	{
		if (pos.Count(BW) == 1 && pos.Count(BB) == 1)
		{
			FLD bw = Bitboard::LSB(pos.Bits(BW));
			FLD bb = Bitboard::LSB(pos.Bits(BB));
			if (FIELD_COLOR[bw] != FIELD_COLOR[bb])
				return EVAL_PROBABLE_DRAW;
		}
	}

	// LOW MATERIAL

	// We can claim draw only in case of "King + minor vs. King".
	if (pos.Count(PW) == 0 && pos.Count(PB) == 0)
	{
		if (pos.MatIndex(WHITE) + pos.MatIndex(BLACK) <= 3)
			return EVAL_THEORETICAL_DRAW;
	}

	// Engames like "King + minor vs. King + minor" - just practical draw,
	// but no draw claim, because checkmate positions do exist.
	if (pos.Count(PW) == 0 && pos.MatIndex(WHITE) < 5)
	{
		if (pos.Count(PB) == 0 && pos.MatIndex(BLACK) < 5)
			return EVAL_PRACTICAL_DRAW;
		else
			return EVAL_WHITE_CANNOT_WIN;
	}

	if (pos.Count(PB) == 0 && pos.MatIndex(BLACK) < 5)
	{
		if (pos.Count(PW) == 0 && pos.MatIndex(WHITE) < 5)
			return EVAL_PRACTICAL_DRAW;
		else
			return EVAL_BLACK_CANNOT_WIN;
	}

	return EVAL_UNKNOWN;
}
Exemple #3
0
EVAL Evaluate(const Position& pos, EVAL alpha, EVAL beta)
{
	EVAL_ESTIMATION ee = EstimateDraw(pos);
	if (ee == EVAL_THEORETICAL_DRAW || ee == EVAL_PRACTICAL_DRAW)
		return DRAW_SCORE;

	EVAL matScore = pos.Material(WHITE) - pos.Material(BLACK);
	if (pos.Count(BW) == 2)
		matScore += BishopPair;
	if (pos.Count(BB) == 2)
		matScore -= BishopPair;
	matScore = matScore * g_evalParams.Material / 50;

	EVAL lazy = (pos.Side() == WHITE)? matScore : -matScore;
	if (lazy <= alpha - g_evalParams.LazyEvalMargin)
		return alpha;
	if (lazy >= beta + g_evalParams.LazyEvalMargin)
		return beta;

	EVAL posScore = 0;
	EVAL boardScore = 0;
	EVAL mobScore = 0;
	EVAL pawnStructScore = 0;
	EVAL pawnPassedScore = 0;
	EVAL kingSafetyScore = 0;
	U64 x, y, occ = pos.BitsAll();
	FLD f;

	//
	//   PAWNS
	//

	int index = pos.PawnHash() % g_pawnHashSize;

	PawnEntry& pentry = g_pawnHash[index];
	if (pentry.m_pawnHash != pos.PawnHash())
		pentry.Read(pos);

	pawnStructScore += pentry.m_score;

	x = pentry.m_passed[WHITE];
	while (x)
	{
		f = Bitboard::PopLSB(x);

		if (pos[f - 8] == NOPIECE)
			pawnPassedScore += PAWN_PASSED_FREE[7 - Row(f)];
		else
			pawnPassedScore += PAWN_PASSED_BLOCKED[7 - Row(f)];

		if (pos.MatIndex(BLACK) == 0)
		{
			FLD f1 = f;
			if (pos.Side() == BLACK)
				f1 += 8;
			if ((Bitboard::PawnSquare(f1, WHITE) & pos.Bits(KB)) == 0)
				pawnPassedScore += PawnPassedSquare * (7 - Row(f1)) / 6;
		}
		else if (pos.MatIndex(BLACK) < 10)
			pawnPassedScore += PassedKingDist * Dist(f - 8, pos.King(BLACK));
	}

	x = pentry.m_passed[BLACK];
	while (x)
	{
		f = Bitboard::PopLSB(x);

		if (pos[f + 8] == NOPIECE)
			pawnPassedScore -= PAWN_PASSED_FREE[Row(f)];
		else
			pawnPassedScore -= PAWN_PASSED_BLOCKED[Row(f)];

		if (pos.MatIndex(WHITE) == 0)
		{
			FLD f1 = f;
			if (pos.Side() == WHITE)
				f1 -= 8;
			if ((Bitboard::PawnSquare(f1, BLACK) & pos.Bits(KW)) == 0)
				pawnPassedScore -= PawnPassedSquare * Row(f1) / 6;
		}
		else if (pos.MatIndex(WHITE) < 10)
			pawnPassedScore -= PassedKingDist * Dist(f + 8, pos.King(WHITE));
	}

	//
	//   KNIGHTS
	//

	static const int outpost[64] =
	{
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 1, 1, 0, 0, 0,
		0, 0, 1, 1, 1, 1, 0, 0,
		0, 1, 1, 1, 1, 1, 1, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0
	};

	static const int knight_mob[64] =
	{
		2, 3, 4, 4, 4, 4, 3, 2,
		3, 4, 6, 6, 6, 6, 4, 2,
		4, 6, 8, 8, 8, 8, 6, 4,
		4, 6, 8, 8, 8, 8, 6, 4,
		4, 6, 8, 8, 8, 8, 6, 4,
		4, 6, 8, 8, 8, 8, 6, 4,
		3, 4, 6, 6, 6, 6, 4, 2,
		2, 3, 4, 4, 4, 4, 3, 2
	};

	x = pos.Bits(NW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		boardScore += PSQ_N[f];
		int mob = knight_mob[f];
		mobScore += KNIGHT_MOBILITY[mob];
		if (outpost[f])
		{
			if (Bitboard::PawnAttacks(f, BLACK) & pos.Bits(PW))
				boardScore += KnightOutpost;
		}
	}

	x = pos.Bits(NB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		boardScore -= PSQ_N[FLIP[f]];
		int mob = knight_mob[f];
		mobScore -= KNIGHT_MOBILITY[mob];
		if (outpost[FLIP[f]])
		{
			if (Bitboard::PawnAttacks(f, WHITE) & pos.Bits(PB))
				boardScore -= KnightOutpost;
		}
	}

	//
	//   BISHOPS
	//

	x = pos.Bits(BW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		boardScore += PSQ_B[f];
		y = Bitboard::BishopAttacks(f, occ);
		mobScore += BISHOP_MOBILITY[Bitboard::CountBits(y)];
	}

	x = pos.Bits(BB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		boardScore -= PSQ_B[FLIP[f]];
		y = Bitboard::BishopAttacks(f, occ);
		mobScore -= BISHOP_MOBILITY[Bitboard::CountBits(y)];
	}

	//
	//   ROOKS
	//

	x = pos.Bits(RW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		y = Bitboard::RookAttacks(f, occ ^ pos.Bits(RW));
		mobScore += ROOK_MOBILITY[Bitboard::CountBits(y)];

		if (Row(f) == 1)
			boardScore += Rook7th;

		int file = Col(f) + 1;
		if (pentry.m_ranks[file][WHITE] == 0)
			boardScore += RookOpen;
	}

	x = pos.Bits(RB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		y = Bitboard::RookAttacks(f, occ ^ pos.Bits(RB));
		mobScore -= ROOK_MOBILITY[Bitboard::CountBits(y)];

		if (Row(f) == 6)
			boardScore -= Rook7th;

		int file = Col(f) + 1;
		if (pentry.m_ranks[file][BLACK] == 7)
			boardScore -= RookOpen;
	}

	//
	//   QUEENS
	//

	x = pos.Bits(QW);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		kingSafetyScore += QUEEN_KING_TROPISM[Dist(f, pos.King(BLACK))];
	}

	x = pos.Bits(QB);
	while (x)
	{
		f = Bitboard::PopLSB(x);
		kingSafetyScore -= QUEEN_KING_TROPISM[Dist(f, pos.King(WHITE))];
	}

	//
	//   KINGS
	//

	{
		f = pos.King(WHITE);
		kingSafetyScore += PSQ_K_MID[f] * pos.MatIndex(BLACK) / 32;
		boardScore += PSQ_K_END[f] * (32 - pos.MatIndex(BLACK)) / 32;
		int penalty = PawnShieldWhite(pentry, f);
		kingSafetyScore += KING_PAWN_SHIELD[penalty] * pos.MatIndex(BLACK) / 32;
	}

	{
		f = pos.King(BLACK);
		kingSafetyScore -= PSQ_K_MID[FLIP[f]] * pos.MatIndex(WHITE) / 32;
		boardScore -= PSQ_K_END[FLIP[f]] * (32 - pos.MatIndex(WHITE)) / 32;
		int penalty = PawnShieldBlack(pentry, f);
		kingSafetyScore -= KING_PAWN_SHIELD[penalty] * pos.MatIndex(WHITE) / 32;
	}

	posScore += mobScore * g_evalParams.Mobility / 50;
	posScore += pawnStructScore * g_evalParams.PawnStruct / 50;
	posScore += pawnPassedScore * g_evalParams.PawnPassed / 50;
	posScore += kingSafetyScore * g_evalParams.KingSafety / 50;
	posScore += boardScore * g_evalParams.BoardControl / 50;

	EVAL e = matScore + posScore;

	if (e > 0 && ee == EVAL_WHITE_CANNOT_WIN)
		e = 0;

	if (e < 0 && ee == EVAL_BLACK_CANNOT_WIN)
		e = 0;

	if (ee == EVAL_PROBABLE_DRAW)
		e /= 2;

	return (pos.Side() == WHITE)? e : -e;
}
void MoveList::GenCheckEvasions(const Position& pos)
{
  Clear();

  COLOR side = pos.Side();
  COLOR opp = side ^ 1;
  U64 freeOrOpp = ~pos.BitsAll(side);
  U64 occ = pos.BitsAll();

  U64 x, y;
  FLD from, to;
  PIECE piece, captured;
  FLD K = pos.King(side);

  U64 attackers = pos.GetAttacks(K, opp, occ);
  U64 mask = attackers;
  while (attackers)
  {
    from = PopLSB(attackers);
    mask |= BB_BETWEEN[from][K];
  }

  int fwd = -8 + 16 * side;
  int second = 6 - 5 * side;
  int seventh = 1 + 5 * side;

  piece = PW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    int row = Row(from);

    to = static_cast<FLD>(from + fwd);
    if (!pos[to])
    {
      if (row == second)
      {
        if (BB_SINGLE[to] & mask)
          Add(from, to, piece);
        
        to = static_cast<FLD>(to + fwd);
        if (!pos[to])
        {
          if (BB_SINGLE[to] & mask)
            Add(from, to, piece);
        }
      }
      else if (row == seventh)
      {
        if (BB_SINGLE[to] & mask)
        {
          Add(from, to, piece, NOPIECE, QW | side);
          Add(from, to, piece, NOPIECE, RW | side);
          Add(from, to, piece, NOPIECE, BW | side);
          Add(from, to, piece, NOPIECE, NW | side);
        }
      }
      else
      {
        if (BB_SINGLE[to] & mask)
          Add(from, to, piece);
      }
    }

    y = BB_PAWN_ATTACKS[from][side] & pos.BitsAll(opp) & mask;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];

      if (row == seventh)
      {
        Add(from, to, piece, captured, QW | side);
        Add(from, to, piece, captured, RW | side);
        Add(from, to, piece, captured, BW | side);
        Add(from, to, piece, captured, NW | side);        
      }
      else
        Add(from, to, piece, captured);
    }
  }

  to = pos.Ep();
  if (to != NF)
  {
    y = BB_PAWN_ATTACKS[to][opp] & pos.Bits(PW | side);
    while (y)
    {
      from = PopLSB(y);
      Add(from, to, piece, PW | opp);
    }
  }

  piece = NW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KNIGHT_ATTACKS[from] & freeOrOpp & mask;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = BW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BishopAttacks(from, occ) & freeOrOpp & mask;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = RW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = RookAttacks(from, occ) & freeOrOpp & mask;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = QW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = QueenAttacks(from, occ) & freeOrOpp & mask;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = KW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KING_ATTACKS[from] & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      if (!pos.IsAttacked(to, opp))
      {
        captured = pos[to];
        Add(from, to, piece, captured);
      }
    }
  }
}
void MoveList::GenAllMoves(const Position& pos)
{
  Clear();

  COLOR side = pos.Side();
  COLOR opp = side ^ 1;
  U64 freeOrOpp = ~pos.BitsAll(side);
  U64 occ = pos.BitsAll();

  U64 x, y;
  FLD from, to;
  PIECE piece, captured;

  int fwd = -8 + 16 * side;
  int second = 6 - 5 * side;
  int seventh = 1 + 5 * side;

  piece = PW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    int row = Row(from);

    to = static_cast<FLD>(from + fwd);
    if (!pos[to])
    {
      if (row == second)
      {
        Add(from, to, piece);
        to = static_cast<FLD>(to + fwd);
        if (!pos[to])
          Add(from, to, piece);
      }
      else if (row == seventh)
      {
        Add(from, to, piece, NOPIECE, QW | side);
        Add(from, to, piece, NOPIECE, RW | side);
        Add(from, to, piece, NOPIECE, BW | side);
        Add(from, to, piece, NOPIECE, NW | side);
      }
      else
        Add(from, to, piece);
    }

    y = BB_PAWN_ATTACKS[from][side] & pos.BitsAll(opp);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];

      if (row == seventh)
      {
        Add(from, to, piece, captured, QW | side);
        Add(from, to, piece, captured, RW | side);
        Add(from, to, piece, captured, BW | side);
        Add(from, to, piece, captured, NW | side);        
      }
      else
        Add(from, to, piece, captured);
    }
  }

  to = pos.Ep();
  if (to != NF)
  {
    y = BB_PAWN_ATTACKS[to][opp] & pos.Bits(PW | side);
    while (y)
    {
      from = PopLSB(y);
      Add(from, to, piece, PW | opp);
    }
  }

  piece = NW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KNIGHT_ATTACKS[from] & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = BW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BishopAttacks(from, occ) & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = RW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = RookAttacks(from, occ) & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = QW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = QueenAttacks(from, occ) & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = KW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KING_ATTACKS[from] & freeOrOpp;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }

    if (from == E1 && side == WHITE)
    {
      if (!pos[F1] && !pos[G1] && (pos.Castlings() & WHITE_O_O))
        if (!pos.IsAttacked(E1, BLACK) && !pos.IsAttacked(F1, BLACK) && !pos.IsAttacked(G1, BLACK))
          Add(E1, G1, KW);

      if (!pos[D1] && !pos[C1] && !pos[B1] 
          && (pos.Castlings() & WHITE_O_O_O))
        if (!pos.IsAttacked(E1, BLACK) && !pos.IsAttacked(D1, BLACK) && !pos.IsAttacked(C1, BLACK))
          Add(E1, C1, KW);
    }
    else if (from == E8 && side == BLACK)
    {
      if (!pos[F8] && !pos[G8] && (pos.Castlings() & BLACK_O_O))
        if (!pos.IsAttacked(E8, WHITE) && !pos.IsAttacked(F8, WHITE) && !pos.IsAttacked(G8, WHITE))
          Add(E8, G8, KB);

      if (!pos[D8] && !pos[C8] && !pos[B8] 
          && (pos.Castlings() & BLACK_O_O_O))
        if (!pos.IsAttacked(E8, WHITE) && !pos.IsAttacked(D8, WHITE) && !pos.IsAttacked(C8, WHITE))
          Add(E8, C8, KB);
    }
  }
}
void MoveList::GenCaptures(const Position& pos, bool genChecks)
{
  Clear();

  COLOR side = pos.Side();
  COLOR opp = side ^ 1;
  U64 targets = pos.BitsAll(opp);
  U64 occ = pos.BitsAll();
  U64 free = ~occ;
  U64 checksN = 0, checksB = 0, checksR = 0, checksQ = 0;

  FLD Kopp = pos.King(opp);
  if (genChecks)
  {
    checksN = BB_KNIGHT_ATTACKS[Kopp] & free;
    checksB = BishopAttacks(Kopp, occ) & free;
    checksR = RookAttacks(Kopp, occ) & free;
    checksQ = checksB | checksR;
  }
  
  U64 x, y;
  FLD from, to;
  PIECE piece, captured;

  int fwd = -8 + 16 * side;
  int seventh = 1 + 5 * side;

  piece = PW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    int row = Row(from);

    to = static_cast<FLD>(from + fwd);
    if (!pos[to])
    {
      if (row == seventh)
      {
        Add(from, to, piece, NOPIECE, QW | side);
        Add(from, to, piece, NOPIECE, RW | side);
        Add(from, to, piece, NOPIECE, BW | side);
        Add(from, to, piece, NOPIECE, NW | side);
      }
    }

    y = BB_PAWN_ATTACKS[from][side] & pos.BitsAll(opp);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];

      if (row == seventh)
      {
        Add(from, to, piece, captured, QW | side);
        Add(from, to, piece, captured, RW | side);
        Add(from, to, piece, captured, BW | side);
        Add(from, to, piece, captured, NW | side);        
      }
      else
        Add(from, to, piece, captured);
    }
  }

  to = pos.Ep();
  if (to != NF)
  {
    y = BB_PAWN_ATTACKS[to][opp] & pos.Bits(PW | side);
    while (y)
    {
      from = PopLSB(y);
      Add(from, to, piece, PW | opp);
    }
  }

  piece = NW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KNIGHT_ATTACKS[from] & (targets | checksN);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = BW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BishopAttacks(from, occ) & (targets | checksB);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = RW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = RookAttacks(from, occ) & (targets | checksR);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = QW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = QueenAttacks(from, occ) & (targets | checksQ);
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }

  piece = KW | side;
  x = pos.Bits(piece);
  while (x)
  {
    from = PopLSB(x);
    y = BB_KING_ATTACKS[from] & targets;
    while (y)
    {
      to = PopLSB(y);
      captured = pos[to];
      Add(from, to, piece, captured);
    }
  }
}
void MoveList::GenCheckEvasions(const Position& pos)
{
	Clear();

	COLOR side = pos.Side();
	COLOR opp = side ^ 1;
	U64 freeOrOpp = ~pos.BitsAll(side);
	U64 occ = pos.BitsAll();

	U64 x, y;
	FLD from, to;
	PIECE piece, captured;
	FLD K = pos.King(side);

	U64 attackers = pos.GetAttacks(K, opp, occ);
	U64 mask = attackers;
	while (attackers)
	{
		from = Bitboard::PopLSB(attackers);
		mask |= Bitboard::Between(from, K);
	}

	int fwd = -8 + 16 * side;
	int second = 6 - 5 * side;
	int seventh = 1 + 5 * side;

	piece = PW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		int row = Row(from);

		to = static_cast<FLD>(from + fwd);
		if (!pos[to])
		{
			if (row == second)
			{
				if (Bitboard::Single(to) & mask)
					Add(from, to, piece);

				to = static_cast<FLD>(to + fwd);
				if (!pos[to])
				{
					if (Bitboard::Single(to) & mask)
						Add(from, to, piece);
				}
			}
			else if (row == seventh)
			{
				if (Bitboard::Single(to) & mask)
				{
					Add(from, to, piece, NOPIECE, QW | side);
					Add(from, to, piece, NOPIECE, RW | side);
					Add(from, to, piece, NOPIECE, BW | side);
					Add(from, to, piece, NOPIECE, NW | side);
				}
			}
			else
			{
				if (Bitboard::Single(to) & mask)
					Add(from, to, piece);
			}
		}

		y = Bitboard::PawnAttacks(from, side) & pos.BitsAll(opp) & mask;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			captured = pos[to];

			if (row == seventh)
			{
				Add(from, to, piece, captured, QW | side);
				Add(from, to, piece, captured, RW | side);
				Add(from, to, piece, captured, BW | side);
				Add(from, to, piece, captured, NW | side);
			}
			else
				Add(from, to, piece, captured);
		}
	}

	to = pos.Ep();
	if (to != NF)
	{
		y = Bitboard::PawnAttacks(to, opp) & pos.Bits(PW | side);
		while (y)
		{
			from = Bitboard::PopLSB(y);
			Add(from, to, piece, PW | opp);
		}
	}

	piece = NW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		y = Bitboard::KnightAttacks(from) & freeOrOpp & mask;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			captured = pos[to];
			Add(from, to, piece, captured);
		}
	}

	piece = BW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		y = Bitboard::BishopAttacks(from, occ) & freeOrOpp & mask;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			captured = pos[to];
			Add(from, to, piece, captured);
		}
	}

	piece = RW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		y = Bitboard::RookAttacks(from, occ) & freeOrOpp & mask;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			captured = pos[to];
			Add(from, to, piece, captured);
		}
	}

	piece = QW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		y = Bitboard::QueenAttacks(from, occ) & freeOrOpp & mask;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			captured = pos[to];
			Add(from, to, piece, captured);
		}
	}

	piece = KW | side;
	x = pos.Bits(piece);
	while (x)
	{
		from = Bitboard::PopLSB(x);
		y = Bitboard::KingAttacks(from) & freeOrOpp;
		while (y)
		{
			to = Bitboard::PopLSB(y);
			if (!pos.IsAttacked(to, opp))
			{
				captured = pos[to];
				Add(from, to, piece, captured);
			}
		}
	}
}