Bitmap generation captures

на главную страницу


ВЗЯТИЯ И ПРЕВРАЩЕНИЯ ПЕШЕК

Приведем фрагмент структуры доски для того, что бы дальше было понятно, откуда мы берем переменные.

unsigned __int64 all_piece; все фигуры
unsigned __int64 all_white_piece; все белые фигуры
unsigned __int64 all_black_piece; все черные фигуры

битовые списки черных и белых фигур
для каждого класса фигур своя битовая доска.
unsigned __int64 white_piece[NAME];
unsigned __int64 black_piece[NAME];

NAME - это имя фигуры и оно принимает следующие значения:
0 - нет фигуры
1 - пешка
2 - конь
3 - слон
4 - ладья
5 - ферзь
6 - король

имя фигуры от координаты :
int white_name_from_coord[COORDINATE];
int black_name_from_coord[COORDINATE];
по ним можно моментально узнать, какая фигура на данном поле стоит.


Взятия короля и коня реализуются проще всего

Рассмотрим взятия белого короля.

// маска расположения белого короля
from_mask = bitboard->white_piece[6];
// находим координату фигуры (самый первый (для нашего отображения правый) установленный бит)
from = first_one(from_mask);
// находим маску взятий короля
captures_mask = (bitboard->all_black_piece & king_moves_masks[from]);

while (captures_mask !=0){
    // Заполняем список ходов
    to = first_one(captures_mask);
    list_capture_white(6,2,from,to,p,bitboard,list_surplus_moves);
    captures_mask = captures_mask & (captures_mask-1);
}//while (captures !=0){

Вначале нам нужно определить координату короля.
Для этого используем битовые списки белых фигур.
Прежде всего, выделяем нужную маску (король у нас находится под цифрой 6)
from_mask = bitboard->white_piece[6];
дальше находим координату фигуры (самый первый (для нашего отображения правый) установленный бит)
from = first_one(from_mask);
Для понимания нужно знать, что делает функция first_one().
Эта функция возвращает самый правый установленный бит.
Например:
first_one(...00001) = 0
first_one(...00010) = 1
first_one(10000...) = 63
полное описание данной функции приведу в отдельном пункте.

Далее находим маску взятий короля:
captures_mask = (bitboard->all_black_piece & king_moves_masks[from]);
У нас есть доска, в которой все черные фигуры представлены взведенными битами, и есть множество возможных ходов короля, которые тоже представлены взведенными битами. В результате применения операции логического и у нас остаются только совпадающие биты, т.е. это фигуры, которые может побить король.

Следует сказать, что _moves_masks[from] - это массив ходов короля в зависимости от расположения. Этот массив рассчитывается заранее. Такие массивы посчитаны для всех фигур. Я говорил об этом в разделе битовое представление доски.

Для иллюстрации принципа приведу очень упрощенный пример.

Допустим, король у нас в 1 бите, и может ходить в 0 и 2 бит:
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 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 0 0 0 0 0 0
1 k 1 0 0 0 0 0

а вражеские фигуры находятся в 2 и 3 бите:
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 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 0 0 0 0 0 0
0 0 1 1 0 0 0 0

5 = 0..0101 - ходы белого короля.
12 = 0..1100 - все черные фигуры.
& - используем операцию битового и которое оставляет 1, только если 1 присутствуют в обоих битах.
4 = 0..0100 - взятия белого короля
в итоге получили маску взятий белого короля (в примере это число 4)
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 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 0 0 0 0 0 0
0 0 1 0 0 0 0 0

дальше посредством функции first_one мы определим, что это 2 бит.
Т.е. король ходит с 1 бита на 2.

Заполняем список ходов.
while (captures_mask !=0){
    to = first_one(captures_mask);
    list_capture_white(6,2,from,to,p,bitboard,list_surplus_moves);
    captures_mask = captures_mask & (captures_mask-1);
}//while (captures !=0){

Для коня все аналогично.


Взятия слайдеров, т.е слона, ладьи, ферзя

Для слайдеров дела обстоят несколько сложнее. Причина в том, что на их пути к врагу могут стоять свои или вражеские фигуры.
Этот момент надо учитывать.

Рассмотрим генерацию взятий для ладьи.

from_mask = bitboard->white_piece[4];
while(from_mask != 0){
    from = first_one(from_mask);
    from_mask = from_mask & (from_mask-1);

    // смотрим в четырех различных направлениях
    // Генерируем ходы
    // луч вверх
    blocking_square_mask = (bitboard->all_piece) & rook_up_masks[from];
    if(blocking_square_mask !=0){
       blocking_coordinate = first_one(blocking_square_mask);
       captures_mask = bitboard->all_black_piece & move_masks[blocking_coordinate];
       // Заполняем список ходов
       if(captures_mask!=0)list_record_w(4,2,p,from,captures_mask,bitboard,list_surplus_moves);
   }//if(blocking_square_mask !=0){
   ......
Проиллюстрируем работу приведенного кода на примере.

Допустим, ладья находится во 2 бите, т.е. на поле C1 тогда всевозможные ходы вверх это массив вида
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 r 0 0 0 0 0

или число rook_up_masks[2] = 289360691352306688

допустим так же, что слон находится на поле С4 - это 26 бит, а конь на С6 - это 42
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 n 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 b 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 r 0 0 0 0 0

первое что мы делаем - это находим маску, содержащую блокированные биты:
blocking_square_mask = (bitboard->all_piece) & rook_up_masks[from];
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 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 0 0 0 0

Проверяем, и если она нулевая то взятий нет.

if(blocking_square_mask !=0){

}

Иначе, находим номер первого блокированного бита и генерируем маску ходов вверх:
blocking_coordinate = first_one(blocking_square_mask);
captures_mask = bitboard->all_black_piece & move_masks[blocking_coordinate];

Пишем взятие, только если есть взятия. Ведь блокировка может быть своей фигурой, тогда блок есть, а взятия нет.
(captures_mask!=0) list_record_w(4,2,p,from,captures_mask,bitboard,list_surplus_moves);

Тут есть важный момент, если это луч вверх, то используем first_one, а если луч вниз, то last_one
Дело в том, что блокированных битов может быть несколько, а нам нужен первый по лучу от фигуры
В итоге маска взятий такова.
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 0 0 0 0 0 0 0
0 0 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 0 0 0 0

лучи вниз (last_one), влево (last_one) и вправо (first_one) аналогично.

Так же считаются взятия для слона:
лучи вверх – вправо (first_one), вверх – влево (first_one), вниз – вправо (last_one), вниз – влево (last_one).

Взятия и превращения пешки

from_mask = bitboard->white_piece[1];
while(from_mask != 0){
  from = first_one(from_mask);
  //выделяем одну пешку
  one_pawn_mask = from_mask & move_masks[from];
  from_mask = from_mask & (from_mask-1);

  Если у нас пешка на предпоследней горизонтали, то считаем ходы и взятия с превращением иначе простые взятия пешкой.
  if ( from / 8 == 6 ){
   // считаем ходы с превращением и взятия с превращением
   // 1 находим простые ходы белой пешки на одно поле вперед
   move_conversion_mask = (one_pawn_mask << 8) & (~(bitboard->all_piece));
   // взятия с превращением
   captures_conversion_mask = pawn_capture_white[from] & bitboard->all_black_piece;

   Пишем ходы с превращением.
   while (move_conversion_mask != 0){
       to = first_one(move_conversion_mask);
       move_conversion_mask = move_conversion_mask & (move_conversion_mask-1);

      // превращение пешки
      // превращение в ферзь 15,превращение в ладью 14,превращение в слона 13,превращение в коня 12
      list_record_os(1,15,p,from,to,0,list_surplus_moves);
      list_record_os(1,14,p,from,to,0,list_surplus_moves);
      list_record_os(1,13,p,from,to,0,list_surplus_moves);
      list_record_os(1,12,p,from,to,0,list_surplus_moves);

     #if KONTROL_B
         KONTROL_move(&from,&to,&p);
     #endif//KONTROL_B
  }//while (move_conversion_mask != 0){

   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

   Пишем взятия с превращением.
   while (captures_conversion_mask != 0){
        to = first_one(captures_conversion_mask);
        captures_conversion_mask = captures_conversion_mask & (captures_conversion_mask-1);

       // превращение пешки с взятием
       // превращение в ферзь 25,превращение в ладью 24,превращение в слона 23,превращение в коня 22
       list_record_os(1,25,p,from,to,bitboard->black_name_from_coord[to],list_surplus_moves);
       list_record_os(1,24,p,from,to,bitboard->black_name_from_coord[to],list_surplus_moves);
       list_record_os(1,23,p,from,to,bitboard->black_name_from_coord[to],list_surplus_moves);
       list_record_os(1,22,p,from,to,bitboard->black_name_from_coord[to],list_surplus_moves);

      #if KONTROL_B
        KONTROL_captures_W(bitboard,&from,&to,&p,120);
     #endif//KONTROL_B
  }//while (captures_conversion_mask != 0){

}else {
   // считаем взятия пешкой
   captures_mask = pawn_capture_white[from] & bitboard->all_black_piece;
   Пишем простые взятия.
   while (captures_mask != 0){
       to = first_one(captures_mask);
       list_capture_white(1,2,from,to,p,bitboard,list_surplus_moves);
       captures_mask = captures_mask & (captures_mask-1);
   }//while (captures_mask != 0){
}//if ( from / 8 == 6 ){


//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 4 находим взятия на проходе
 if(bitboard->taking_passage_yes == 1){
  if( from / 8 == 4 ){
      to = 8 * bitboard->taking_passage_y + bitboard->taking_passage_x;

     if( ((from - to) == -9) && (from % 8 != 7) ){
          list_record_os(1,5,p,from,to,bitboard->black_name_from_coord[to - 8],list_surplus_moves);

         #if KONTROL_B
             to = to - 8;
             KONTROL_captures_W(bitboard,&from,&to,&p,130);
         #endif//KONTROL_B
     }//if ( ((from - to) == -9) && (from % 8 != 7) ){

    if( ((from - to) == -7) && (from % 8 != 0) ){
        list_record_os(1,5,p,from,to,bitboard->black_name_from_coord[to - 8],list_surplus_moves);

       #if KONTROL_B
          to = to - 8;
          KONTROL_captures_W(bitboard,&from,&to,&p,130);
      #endif//KONTROL_B
    }//if ( ((from - to) == -7) && (from % 8 != 0) ){
  }//if ( from / 8 == 4 ){
 }//if(bitboard->taking_passage_yes == 1){

}//while(from_mask != 0){