Ключевое слово
30 | 05 | 2024
Новости Библиотеки
Шахматы Онлайн
Welcome, Guest
Username: Password: Remember me

TOPIC: Bitboard в программировании шахмат №2

Bitboard в программировании шахмат №2 23 Янв 2023 19:57 #121

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
10 урок - нахождение индекса младшего значащего бита и возвращение его координаты в шахматной нотации
program bbc;

{$APPTYPE CONSOLE}

uses
  SysUtils,Windows,TypInfo;
type
    U64 = UInt64;
    TBoard_squares = (
    a8, b8, c8, d8, e8, f8, g8, h8,
    a7, b7, c7, d7, e7, f7, g7, h7,
    a6, b6, c6, d6, e6, f6, g6, h6,
    a5, b5, c5, d5, e5, f5, g5, h5,
    a4, b4, c4, d4, e4, f4, g4, h4,
    a3, b3, c3, d3, e3, f3, g3, h3,
    a2, b2, c2, d2, e2, f2, g2, h2,
    a1, b1, c1, d1, e1, f1, g1, h1
    );
    TSide = (white, black);
    //Первый индекс обозначает номер строки в матрице, второй индекс – номер столбца
    TPawn_attacks=array[TSide,TBoard_squares] of U64;
    TChip_attacks=array[TBoard_squares] of U64;
var
 bitboard:U64=0;
 block:U64=0;
 // pawn attacks table [side][square]
 pawn_attacks:TPawn_attacks;
 // knight attacks table [square]
 knight_attacks:TChip_attacks;
 // king attacks table [square]
 king_attacks:TChip_attacks;
 square:TBoard_squares;
const
{/*
        not A file
  8  0 1 1 1 1 1 1 1
  7  0 1 1 1 1 1 1 1
  6  0 1 1 1 1 1 1 1
  5  0 1 1 1 1 1 1 1
  4  0 1 1 1 1 1 1 1
  3  0 1 1 1 1 1 1 1
  2  0 1 1 1 1 1 1 1
  1  0 1 1 1 1 1 1 1
     a b c d e f g h
        not H file
  8  1 1 1 1 1 1 1 0
  7  1 1 1 1 1 1 1 0
  6  1 1 1 1 1 1 1 0
  5  1 1 1 1 1 1 1 0
  4  1 1 1 1 1 1 1 0
  3  1 1 1 1 1 1 1 0
  2  1 1 1 1 1 1 1 0
  1  1 1 1 1 1 1 1 0
     a b c d e f g h
       not HG file
  8  1 1 1 1 1 1 0 0
  7  1 1 1 1 1 1 0 0
  6  1 1 1 1 1 1 0 0
  5  1 1 1 1 1 1 0 0
  4  1 1 1 1 1 1 0 0
  3  1 1 1 1 1 1 0 0
  2  1 1 1 1 1 1 0 0
  1  1 1 1 1 1 1 0 0
     a b c d e f g h
       not AB file
  8  0 0 1 1 1 1 1 1
  7  0 0 1 1 1 1 1 1
  6  0 0 1 1 1 1 1 1
  5  0 0 1 1 1 1 1 1
  4  0 0 1 1 1 1 1 1
  3  0 0 1 1 1 1 1 1
  2  0 0 1 1 1 1 1 1
  1  0 0 1 1 1 1 1 1
     a b c d e f g h
*/}

// not A file constant
not_a_file:U64 = $FEFEFEFEFEFEFEFE;//18374403900871474942;
// not H file constant
not_h_file:U64 = $7F7F7F7F7F7F7F7F;//9187201950435737471;
// not HG file constant
not_hg_file:U64 =$3F3F3F3F3F3F3F3F;//4557430888798830399;
// not AB file constant
not_ab_file:U64 =$FCFCFCFCFCFCFCFC;//18229723555195321596;
square_to_coordinates: array [0..63]  of  string =  (
    'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8',
    'a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7',
    'a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6',
    'a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5',
    'a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4',
    'a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3',
    'a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2',
    'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1'
);
{/**********************************\
 ==================================
 
          Bit manipulations
 
 ==================================
\**********************************/}
// set/get/pop
function get_bit(bb:U64;const sq:integer):integer;
begin
get_bit:=(bb shr sq) and 1;
end;
procedure set_bit(var bb:U64;const sq:TBoard_squares);
begin
bb:=bb or ($8000000000000000 shr (63-Ord(sq)));
end;
procedure pop_bit(var bb:U64;const sq:TBoard_squares);
begin
if get_bit(bb,Ord(sq))>0 then bb:=bb xor ($8000000000000000 shr (63-Ord(sq)));
end;
// count bits within a bitboard (Brian Kernighan's way)
function count_bits(bb:U64):integer;
var
count:integer;
begin
    // bit counter
    count := 0;
    // consecutively reset least significant 1st bit
     while bb>0
     do  begin
         // increment count
         Inc(count);
         // reset least significant 1st bit
         bb := bb and (bb - 1);
         end;
count_bits:=count;
end;
// get least significant 1st bit index
function  get_ls1b_index(bb:U64):integer;
begin
  // make sure bitboard is not 0
 if bb<>0 then
 // count trailing bits before LS1B
 result:=count_bits((bb and (-bb))-1)
 // return illegal index
 else result:=-1;
end;
{/**********************************\
 ==================================
 
           Input & Output
 
 ==================================
\**********************************/}
// print bitboard
procedure print_bitboard(bb:U64);
var
rank_,file_,sq:integer;
begin
Writeln('');
  // loop over board ranks
  for rank_ := 0 to 7 do  begin
        // loop over board files
        for file_ := 0 to 7 do  begin
           // convert file & rank into square index
           sq:=rank_*8 + file_;
           //// print ranks
           if file_ = 0 then begin
           Write(8 - rank_);Write(' ');
           end;
           Write(' ');
           // print bit state (either 1 or 0)
           Write(get_bit(bb,sq));
        end;
        // print new line every rank
        Writeln('');
  end;
  // print new line
  Writeln('');
  // print board files
  Writeln('   a b c d e f g h');
  Writeln('');
  // print bitboard as unsigned decimal number
  Write('bitboard = ',bb);
  Writeln('');
end;
{/**********************************\
 ==================================

              Attacks

 ==================================
\**********************************/}
// generate pawn attacks
function mask_pawn_attacks(side:TSide;square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // white pawns
    if (side=white) then begin
      if ((bitboard shr 7) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 7);
      if ((bitboard shr 9) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 9);
    end
    // black pawns
    else  begin
      if ((bitboard shl 7) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 7);
      if ((bitboard shl 9) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 9);
    end;
// return attack map
mask_pawn_attacks:=attacks;
end;
// generate knight attacks
function  mask_knight_attacks(square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // generate knight attacks
    if ((bitboard shr 17) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 17);
    if ((bitboard shr 15) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 15);
    if ((bitboard shr 10) and not_hg_file)>0 then  attacks:=attacks or (bitboard shr 10);
    if ((bitboard shr 6) and not_ab_file)>0 then  attacks:=attacks or (bitboard shr 6);
    if ((bitboard shl 17) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 17);
    if ((bitboard shl 15) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 15);
    if ((bitboard shl 10) and not_ab_file)>0 then  attacks:=attacks or (bitboard shl 10);
    if ((bitboard shl 6) and not_hg_file)>0 then  attacks:=attacks or (bitboard shl 6);
// return attack map
mask_knight_attacks:=attacks;
end;
// generate king attacks
function  mask_king_attacks(square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // generate king attacks
    if (bitboard shr 8)>0 then  attacks:=attacks or (bitboard shr 8);
    if ((bitboard shr 9) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 9);
    if ((bitboard shr 1) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 1);
    if ((bitboard shr 7) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 7);
    if (bitboard shl 8)>0 then  attacks:=attacks or (bitboard shl 8);
    if ((bitboard shl 9) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 9);
    if ((bitboard shl 1) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 1);
    if ((bitboard shl 7) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 7);
// return attack map
mask_king_attacks:=attacks;
end;
//урок 6-masking relevant bishop occupancy bits to form a key for MAGIC BITBOARDS
// mask bishop attacks
function   mask_bishop_attacks(square:TBoard_squares):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // mask relevant bishop occupancy bits
    f:=tf+1;
    for r:=tr+1 to 6 do begin
       if f>6 then break;
       attacks := attacks or (n shl (r*8+f));
       Inc(f);
    end;
    f:=tf+1;
    for r:=tr-1 downto 1 do begin
       if f>6 then break;
       attacks := attacks or (n shl (r*8+f));
       Inc(f);
    end;
    f:=tf-1;
    for r:=tr+1 to 6 do begin
       if f<1 then break;
       attacks := attacks or (n shl (r*8+f));
       Dec(f);
    end;
    f:=tf-1;
    for r:=tr-1 downto 1 do begin
       if f<1 then break;
       attacks := attacks or (n shl (r*8+f));
       Dec(f);
    end;
// return attack map
mask_bishop_attacks:=attacks;
end;
//урок 7-masking relevant ROOK OCCUPANCY BITS to form a key for MAGIC BITBOARDS
// mask rook attacks
function   mask_rook_attacks(square:TBoard_squares):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // mask relevant bishop occupancy bits
    for r:=tr+1 to 6 do attacks := attacks or (n shl (r*8+tf));
    for r:=tr-1 downto 1 do attacks := attacks or (n shl (r*8+tf));
    for f:=tf+1 to 6 do attacks := attacks or (n shl (tr*8+f));
    for f:=tf-1 downto 1 do attacks := attacks or (n shl (tr*8+f));
// return attack map
mask_rook_attacks:=attacks;
end;
//урок 8-generating SLIDER PIECES ATTACKS on the fly for MAGIC BITBOARD purposes
// generate bishop attacks on the fly
function  bishop_attacks_on_the_fly(square:TBoard_squares;blk:U64):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // generate bishop atacks
    f:=tf+1;
    for r:=tr+1 to 7 do begin
       if f>7 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Inc(f);
    end;
        f:=tf+1;
    for r:=tr-1 downto 0 do begin
       if f>7 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Inc(f);
    end;
    f:=tf-1;
    for r:=tr+1 to 7 do begin
       if f<0 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Dec(f);
    end;
    f:=tf-1;
    for r:=tr-1 downto 0 do begin
       if f<0 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Dec(f);
    end;
// return attack map
bishop_attacks_on_the_fly:=attacks;
end;
// generate rook attacks on the fly
function  rook_attacks_on_the_fly(square:TBoard_squares;blk:U64):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // generate rook attacks
    for r:=tr+1 to 7 do begin
    attacks := attacks or (n shl (r*8+tf));
    if ((n shl (r*8+tf)) and blk)>0 then  break;
    end;
    for r:=tr-1 downto 0 do begin
    attacks := attacks or (n shl (r*8+tf));
    if ((n shl (r*8+tf)) and blk)>0 then  break;
    end;
    for f:=tf+1 to 7 do begin
    attacks := attacks or (n shl (tr*8+f));
    if ((n shl (tr*8+f)) and blk)>0 then  break;
    end;
    for f:=tf-1 downto 0 do begin
    attacks := attacks or (n shl (tr*8+f));
    if ((n shl (tr*8+f)) and blk)>0 then  break;
    end;
// return attack map
rook_attacks_on_the_fly:=attacks;
end;
// init leaper pieces attacks
procedure init_leapers_attacks();
var
square:TBoard_squares;
begin
    // loop over 64 board squares
    for square := a8 to h1 do  begin
//урок 3-generating pre-calculated PAWN ATTACK tables
       // init pawn attacks
       pawn_attacks[white][square] := mask_pawn_attacks(white,square);
       pawn_attacks[black][square] := mask_pawn_attacks(black,square);
//урок 4-generating pre-calculated KNIGHT ATTACK table
       // init knight attacks
       knight_attacks[square] := mask_knight_attacks(square);
//урок 5-generating pre-calculated KING ATTACK tables
       // init king attacks
       king_attacks[square] := mask_king_attacks(square);
    end;
end;
{/**********************************\
 ==================================

             Main driver
 
 ==================================
\**********************************/}
 begin
  //Переключение окна консоли на кодовую страницу CP1251 (Win-1251).
  //Если после переключения русские буквы показываются неверно,
  //следует открыть системное меню консольного окна - щелчком мыши в левом
  //верхнем углу окна консоли. И выбрать:
  //Свойства - закладка "Шрифт" - выбрать шрифт: "Lucida Console".
  SetConsoleCP(1251);
  SetConsoleOutputCP(1251);
// ==================================
  init_leapers_attacks();
  block:=4512464976740352;
  print_bitboard(block);
  square:=TBoard_squares(get_ls1b_index(block));
  Write('get_ls1b_index:',get_ls1b_index(block));
  Writeln('  coordinate:',square_to_coordinates[Ord(square)]);
  set_bit(bitboard,square);
  print_bitboard(bitboard);
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;
end.

Bitboard в программировании шахмат №2 24 Янв 2023 09:47 #122

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Разобрался с 11 уроком - Bitboard CHESS ENGINE in C: populating OCCUPANCY sets to multiply them later by MAGIC NUMBERS.
Пока это все подготовка к реализации Magic Bitboards
В этом уроке описывается функция нызываемая - начальными занятиями (set_occupancy).
По сути это комбинация всех различных расположений фигур на линии атаки скользящей фигуры (ладьи, слона).







8/8/8/8/8/8/8/R7
Например при ладье на a1 и ее атаках по линиям A2-A7 и B1-G1 (края доски не учитываются), теоретически эти поля могут быть заняты другими фигурами в различных комбинациях. По сути мы имеем дело с 6 клетками по вертикали и 6 по горизонали.
6 клеток это число с 6 включенными битами, соответствует числу 63.
Правило умножения (основная формула комбинаторики)
Общее число N способов, которыми можно выбрать по одному элементу из каждой группы и расставить их в определенном порядке (то есть получить упорядоченную совокупность a,b,c,d), равно:
N=n1*n2*n3* ... nk
T.e. в нашел случае при ладье на a1
N=64*64=4096 различных комбинаций занятости этих линий.
В двоичном виде это число выглядит так

41.jpg


По сути пробегая в цикле от нуля до 4095 мы получим все эти различные комбинации перестановок
block:=mask_rook_attacks(a1);
  print_bitboard(block);
  for i:=0 to 4095 do begin
  block:=mask_rook_attacks(a1);
  bitboard:=set_occupancy(i,count_bits(block),block);
  print_bitboard(bitboard);
  Readln;
  end;
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;
// make sure occupancy is on board
               if (index and (1 shl count))>0 then
                   occupancy:=occupancy or (n shl integer(square_));
Index -это как раз число перестановок (в конкретном случае - 4096)
Т.е. пробигая по вариантам занятости for i:=0 to 4095 при условии - i and (1 shl count) мы находим установленный бит и и получаем конкретную занятость для i.
Короче вот реализация на Делфи
// set occupancies
//перебираем по очереди биты в attack_mask
function set_occupancy(index,bits_in_mask:integer;var attack_mask:U64):U64;
var
occupancy,n:U64;
count:integer;
square_:TBoard_squares;
begin
n:=1;
// occupancy map
occupancy:=0;
            // loop over the range of bits within attack mask
            for count:=0 to bits_in_mask-1 do begin
               // get LS1B index of attacks mask
               square_:=TBoard_squares(get_ls1b_index(attack_mask));
               // pop LS1B in attack map
               pop_bit(attack_mask,square_);
               // make sure occupancy is on board
               if (index and (n shl count))>0 then
                   occupancy:=occupancy or (n shl integer(square_));
            end;
set_occupancy:=occupancy;
end;
Last Edit: 24 Янв 2023 10:02 by alexlaw.

Bitboard в программировании шахмат №2 24 Янв 2023 11:08 #123

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
12 урок - Bitboard CHESS ENGINE in C: generating relevant OCCUPANCY BIT COUNT lookup tables for sliding pieces

Просто заполнение таблицы количеста атакуемых клеток скользящих фигур из каждой клетки доски
// bishop relevant occupancy bit count for every square on board
bishop_relevant_bits: array [0..63]  of  integer =(
    6, 5, 5, 5, 5, 5, 5, 6,
    5, 5, 5, 5, 5, 5, 5, 5, 
    5, 5, 7, 7, 7, 7, 5, 5, 
    5, 5, 7, 9, 9, 7, 5, 5, 
    5, 5, 7, 9, 9, 7, 5, 5, 
    5, 5, 7, 7, 7, 7, 5, 5, 
    5, 5, 5, 5, 5, 5, 5, 5, 
    6, 5, 5, 5, 5, 5, 5, 6
);

// rook relevant occupancy bit count for every square on board
rook_relevant_bits: array [0..63]  of  integer =(
    12, 11, 11, 11, 11, 11, 11, 12, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    12, 11, 11, 11, 11, 11, 11, 12
);
Writeln('bishop_relevant_bits');
  for square := a8 to h1 do  begin
    if (((integer(square) mod 8)=0) and (square > a8)) then  Writeln('');
     Write(count_bits(mask_bishop_attacks(square))); Write(' ');
  end;
  Writeln('');
  Writeln('rook_relevant_bits');
    for square := a8 to h1 do  begin
    if (((integer(square) mod 8)=0) and (square > a8)) then  Writeln('');
     Write(count_bits(mask_rook_attacks(square))); Write(' ');
  end;
  Writeln('');
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;

42.jpg

Bitboard в программировании шахмат №2 25 Янв 2023 05:11 #124

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Уроки 13 и 14
13.Bitboard CHESS ENGINE in C: implementing pseudo RANDOM NUMBER generator using XORSHIFT32 algorithm
14.Bitboard CHESS ENGINE in C: generating MAGIC NUMBER candidates

Макс рассказывает как сгенерировать числа - кандитаты в магические числа.
По сути - это псевдослучайные числа.
И самое интересное, далее он расскажет, как их использовать в качестве магических чисел.
{/**********************************\
 ==================================
 
           Random numbers
 
 ==================================
\**********************************/}
// generate 32-bit pseudo legal numbers
function  get_random_U32_number():cardinal;
begin
// XOR shift algorithm
stateU32:=stateU32 xor (stateU32 shl 13);
stateU32:=stateU32 xor (stateU32 shr 17);
stateU32:=stateU32 xor (stateU32 shl 5);
get_random_U32_number:=stateU32;
end;
// generate 64-bit pseudo legal numbers
function  get_random_U64_number():U64;
var
// define 4 random numbers
n1,n2,n3,n4:U64;
begin
n1:=0;n2:=0;n3:=0; n4:=0;
// init random numbers slicing 16 bits from MS1B side
n1:=n1 or (get_random_U32_number() and $FFFF);
n2:=n2 or (get_random_U32_number() and $FFFF);
n3:=n3 or (get_random_U32_number() and $FFFF);
n4:=n4 or (get_random_U32_number() and $FFFF);
// return random number
get_random_U64_number:=n1 or (n2 shl 16) or (n3 shl 32) or (n4 shl 48);
end;
// generate magic number candidate
function generate_magic_number():U64;
begin
  result:=get_random_U64_number() and get_random_U64_number() and get_random_U64_number();
end;

Хотя эти числа всегда одни и те же, но раз это работает, то делаем так же.

43.jpg


44.jpg

Bitboard в программировании шахмат №2 25 Янв 2023 13:24 #125

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Попытка объяснить Magic Bitboard

Bitboard в программировании шахмат №2 27 Янв 2023 12:53 #126

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Урок 15.Bitboard CHESS ENGINE in C: generating MAGIC NUMBERS via brute force trial and error method.
Разобрался с этим уроком - генерация магических чисел.
Попробую рассказать свое понимание этого.
Итак, какие исходные данные есть у нас.
1. Позиция дальнобойной фигуры (например ладья на a1)
TBoard_squares = (
a8, b8, c8, d8, e8, f8, g8, h8,
a7, b7, c7, d7, e7, f7, g7, h7,
a6, b6, c6, d6, e6, f6, g6, h6,
a5, b5, c5, d5, e5, f5, g5, h5,
a4, b4, c4, d4, e4, f4, g4, h4,
a3, b3, c3, d3, e3, f3, g3, h3,
a2, b2, c2, d2, e2, f2, g2, h2,
a1, b1, c1, d1, e1, f1, g1, h1
);
2. Количество атакуемых клеток из этой позиции при отсутствии блокирующих фигур (края доски не учитываются)
(ладья на a1 атакует 6 клеток по горизонтали, 6 по вертикали: всего 12)
// rook relevant occupancy bit count for every square on board
rook_relevant_bits: array [0..63] of integer =(
12, 11, 11, 11, 11, 11, 11, 12,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
11, 10, 10, 10, 10, 10, 10, 11,
12, 11, 11, 11, 11, 11, 11, 12
);

Производные от первоначальных данных
1.битбоард атаки (ладьи) этих 12 клеток
attack_mask:=mask_bishop_attacks(square)
2. Количество перестановок блокирующих фигур на атакуемых ладьей полях
occupancy_indicies:integer;
- 64*64
- 2 в степени 12
- 1 << 12
occupancy_indicies:=1 shl relevant_bits;
3.Комбинации занятости блокирующих фигур
occupancies:array[0..4095] of U64;
4.Самое важное это атаки с учетом блокирующих фигур
// init attack tables
attacks:array[0..4095] of U64;

Вроде бы все прекрасно - эти атаки нам и нужны в идеале.
Но есть одно большое НО.
Чтобы найти их в таблице array[0..4095], придется долго и упорно ее перелапачивать.

Умные люди решили проблему так -
Придумать такую хэш функция, чтобы с помощью простого ключа быстро находить нужные атаки в таблице.
Ключ, это и есть - магическое число с простыми манипуляциями с ним.
Это как подойти к реальной двери, глянуть на скважину замка, достать отмычку, туда сюда ее изогнуть на глаз и пробовать открыть замок.

Этот урок Макса, как раз и есть, описание способа, гнуть отмычку туда сюда , чтобы получить ключ.
Способ такой.
1.Создается массив
// init used attacks
used_attacks:array[0..4095] of U64;
Инициализируется 0.
FillChar(used_attacks, 4096*SizeOf(UInt64), n); - делфи
memset(used_attacks, 0ULL, sizeof(used_attacks)); - СИ
2.U64 magic_number - генерируем 64 битные случайные числа
3.Подставляем ключ в хэш функцию
magic_index := integer((occupancies[index] * magic_number) shr (64 - relevant_bits)); - делфи
int magic_index = (int)((occupancies[index] * magic_number) >> (64 - relevant_bits)); - Си

Пробуем полученный ключ - если уже был другой ключ, то это коллизия ( ключ выбрасываем)

Как то так в моем понимании.

Bitboard в программировании шахмат №2 27 Янв 2023 12:54 #127

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
На языке Си (Макс)
/**********************************\
 ==================================

             Didactic
       BITBOARD CHESS ENGINE

                by

         Code Monkey King

 ==================================
\**********************************/

// system headers
#include <stdio.h>
#include <string.h>

// define bitboard data type
#define U64 unsigned long long

// board squares
enum {
    a8, b8, c8, d8, e8, f8, g8, h8,
    a7, b7, c7, d7, e7, f7, g7, h7,
    a6, b6, c6, d6, e6, f6, g6, h6,
    a5, b5, c5, d5, e5, f5, g5, h5,
    a4, b4, c4, d4, e4, f4, g4, h4,
    a3, b3, c3, d3, e3, f3, g3, h3,
    a2, b2, c2, d2, e2, f2, g2, h2,
    a1, b1, c1, d1, e1, f1, g1, h1
};

// sides to move (colors)
enum { white, black };

// bishop and rook
enum { rook, bishop };

// convert squares to coordinates
const char *square_to_coordinates[] = {
    "a8", "b8", "c8", "d8", "e8", "f8", "g8", "h8",
    "a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7",
    "a6", "b6", "c6", "d6", "e6", "f6", "g6", "h6",
    "a5", "b5", "c5", "d5", "e5", "f5", "g5", "h5",
    "a4", "b4", "c4", "d4", "e4", "f4", "g4", "h4",
    "a3", "b3", "c3", "d3", "e3", "f3", "g3", "h3",
    "a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2",
    "a1", "b1", "c1", "d1", "e1", "f1", "g1", "h1",
};


/**********************************\
 ==================================

           Random numbers

 ==================================
\**********************************/

// pseudo random number state
unsigned int random_state = 1804289383;

// generate 32-bit pseudo legal numbers
unsigned int get_random_U32_number()
{
    // get current state
    unsigned int number = random_state;

    // XOR shift algorithm
    number ^= number << 13;
    number ^= number >> 17;
    number ^= number << 5;

    // update random number state
    random_state = number;

    // return random number
    return number;
}

// generate 64-bit pseudo legal numbers
U64 get_random_U64_number()
{
    // define 4 random numbers
    U64 n1, n2, n3, n4;

    // init random numbers slicing 16 bits from MS1B side
    n1 = (U64)(get_random_U32_number()) & 0xFFFF;
    n2 = (U64)(get_random_U32_number()) & 0xFFFF;
    n3 = (U64)(get_random_U32_number()) & 0xFFFF;
    n4 = (U64)(get_random_U32_number()) & 0xFFFF;

    // return random number
    return n1 | (n2 << 16) | (n3 << 32) | (n4 << 48);
}

// generate magic number candidate
U64 generate_magic_number()
{
    return get_random_U64_number() & get_random_U64_number() & get_random_U64_number();
}


/**********************************\
 ==================================

          Bit manipulations

 ==================================
\**********************************/

// set/get/pop bit macros
#define set_bit(bitboard, square) (bitboard |= (1ULL << square))
#define get_bit(bitboard, square) (bitboard & (1ULL << square))
#define pop_bit(bitboard, square) (get_bit(bitboard, square) ? bitboard ^= (1ULL << square) : 0)

// count bits within a bitboard (Brian Kernighan's way)
static inline int count_bits(U64 bitboard)
{
    // bit counter
    int count = 0;

    // consecutively reset least significant 1st bit
    while (bitboard)
    {
        // increment count
        count++;

        // reset least significant 1st bit
        bitboard &= bitboard - 1;
    }

    // return bit count
    return count;
}

// get least significant 1st bit index
static inline int get_ls1b_index(U64 bitboard)
{
    // make sure bitboard is not 0
    if (bitboard)
    {
        // count trailing bits before LS1B
        return count_bits((bitboard & -bitboard) - 1);
    }

    //otherwise
    else
        // return illegal index
        return -1;
}

/**********************************\
 ==================================

           Input & Output

 ==================================
\**********************************/

// print bitboard
void print_bitboard(U64 bitboard)
{
    printf("\n");

    // loop over board ranks
    for (int rank = 0; rank < 8; rank++)
    {
        // loop over board files
        for (int file = 0; file < 8; file++)
        {
            // convert file & rank into square index
            int square = rank * 8 + file;

            // print ranks
            if (!file)
                printf("  %d ", 8 - rank);

            // print bit state (either 1 or 0)
            printf(" %d", get_bit(bitboard, square) ? 1 : 0);

        }

        // print new line every rank
        printf("\n");
    }

    // print board files
    printf("\n     a b c d e f g h\n\n");

    // print bitboard as unsigned decimal number
    printf("     Bitboard: %llud\n\n", bitboard);
}


/**********************************\
 ==================================

              Attacks

 ==================================
\**********************************/

/*
        not A file
  8  0 1 1 1 1 1 1 1
  7  0 1 1 1 1 1 1 1
  6  0 1 1 1 1 1 1 1
  5  0 1 1 1 1 1 1 1
  4  0 1 1 1 1 1 1 1
  3  0 1 1 1 1 1 1 1
  2  0 1 1 1 1 1 1 1
  1  0 1 1 1 1 1 1 1
     a b c d e f g h
        not H file

  8  1 1 1 1 1 1 1 0
  7  1 1 1 1 1 1 1 0
  6  1 1 1 1 1 1 1 0
  5  1 1 1 1 1 1 1 0
  4  1 1 1 1 1 1 1 0
  3  1 1 1 1 1 1 1 0
  2  1 1 1 1 1 1 1 0
  1  1 1 1 1 1 1 1 0
     a b c d e f g h
       not HG file
  8  1 1 1 1 1 1 0 0
  7  1 1 1 1 1 1 0 0
  6  1 1 1 1 1 1 0 0
  5  1 1 1 1 1 1 0 0
  4  1 1 1 1 1 1 0 0
  3  1 1 1 1 1 1 0 0
  2  1 1 1 1 1 1 0 0
  1  1 1 1 1 1 1 0 0
     a b c d e f g h
       not AB file
  8  0 0 1 1 1 1 1 1
  7  0 0 1 1 1 1 1 1
  6  0 0 1 1 1 1 1 1
  5  0 0 1 1 1 1 1 1
  4  0 0 1 1 1 1 1 1
  3  0 0 1 1 1 1 1 1
  2  0 0 1 1 1 1 1 1
  1  0 0 1 1 1 1 1 1
     a b c d e f g h
*/

// not A file constant
const U64 not_a_file = 18374403900871474942ULL;

// not H file constant
const U64 not_h_file = 9187201950435737471ULL;

// not HG file constant
const U64 not_hg_file = 4557430888798830399ULL;

// not AB file constant
const U64 not_ab_file = 18229723555195321596ULL;

// bishop relevant occupancy bit count for every square on board
const int bishop_relevant_bits[64] = {
    6, 5, 5, 5, 5, 5, 5, 6,
    5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 7, 7, 7, 7, 5, 5,
    5, 5, 7, 9, 9, 7, 5, 5,
    5, 5, 7, 9, 9, 7, 5, 5,
    5, 5, 7, 7, 7, 7, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5,
    6, 5, 5, 5, 5, 5, 5, 6
};

// rook relevant occupancy bit count for every square on board
const int rook_relevant_bits[64] = {
    12, 11, 11, 11, 11, 11, 11, 12,
    11, 10, 10, 10, 10, 10, 10, 11,
    11, 10, 10, 10, 10, 10, 10, 11,
    11, 10, 10, 10, 10, 10, 10, 11,
    11, 10, 10, 10, 10, 10, 10, 11,
    11, 10, 10, 10, 10, 10, 10, 11,
    11, 10, 10, 10, 10, 10, 10, 11,
    12, 11, 11, 11, 11, 11, 11, 12
};

// rook magic numbers
U64 rook_magic_numbers[64] = {
    0x8a80104000800020ULL,
    0x140002000100040ULL,
    0x2801880a0017001ULL,
    0x100081001000420ULL,
    0x200020010080420ULL,
    0x3001c0002010008ULL,
    0x8480008002000100ULL,
    0x2080088004402900ULL,
    0x800098204000ULL,
    0x2024401000200040ULL,
    0x100802000801000ULL,
    0x120800800801000ULL,
    0x208808088000400ULL,
    0x2802200800400ULL,
    0x2200800100020080ULL,
    0x801000060821100ULL,
    0x80044006422000ULL,
    0x100808020004000ULL,
    0x12108a0010204200ULL,
    0x140848010000802ULL,
    0x481828014002800ULL,
    0x8094004002004100ULL,
    0x4010040010010802ULL,
    0x20008806104ULL,
    0x100400080208000ULL,
    0x2040002120081000ULL,
    0x21200680100081ULL,
    0x20100080080080ULL,
    0x2000a00200410ULL,
    0x20080800400ULL,
    0x80088400100102ULL,
    0x80004600042881ULL,
    0x4040008040800020ULL,
    0x440003000200801ULL,
    0x4200011004500ULL,
    0x188020010100100ULL,
    0x14800401802800ULL,
    0x2080040080800200ULL,
    0x124080204001001ULL,
    0x200046502000484ULL,
    0x480400080088020ULL,
    0x1000422010034000ULL,
    0x30200100110040ULL,
    0x100021010009ULL,
    0x2002080100110004ULL,
    0x202008004008002ULL,
    0x20020004010100ULL,
    0x2048440040820001ULL,
    0x101002200408200ULL,
    0x40802000401080ULL,
    0x4008142004410100ULL,
    0x2060820c0120200ULL,
    0x1001004080100ULL,
    0x20c020080040080ULL,
    0x2935610830022400ULL,
    0x44440041009200ULL,
    0x280001040802101ULL,
    0x2100190040002085ULL,
    0x80c0084100102001ULL,
    0x4024081001000421ULL,
    0x20030a0244872ULL,
    0x12001008414402ULL,
    0x2006104900a0804ULL,
    0x1004081002402ULL
};

// bishop magic numbers
U64 bishop_magic_numbers[64] = {
    0x40040844404084ULL,
    0x2004208a004208ULL,
    0x10190041080202ULL,
    0x108060845042010ULL,
    0x581104180800210ULL,
    0x2112080446200010ULL,
    0x1080820820060210ULL,
    0x3c0808410220200ULL,
    0x4050404440404ULL,
    0x21001420088ULL,
    0x24d0080801082102ULL,
    0x1020a0a020400ULL,
    0x40308200402ULL,
    0x4011002100800ULL,
    0x401484104104005ULL,
    0x801010402020200ULL,
    0x400210c3880100ULL,
    0x404022024108200ULL,
    0x810018200204102ULL,
    0x4002801a02003ULL,
    0x85040820080400ULL,
    0x810102c808880400ULL,
    0xe900410884800ULL,
    0x8002020480840102ULL,
    0x220200865090201ULL,
    0x2010100a02021202ULL,
    0x152048408022401ULL,
    0x20080002081110ULL,
    0x4001001021004000ULL,
    0x800040400a011002ULL,
    0xe4004081011002ULL,
    0x1c004001012080ULL,
    0x8004200962a00220ULL,
    0x8422100208500202ULL,
    0x2000402200300c08ULL,
    0x8646020080080080ULL,
    0x80020a0200100808ULL,
    0x2010004880111000ULL,
    0x623000a080011400ULL,
    0x42008c0340209202ULL,
    0x209188240001000ULL,
    0x400408a884001800ULL,
    0x110400a6080400ULL,
    0x1840060a44020800ULL,
    0x90080104000041ULL,
    0x201011000808101ULL,
    0x1a2208080504f080ULL,
    0x8012020600211212ULL,
    0x500861011240000ULL,
    0x180806108200800ULL,
    0x4000020e01040044ULL,
    0x300000261044000aULL,
    0x802241102020002ULL,
    0x20906061210001ULL,
    0x5a84841004010310ULL,
    0x4010801011c04ULL,
    0xa010109502200ULL,
    0x4a02012000ULL,
    0x500201010098b028ULL,
    0x8040002811040900ULL,
    0x28000010020204ULL,
    0x6000020202d0240ULL,
    0x8918844842082200ULL,
    0x4010011029020020ULL
};

// pawn attacks table [side][square]
U64 pawn_attacks[2][64];

// knight attacks table [square]
U64 knight_attacks[64];

// king attacks table [square]
U64 king_attacks[64];

// generate pawn attacks
U64 mask_pawn_attacks(int side, int square)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // piece bitboard
    U64 bitboard = 0ULL;

    // set piece on board
    set_bit(bitboard, square);

    // white pawns
    if (!side)
    {
        // generate pawn attacks
        if ((bitboard >> 7) & not_a_file) attacks |= (bitboard >> 7);
        if ((bitboard >> 9) & not_h_file) attacks |= (bitboard >> 9);
    }

    // black pawns
    else
    {
        // generate pawn attacks
        if ((bitboard << 7) & not_h_file) attacks |= (bitboard << 7);
        if ((bitboard << 9) & not_a_file) attacks |= (bitboard << 9);
    }

    // return attack map
    return attacks;
}

// generate knight attacks
U64 mask_knight_attacks(int square)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // piece bitboard
    U64 bitboard = 0ULL;

    // set piece on board
    set_bit(bitboard, square);

    // generate knight attacks
    if ((bitboard >> 17) & not_h_file) attacks |= (bitboard >> 17);
    if ((bitboard >> 15) & not_a_file) attacks |= (bitboard >> 15);
    if ((bitboard >> 10) & not_hg_file) attacks |= (bitboard >> 10);
    if ((bitboard >> 6) & not_ab_file) attacks |= (bitboard >> 6);
    if ((bitboard << 17) & not_a_file) attacks |= (bitboard << 17);
    if ((bitboard << 15) & not_h_file) attacks |= (bitboard << 15);
    if ((bitboard << 10) & not_ab_file) attacks |= (bitboard << 10);
    if ((bitboard << 6) & not_hg_file) attacks |= (bitboard << 6);

    // return attack map
    return attacks;
}

// generate king attacks
U64 mask_king_attacks(int square)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // piece bitboard
    U64 bitboard = 0ULL;

    // set piece on board
    set_bit(bitboard, square);

    // generate king attacks
    if (bitboard >> 8) attacks |= (bitboard >> 8);
    if ((bitboard >> 9) & not_h_file) attacks |= (bitboard >> 9);
    if ((bitboard >> 7) & not_a_file) attacks |= (bitboard >> 7);
    if ((bitboard >> 1) & not_h_file) attacks |= (bitboard >> 1);
    if (bitboard << 8) attacks |= (bitboard << 8);
    if ((bitboard << 9) & not_a_file) attacks |= (bitboard << 9);
    if ((bitboard << 7) & not_h_file) attacks |= (bitboard << 7);
    if ((bitboard << 1) & not_a_file) attacks |= (bitboard << 1);

    // return attack map
    return attacks;
}

// mask bishop attacks
U64 mask_bishop_attacks(int square)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // init ranks & files
    int r, f;

    // init target rank & files
    int tr = square / 8;
    int tf = square % 8;

    // mask relevant bishop occupancy bits
    for (r = tr + 1, f = tf + 1; r <= 6 && f <= 6; r++, f++) attacks |= (1ULL << (r * 8 + f));
    for (r = tr - 1, f = tf + 1; r >= 1 && f <= 6; r--, f++) attacks |= (1ULL << (r * 8 + f));
    for (r = tr + 1, f = tf - 1; r <= 6 && f >= 1; r++, f--) attacks |= (1ULL << (r * 8 + f));
    for (r = tr - 1, f = tf - 1; r >= 1 && f >= 1; r--, f--) attacks |= (1ULL << (r * 8 + f));

    // return attack map
    return attacks;
}

// mask rook attacks
U64 mask_rook_attacks(int square)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // init ranks & files
    int r, f;

    // init target rank & files
    int tr = square / 8;
    int tf = square % 8;

    // mask relevant rook occupancy bits
    for (r = tr + 1; r <= 6; r++) attacks |= (1ULL << (r * 8 + tf));
    for (r = tr - 1; r >= 1; r--) attacks |= (1ULL << (r * 8 + tf));
    for (f = tf + 1; f <= 6; f++) attacks |= (1ULL << (tr * 8 + f));
    for (f = tf - 1; f >= 1; f--) attacks |= (1ULL << (tr * 8 + f));

    // return attack map
    return attacks;
}

// generate bishop attacks on the fly
U64 bishop_attacks_on_the_fly(int square, U64 block)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // init ranks & files
    int r, f;

    // init target rank & files
    int tr = square / 8;
    int tf = square % 8;

    // generate bishop atacks
    for (r = tr + 1, f = tf + 1; r <= 7 && f <= 7; r++, f++)
    {
        attacks |= (1ULL << (r * 8 + f));
        if ((1ULL << (r * 8 + f)) & block) break;
    }

    for (r = tr - 1, f = tf + 1; r >= 0 && f <= 7; r--, f++)
    {
        attacks |= (1ULL << (r * 8 + f));
        if ((1ULL << (r * 8 + f)) & block) break;
    }

    for (r = tr + 1, f = tf - 1; r <= 7 && f >= 0; r++, f--)
    {
        attacks |= (1ULL << (r * 8 + f));
        if ((1ULL << (r * 8 + f)) & block) break;
    }

    for (r = tr - 1, f = tf - 1; r >= 0 && f >= 0; r--, f--)
    {
        attacks |= (1ULL << (r * 8 + f));
        if ((1ULL << (r * 8 + f)) & block) break;
    }

    // return attack map
    return attacks;
}

// generate rook attacks on the fly
U64 rook_attacks_on_the_fly(int square, U64 block)
{
    // result attacks bitboard
    U64 attacks = 0ULL;

    // init ranks & files
    int r, f;

    // init target rank & files
    int tr = square / 8;
    int tf = square % 8;

    // generate rook attacks
    for (r = tr + 1; r <= 7; r++)
    {
        attacks |= (1ULL << (r * 8 + tf));
        if ((1ULL << (r * 8 + tf)) & block) break;
    }

    for (r = tr - 1; r >= 0; r--)
    {
        attacks |= (1ULL << (r * 8 + tf));
        if ((1ULL << (r * 8 + tf)) & block) break;
    }

    for (f = tf + 1; f <= 7; f++)
    {
        attacks |= (1ULL << (tr * 8 + f));
        if ((1ULL << (tr * 8 + f)) & block) break;
    }

    for (f = tf - 1; f >= 0; f--)
    {
        attacks |= (1ULL << (tr * 8 + f));
        if ((1ULL << (tr * 8 + f)) & block) break;
    }

    // return attack map
    return attacks;
}

// init leaper pieces attacks
void init_leapers_attacks()
{
    // loop over 64 board squares
    for (int square = 0; square < 64; square++)
    {
        // init pawn attacks
        pawn_attacks[white][square] = mask_pawn_attacks(white, square);
        pawn_attacks[black][square] = mask_pawn_attacks(black, square);

        // init knight attacks
        knight_attacks[square] = mask_knight_attacks(square);

        // init king attacks
        king_attacks[square] = mask_king_attacks(square);
    }
}

// set occupancies
U64 set_occupancy(int index, int bits_in_mask, U64 attack_mask)
{
    // occupancy map
    U64 occupancy = 0ULL;

    // loop over the range of bits within attack mask
    for (int count = 0; count < bits_in_mask; count++)
    {
        // get LS1B index of attacks mask
        int square = get_ls1b_index(attack_mask);

        // pop LS1B in attack map
        pop_bit(attack_mask, square);

        // make sure occupancy is on board
        if (index & (1 << count))
            // populate occupancy map
            occupancy |= (1ULL << square);
    }

    // return occupancy map
    return occupancy;
}


/**********************************\
 ==================================

               Magics

 ==================================
\**********************************/

// find appropriate magic number
U64 find_magic_number(int square, int relevant_bits, int bishop)
{
    // init occupancies
    U64 occupancies[4096];

    // init attack tables
    U64 attacks[4096];

    // init used attacks
    U64 used_attacks[4096];

    // init attack mask for a current piece
    U64 attack_mask = bishop ? mask_bishop_attacks(square) : mask_rook_attacks(square);

    // init occupancy indicies
    int occupancy_indicies = 1 << relevant_bits;

    // loop over occupancy indicies
    for (int index = 0; index < occupancy_indicies; index++)
    {
        // init occupancies
        occupancies[index] = set_occupancy(index, relevant_bits, attack_mask);

        // init attacks
        attacks[index] = bishop ? bishop_attacks_on_the_fly(square, occupancies[index]) :
                                    rook_attacks_on_the_fly(square, occupancies[index]);
    }

    // test magic numbers loop
    for (int random_count = 0; random_count < 100000000; random_count++)
    {
        // generate magic number candidate
        U64 magic_number = generate_magic_number();

        // skip inappropriate magic numbers
        if (count_bits((attack_mask * magic_number) & 0xFF00000000000000) < 6) continue;

        // init used attacks
        memset(used_attacks, 0ULL, sizeof(used_attacks));

        // init index & fail flag
        int index, fail;

        // test magic index loop
        for (index = 0, fail = 0; !fail && index < occupancy_indicies; index++)
        {
            // init magic index
            int magic_index = (int)((occupancies[index] * magic_number) >> (64 - relevant_bits));
            //printf("occupancies[%d] = %llud\n\n",index,occupancies[index]);
            //printf("magic_index = %d\n\n", magic_index);
            //printf("magic_number = %llud\n\n", magic_number);
            //getchar();
            // if magic index works
            if (used_attacks[magic_index] == 0ULL)
                // init used attacks
                used_attacks[magic_index] = attacks[index];

            // otherwise
            else if (used_attacks[magic_index] != attacks[index])
                // magic index doesn't work
                fail = 1;
        }

        // if magic number works
        if (!fail)
            // return it
            return magic_number;
    }

    // if magic number doesn't work
    printf("  Magic number fails!\n");
    return 0ULL;
}

// init magic numbers
void init_magic_numbers()
{
    // loop over 64 board squares
    for (int square = 0; square < 64; square++)
        // init rook magic numbers
        rook_magic_numbers[square] = find_magic_number(square, rook_relevant_bits[square], rook);

    // loop over 64 board squares
    for (int square = 0; square < 64; square++)
        // init bishop magic numbers
        bishop_magic_numbers[square] = find_magic_number(square, bishop_relevant_bits[square], bishop);
}


/**********************************\
 ==================================

              Init all

 ==================================
\**********************************/

// init all variables
void init_all()
{
    // init leaper pieces attacks
    init_leapers_attacks();

    // init magic numbers
    init_magic_numbers();
}

/**********************************\
 ==================================

             Main driver

 ==================================
\**********************************/

int main()
{
    // init all
    init_all();


    return 0;
}





Делфи
program bbc;

{$APPTYPE CONSOLE}

uses
  SysUtils,Windows,TypInfo;
type
    U64 = UInt64;
    TBoard_squares = (
    a8, b8, c8, d8, e8, f8, g8, h8,
    a7, b7, c7, d7, e7, f7, g7, h7,
    a6, b6, c6, d6, e6, f6, g6, h6,
    a5, b5, c5, d5, e5, f5, g5, h5,
    a4, b4, c4, d4, e4, f4, g4, h4,
    a3, b3, c3, d3, e3, f3, g3, h3,
    a2, b2, c2, d2, e2, f2, g2, h2,
    a1, b1, c1, d1, e1, f1, g1, h1
    );
    // sides to move (colors)
    TSide = (white, black);
    // bishop and rook
    Tbishop = (rook, bishop);
    //Первый индекс обозначает номер строки в матрице, второй индекс – номер столбца
    TPawn_attacks=array[TSide,TBoard_squares] of U64;
    TChip_attacks=array[TBoard_squares] of U64;
var
 bitboard:U64=0;
 block:U64=0;
 // pawn attacks table [side][square]
 pawn_attacks:TPawn_attacks;
 // knight attacks table [square]
 knight_attacks:TChip_attacks;
 // king attacks table [square]
 king_attacks:TChip_attacks;
 square:TBoard_squares;
 // pseudo random number state
 //cardinal - беззнаковое целое
 stateU32:cardinal = 1804289383;
const
{/*
        not A file
  8  0 1 1 1 1 1 1 1
  7  0 1 1 1 1 1 1 1
  6  0 1 1 1 1 1 1 1
  5  0 1 1 1 1 1 1 1
  4  0 1 1 1 1 1 1 1
  3  0 1 1 1 1 1 1 1
  2  0 1 1 1 1 1 1 1
  1  0 1 1 1 1 1 1 1
     a b c d e f g h
        not H file
  8  1 1 1 1 1 1 1 0
  7  1 1 1 1 1 1 1 0
  6  1 1 1 1 1 1 1 0
  5  1 1 1 1 1 1 1 0
  4  1 1 1 1 1 1 1 0
  3  1 1 1 1 1 1 1 0
  2  1 1 1 1 1 1 1 0
  1  1 1 1 1 1 1 1 0
     a b c d e f g h
       not HG file
  8  1 1 1 1 1 1 0 0
  7  1 1 1 1 1 1 0 0
  6  1 1 1 1 1 1 0 0
  5  1 1 1 1 1 1 0 0
  4  1 1 1 1 1 1 0 0
  3  1 1 1 1 1 1 0 0
  2  1 1 1 1 1 1 0 0
  1  1 1 1 1 1 1 0 0
     a b c d e f g h
       not AB file
  8  0 0 1 1 1 1 1 1
  7  0 0 1 1 1 1 1 1
  6  0 0 1 1 1 1 1 1
  5  0 0 1 1 1 1 1 1
  4  0 0 1 1 1 1 1 1
  3  0 0 1 1 1 1 1 1
  2  0 0 1 1 1 1 1 1
  1  0 0 1 1 1 1 1 1
     a b c d e f g h
*/}

// not A file constant
not_a_file:U64 = $FEFEFEFEFEFEFEFE;//18374403900871474942;
// not H file constant
not_h_file:U64 = $7F7F7F7F7F7F7F7F;//9187201950435737471;
// not HG file constant
not_hg_file:U64 =$3F3F3F3F3F3F3F3F;//4557430888798830399;
// not AB file constant
not_ab_file:U64 =$FCFCFCFCFCFCFCFC;//18229723555195321596;
square_to_coordinates: array [0..63]  of  string =  (
    'a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8',
    'a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7',
    'a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6',
    'a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5',
    'a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4',
    'a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3',
    'a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2',
    'a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1'
);
// bishop relevant occupancy bit count for every square on board
bishop_relevant_bits: array [0..63]  of  integer =(
    6, 5, 5, 5, 5, 5, 5, 6,
    5, 5, 5, 5, 5, 5, 5, 5, 
    5, 5, 7, 7, 7, 7, 5, 5, 
    5, 5, 7, 9, 9, 7, 5, 5, 
    5, 5, 7, 9, 9, 7, 5, 5, 
    5, 5, 7, 7, 7, 7, 5, 5, 
    5, 5, 5, 5, 5, 5, 5, 5, 
    6, 5, 5, 5, 5, 5, 5, 6
);

// rook relevant occupancy bit count for every square on board
rook_relevant_bits: array [0..63]  of  integer =(
    12, 11, 11, 11, 11, 11, 11, 12, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    11, 10, 10, 10, 10, 10, 10, 11, 
    12, 11, 11, 11, 11, 11, 11, 12
);
{/**********************************\
 ==================================
 
           Random numbers
 
 ==================================
\**********************************/}
// generate 32-bit pseudo legal numbers
function  get_random_U32_number():cardinal;
begin
// XOR shift algorithm
stateU32:=stateU32 xor (stateU32 shl 13);
stateU32:=stateU32 xor (stateU32 shr 17);
stateU32:=stateU32 xor (stateU32 shl 5);
get_random_U32_number:=stateU32;
end;
// generate 64-bit pseudo legal numbers
function  get_random_U64_number():U64;
var
// define 4 random numbers
n1,n2,n3,n4:U64;
begin
n1:=0;n2:=0;n3:=0; n4:=0;
// init random numbers slicing 16 bits from MS1B side
n1:=(n1 or (get_random_U32_number())) and $FFFF;
n2:=(n2 or (get_random_U32_number())) and $FFFF;
n3:=(n3 or (get_random_U32_number())) and $FFFF;
n4:=(n4 or (get_random_U32_number())) and $FFFF;
// return random number
get_random_U64_number:=n1 or (n2 shl 16) or (n3 shl 32) or (n4 shl 48);
end;
// generate magic number candidate
function generate_magic_number():U64;
begin
  result:=get_random_U64_number() and get_random_U64_number() and get_random_U64_number();
end;
{/**********************************\
 ==================================
 
          Bit manipulations
 
 ==================================
\**********************************/}
// set/get/pop
function get_bit(bb:U64;const sq:integer):integer;
begin
get_bit:=(bb shr sq) and 1;
end;
procedure set_bit(var bb:U64;const sq:TBoard_squares);
begin
bb:=bb or ($8000000000000000 shr (63-Ord(sq)));
end;
procedure pop_bit(var bb:U64;const sq:TBoard_squares);
begin
if get_bit(bb,Ord(sq))>0 then bb:=bb xor ($8000000000000000 shr (63-Ord(sq)));
end;
// count bits within a bitboard (Brian Kernighan's way)
function count_bits(bb:U64):integer;
var
count:integer;
begin
    // bit counter
    count := 0;
    // consecutively reset least significant 1st bit
     while bb>0
     do  begin
         // increment count
         Inc(count);
         // reset least significant 1st bit
         bb := bb and (bb - 1);
         end;
count_bits:=count;
end;
// get least significant 1st bit index
function  get_ls1b_index(bb:U64):integer;
begin
  // make sure bitboard is not 0
 if bb<>0 then
 // count trailing bits before LS1B
 result:=count_bits((bb and (-bb))-1)
 // return illegal index
 else result:=-1;
end;
{/**********************************\
 ==================================
 
           Input & Output
 
 ==================================
\**********************************/}
// print bitboard
procedure print_bitboard(bb:U64);
var
rank_,file_,sq:integer;
begin
Writeln('');
  // loop over board ranks
  for rank_ := 0 to 7 do  begin
        // loop over board files
        for file_ := 0 to 7 do  begin
           // convert file & rank into square index
           sq:=rank_*8 + file_;
           //// print ranks
           if file_ = 0 then begin
           Write(8 - rank_);Write(' ');
           end;
           Write(' ');
           // print bit state (either 1 or 0)
           Write(get_bit(bb,sq));
        end;
        // print new line every rank
        Writeln('');
  end;
  // print new line
  Writeln('');
  // print board files
  Writeln('   a b c d e f g h');
  Writeln('');
  // print bitboard as unsigned decimal number
  Write('bitboard = ',bb);
  Writeln('');
end;
{/**********************************\
 ==================================

              Attacks

 ==================================
\**********************************/}
// generate pawn attacks
function mask_pawn_attacks(side:TSide;square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // white pawns
    if (side=white) then begin
      if ((bitboard shr 7) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 7);
      if ((bitboard shr 9) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 9);
    end
    // black pawns
    else  begin
      if ((bitboard shl 7) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 7);
      if ((bitboard shl 9) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 9);
    end;
// return attack map
mask_pawn_attacks:=attacks;
end;
// generate knight attacks
function  mask_knight_attacks(square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // generate knight attacks
    if ((bitboard shr 17) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 17);
    if ((bitboard shr 15) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 15);
    if ((bitboard shr 10) and not_hg_file)>0 then  attacks:=attacks or (bitboard shr 10);
    if ((bitboard shr 6) and not_ab_file)>0 then  attacks:=attacks or (bitboard shr 6);
    if ((bitboard shl 17) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 17);
    if ((bitboard shl 15) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 15);
    if ((bitboard shl 10) and not_ab_file)>0 then  attacks:=attacks or (bitboard shl 10);
    if ((bitboard shl 6) and not_hg_file)>0 then  attacks:=attacks or (bitboard shl 6);
// return attack map
mask_knight_attacks:=attacks;
end;
// generate king attacks
function  mask_king_attacks(square:TBoard_squares):U64;
var
attacks,bitboard:U64;
begin
// result attacks bitboard
attacks := 0;
// piece bitboard
bitboard := 0;
// set piece on board
set_bit(bitboard, square);
    // generate king attacks
    if (bitboard shr 8)>0 then  attacks:=attacks or (bitboard shr 8);
    if ((bitboard shr 9) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 9);
    if ((bitboard shr 1) and not_h_file)>0 then  attacks:=attacks or (bitboard shr 1);
    if ((bitboard shr 7) and not_a_file)>0 then  attacks:=attacks or (bitboard shr 7);
    if (bitboard shl 8)>0 then  attacks:=attacks or (bitboard shl 8);
    if ((bitboard shl 9) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 9);
    if ((bitboard shl 1) and not_a_file)>0 then  attacks:=attacks or (bitboard shl 1);
    if ((bitboard shl 7) and not_h_file)>0 then  attacks:=attacks or (bitboard shl 7);
// return attack map
mask_king_attacks:=attacks;
end;
//урок 6-masking relevant bishop occupancy bits to form a key for MAGIC BITBOARDS
// mask bishop attacks
function   mask_bishop_attacks(square:TBoard_squares):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // mask relevant bishop occupancy bits
    f:=tf+1;
    for r:=tr+1 to 6 do begin
       if f>6 then break;
       attacks := attacks or (n shl (r*8+f));
       Inc(f);
    end;
    f:=tf+1;
    for r:=tr-1 downto 1 do begin
       if f>6 then break;
       attacks := attacks or (n shl (r*8+f));
       Inc(f);
    end;
    f:=tf-1;
    for r:=tr+1 to 6 do begin
       if f<1 then break;
       attacks := attacks or (n shl (r*8+f));
       Dec(f);
    end;
    f:=tf-1;
    for r:=tr-1 downto 1 do begin
       if f<1 then break;
       attacks := attacks or (n shl (r*8+f));
       Dec(f);
    end;
// return attack map
mask_bishop_attacks:=attacks;
end;
//урок 7-masking relevant ROOK OCCUPANCY BITS to form a key for MAGIC BITBOARDS
// mask rook attacks
function   mask_rook_attacks(square:TBoard_squares):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // mask relevant bishop occupancy bits
    for r:=tr+1 to 6 do attacks := attacks or (n shl (r*8+tf));
    for r:=tr-1 downto 1 do attacks := attacks or (n shl (r*8+tf));
    for f:=tf+1 to 6 do attacks := attacks or (n shl (tr*8+f));
    for f:=tf-1 downto 1 do attacks := attacks or (n shl (tr*8+f));
// return attack map
mask_rook_attacks:=attacks;
end;
//урок 8-generating SLIDER PIECES ATTACKS on the fly for MAGIC BITBOARD purposes
// generate bishop attacks on the fly
function  bishop_attacks_on_the_fly(square:TBoard_squares;blk:U64):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // generate bishop atacks
    f:=tf+1;
    for r:=tr+1 to 7 do begin
       if f>7 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Inc(f);
    end;
        f:=tf+1;
    for r:=tr-1 downto 0 do begin
       if f>7 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Inc(f);
    end;
    f:=tf-1;
    for r:=tr+1 to 7 do begin
       if f<0 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Dec(f);
    end;
    f:=tf-1;
    for r:=tr-1 downto 0 do begin
       if f<0 then break;
       attacks := attacks or (n shl (r*8+f));
       if ((n shl (r*8+f)) and blk)>0 then  break;
       Dec(f);
    end;
// return attack map
bishop_attacks_on_the_fly:=attacks;
end;
// generate rook attacks on the fly
function  rook_attacks_on_the_fly(square:TBoard_squares;blk:U64):U64;
var
attacks,n:U64;
r,f,tr,tf:integer;
begin
n:=1;
// result attacks bitboard
attacks := 0;
    // init target rank & files
    tr := Ord(square) div 8;//целочисленное деление
    tf := Ord(square) mod 8;//остаток от деления
    // generate rook attacks
    for r:=tr+1 to 7 do begin
    attacks := attacks or (n shl (r*8+tf));
    if ((n shl (r*8+tf)) and blk)>0 then  break;
    end;
    for r:=tr-1 downto 0 do begin
    attacks := attacks or (n shl (r*8+tf));
    if ((n shl (r*8+tf)) and blk)>0 then  break;
    end;
    for f:=tf+1 to 7 do begin
    attacks := attacks or (n shl (tr*8+f));
    if ((n shl (tr*8+f)) and blk)>0 then  break;
    end;
    for f:=tf-1 downto 0 do begin
    attacks := attacks or (n shl (tr*8+f));
    if ((n shl (tr*8+f)) and blk)>0 then  break;
    end;
// return attack map
rook_attacks_on_the_fly:=attacks;
end;
// init leaper pieces attacks
procedure init_leapers_attacks();
var
square:TBoard_squares;
begin
    // loop over 64 board squares
    for square := a8 to h1 do  begin
//урок 3-generating pre-calculated PAWN ATTACK tables
       // init pawn attacks
       pawn_attacks[white][square] := mask_pawn_attacks(white,square);
       pawn_attacks[black][square] := mask_pawn_attacks(black,square);
//урок 4-generating pre-calculated KNIGHT ATTACK table
       // init knight attacks
       knight_attacks[square] := mask_knight_attacks(square);
//урок 5-generating pre-calculated KING ATTACK tables
       // init king attacks
       king_attacks[square] := mask_king_attacks(square);
    end;
end;
// set occupancies
//перебираем по очереди биты в attack_mask
//испр. ошибка - было -var attack_mask:U64, стало-attack_mask:U64
function set_occupancy(index,bits_in_mask:integer;attack_mask:U64):U64;
var
occupancy,n:U64;
count:integer;
square_:TBoard_squares;
begin
n:=1;
// occupancy map
occupancy:=0;
            // loop over the range of bits within attack mask
            for count:=0 to bits_in_mask-1 do begin
               // get LS1B index of attacks mask
               square_:=TBoard_squares(get_ls1b_index(attack_mask));
               // pop LS1B in attack map
               pop_bit(attack_mask,square_);
               // make sure occupancy is on board
               if (index and (n shl count))>0 then
                   occupancy:=occupancy or (n shl integer(square_));
            end;
set_occupancy:=occupancy;
end;
{/**********************************\
 ==================================

               Magics
 function  rook_attacks_on_the_fly(square:TBoard_squares;blk:U64):U64;
 ==================================
\**********************************/}
// find appropriate magic number
function find_magic_number(square:TBoard_squares;relevant_bits:integer;bishop_flag:Tbishop):U64;
//function find_magic_number():U64;
var
// init occupancies
occupancies:array[0..4095] of U64;
// init attack tables
attacks:array[0..4095] of U64;
// init used attacks
used_attacks:array[0..4095] of U64;
n:Byte;
// init attack mask for a current piece
attack_mask:U64;
// init occupancy indicies
occupancy_indicies:integer;
magic_index:integer;
index,fail,random_count:integer;
magic_number:U64;
//memset
//https://metanit.com/c/tutorial/8.3.php?ysclid=ldc20xz850854644891
begin
attack_mask:=0;
 // init attack mask for a current piece
 if bishop_flag=bishop then attack_mask:=mask_bishop_attacks(square)
                       else attack_mask:=mask_rook_attacks(square);
 // init occupancy indicies  напр. ладья на a1 - rook_relevant_bits: array [ ] = 12
 // 1 shl 12 = 4096
 occupancy_indicies:=1 shl relevant_bits;
 // loop over occupancy indicies
 for index:=0 to occupancy_indicies-1 do begin
    // init occupancies
    occupancies[index] := set_occupancy(index,relevant_bits,attack_mask);
    // init attacks
    if bishop_flag=bishop then attacks[index]:= bishop_attacks_on_the_fly(square, occupancies[index])
                          else attacks[index]:= rook_attacks_on_the_fly(square, occupancies[index]);
 end;
 // test magic numbers loop
 n:=0;
 for random_count:= 0 to 100000000 do begin
     // generate magic number candidate
     magic_number := generate_magic_number();
     // skip inappropriate magic numbers
     if (count_bits((attack_mask * magic_number) and $FF00000000000000) < 6) then continue;
//http://www.delphibasics.ru/FillChar.php
// procedure FillChar ( var Buffer; FillCount : Integer; FillValue : Byte ) ;
{Процедура FillChar заполняет раздел памяти Buffer
тем же самым байтом или символом FillValue FillCount раз.
Это используется, преимущественно, для инициализирования массивов чисел.}
   // Теперь заполняем массив used_attacks значением 0
   // UInt64 - 8 байт
   FillChar(used_attacks, 4096*SizeOf(UInt64), n);
   fail := 0;
   for index:=0 to occupancy_indicies-1 do begin
      // init magic index
      magic_index := integer((occupancies[index] * magic_number) shr (64 - relevant_bits));
      {Writeln('occupancies[',index,'] = ',occupancies[index]);
      Writeln('magic_index = ',magic_index);
      Writeln('magic_number = ',magic_number);
      Readln;}
            // if magic index works
            if (used_attacks[magic_index] = 0) then
                // init used attacks
                used_attacks[magic_index] := attacks[index]
            // otherwise
            else if (used_attacks[magic_index] <> attacks[index])  then  begin
                // magic index doesn't work
                 fail := 1;break;
            end;
    end;
// if magic number works
if (fail=0) then  begin
// return it
result:=magic_number;
exit;
end;
 end;
   // if magic number doesn't work
   Writeln(' Magic number fails! ');
   result:=0;
end;
// init magic numbers
procedure init_magic_numbers();
var
tem64:U64;
temp32:integer;
begin
 // loop over 64 board squares
  for square := a8 to h1 do  begin
    tem64:=find_magic_number(square,rook_relevant_bits[integer(square)],rook);
    Write('0x');Write(Format('%x',[tem64]));Write('ULL');
    Writeln('');
    //Write(tem64);
    //Readln;
  end;
  Writeln('====================');
  for square := a8 to h1 do  begin
    tem64:=find_magic_number(square,bishop_relevant_bits[integer(square)],bishop);
    Write('0x');Write(Format('%x',[tem64]));Write('ULL');
    Writeln('');
    //Write(tem64);
    //Readln;
  end;
end;
{/**********************************\
 ==================================

             Main driver
 
 ==================================
\**********************************/}
 begin
  //Переключение окна консоли на кодовую страницу CP1251 (Win-1251).
  //Если после переключения русские буквы показываются неверно,
  //следует открыть системное меню консольного окна - щелчком мыши в левом
  //верхнем углу окна консоли. И выбрать:
  //Свойства - закладка "Шрифт" - выбрать шрифт: "Lucida Console".
  SetConsoleCP(1251);
  SetConsoleOutputCP(1251);
// ==================================
  init_leapers_attacks(); 
  init_magic_numbers();
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;
end.
  {print_bitboard(get_random_U32_number());
  print_bitboard(get_random_U32_number());
  print_bitboard(get_random_U64_number());
  print_bitboard(generate_magic_number());}
  {Writeln('bishop_relevant_bits');
  for square := a8 to h1 do  begin
    if (integer(square) mod 8)=0 then  Writeln('');
     Write(count_bits(mask_bishop_attacks(square))); Write(' ');
  end;
  Writeln('');
  Writeln('rook_relevant_bits');
    for square := a8 to h1 do  begin
    if (integer(square) mod 8)=0 then  Writeln('');
     Write(count_bits(mask_rook_attacks(square))); Write(' ');
  end;
  Writeln('');}
   { block:=4512464976740352;
  print_bitboard(block);
  square:=TBoard_squares(get_ls1b_index(block));
  Write('get_ls1b_index:',integer(square));
  Writeln('  coordinate:',square_to_coordinates[integer(square)]);
  set_bit(bitboard,square);
  print_bitboard(bitboard);}
  //ZobristKey[i][j][z]=rd.nextLong()^(rd.nextLong()<<15)^(rd.nextLong()<<30)^(rd.nextLong()<<45)^(rd.nextLong()<<60);
  //<< shl

Магические числа, полученные с помощью кода адаптированного на Делфи
0x8A80104000800020ULL
0x140002000100040ULL
0x2801880A0017001ULL
0x100081001000420ULL
0x200020010080420ULL
0x3001C0002010008ULL
0x8480008002000100ULL
0x2080088004402900ULL
0x800098204000ULL
0x2024401000200040ULL
0x100802000801000ULL
0x120800800801000ULL
0x208808088000400ULL
0x2802200800400ULL
0x2200800100020080ULL
0x801000060821100ULL
0x80044006422000ULL
0x100808020004000ULL
0x12108A0010204200ULL
0x140848010000802ULL
0x481828014002800ULL
0x8094004002004100ULL
0x4010040010010802ULL
0x20008806104ULL
0x100400080208000ULL
0x2040002120081000ULL
0x21200680100081ULL
0x20100080080080ULL
0x2000A00200410ULL
0x20080800400ULL
0x80088400100102ULL
0x80004600042881ULL
0x4040008040800020ULL
0x440003000200801ULL
0x4200011004500ULL
0x188020010100100ULL
0x14800401802800ULL
0x2080040080800200ULL
0x124080204001001ULL
0x200046502000484ULL
0x480400080088020ULL
0x1000422010034000ULL
0x30200100110040ULL
0x100021010009ULL
0x2002080100110004ULL
0x202008004008002ULL
0x20020004010100ULL
0x2048440040820001ULL
0x101002200408200ULL
0x40802000401080ULL
0x4008142004410100ULL
0x2060820C0120200ULL
0x1001004080100ULL
0x20C020080040080ULL
0x2935610830022400ULL
0x44440041009200ULL
0x280001040802101ULL
0x2100190040002085ULL
0x80C0084100102001ULL
0x4024081001000421ULL
0x20030A0244872ULL
0x12001008414402ULL
0x2006104900A0804ULL
0x1004081002402ULL
====================
0x40040844404084ULL
0x2004208A004208ULL
0x10190041080202ULL
0x108060845042010ULL
0x581104180800210ULL
0x2112080446200010ULL
0x1080820820060210ULL
0x3C0808410220200ULL
0x4050404440404ULL
0x21001420088ULL
0x24D0080801082102ULL
0x1020A0A020400ULL
0x40308200402ULL
0x4011002100800ULL
0x401484104104005ULL
0x801010402020200ULL
0x400210C3880100ULL
0x404022024108200ULL
0x810018200204102ULL
0x4002801A02003ULL
0x85040820080400ULL
0x810102C808880400ULL
0xE900410884800ULL
0x8002020480840102ULL
0x220200865090201ULL
0x2010100A02021202ULL
0x152048408022401ULL
0x20080002081110ULL
0x4001001021004000ULL
0x800040400A011002ULL
0xE4004081011002ULL
0x1C004001012080ULL
0x8004200962A00220ULL
0x8422100208500202ULL
0x2000402200300C08ULL
0x8646020080080080ULL
0x80020A0200100808ULL
0x2010004880111000ULL
0x623000A080011400ULL
0x42008C0340209202ULL
0x209188240001000ULL
0x400408A884001800ULL
0x110400A6080400ULL
0x1840060A44020800ULL
0x90080104000041ULL
0x201011000808101ULL
0x1A2208080504F080ULL
0x8012020600211212ULL
0x500861011240000ULL
0x180806108200800ULL
0x4000020E01040044ULL
0x300000261044000AULL
0x802241102020002ULL
0x20906061210001ULL
0x5A84841004010310ULL
0x4010801011C04ULL
0xA010109502200ULL
0x4A02012000ULL
0x500201010098B028ULL
0x8040002811040900ULL
0x28000010020204ULL
0x6000020202D0240ULL
0x8918844842082200ULL
0x4010011029020020ULL
Нажмите <ENTER>, чтобы выйти ...

Вроде такие же, как у Макса
Last Edit: 27 Янв 2023 12:58 by alexlaw.

Bitboard в программировании шахмат №2 27 Янв 2023 23:00 #128

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Посмотрел 16 урок - Bitboard CHESS ENGINE in C: initializing SLIDER PIECES attack tables using PLAIN MAGIC BITBOARDS
К сожалению Макс перестал объснять, а просто пишет код.
Я тоже одновременно с ним пишу.
И да, в этом есть какая то магия, точно есть)))
45.jpg
// init slider piece's attack tables
procedure init_sliders_attacks(bishop_flag:Tbishop);
var
// init current mask
attack_mask:U64;
// init current occupancy variation
occupancy:U64;
// init relevant occupancy bit count
relevant_bits_count:integer;
// init occupancy indicies
occupancy_indicies:integer;
magic_index:integer;
index:integer;
begin
    // loop over 64 board squares
    for square := a8 to h1 do  begin
        // init bishop & rook masks
        bishop_masks[square] := mask_bishop_attacks(square);
        rook_masks[square] := mask_rook_attacks(square);
        // init current mask
        if bishop_flag=bishop then  attack_mask:=bishop_masks[square]
                              else  attack_mask:=rook_masks[square];
        // init relevant occupancy bit count
        relevant_bits_count := count_bits(attack_mask);
        // init occupancy indicies
        occupancy_indicies := 1 shl relevant_bits_count;
        // loop over occupancy indicies
        for index:=0 to occupancy_indicies-1 do begin
           // bishop
           if bishop_flag=bishop then begin
// init current occupancy variation
occupancy := set_occupancy(index, relevant_bits_count, attack_mask);
// init magic index
magic_index := integer((occupancy * bishop_magic_numbers[square]) shr (64 - bishop_relevant_bits[square]));
// init bishop attacks
bishop_attacks[square][magic_index] := bishop_attacks_on_the_fly(square, occupancy);
           end
           // rook
           else begin
// init current occupancy variation
occupancy := set_occupancy(index, relevant_bits_count, attack_mask);
// init magic index
magic_index := integer((occupancy * rook_magic_numbers[square]) shr (64 - rook_relevant_bits[square]));
// init bishop attacks
rook_attacks[square][magic_index] := rook_attacks_on_the_fly(square, occupancy);
           end;
        end;
    end;
end;
// get bishop attacks
function get_bishop_attacks(square:TBoard_squares;occupancy:U64):U64;
begin
occupancy:=occupancy and bishop_masks[square];
occupancy:=occupancy * bishop_magic_numbers[square];
occupancy:=occupancy shr (64 - bishop_relevant_bits[square]);
// return bishop attacks
result:=bishop_attacks[square][occupancy];
end;
// get rook attacks
function get_rook_attacks(square:TBoard_squares;occupancy:U64):U64;
begin
occupancy:=occupancy and rook_masks[square];
occupancy:=occupancy * rook_magic_numbers[square];
occupancy:=occupancy shr (64 - rook_relevant_bits[square]);
// return bishop attacks
result:=rook_attacks[square][occupancy];
end;
{/**********************************\
 ==================================

              Init all

 ==================================
\**********************************/}
// init all variables
procedure init_all();
begin
    // init leaper pieces attacks
    init_leapers_attacks();
    // init slider pieces attacks
    init_sliders_attacks(bishop);
    init_sliders_attacks(rook);
    // init magic numbers
    //init_magic_numbers();
end;
{/**********************************\
 ==================================

             Main driver
 
 ==================================
\**********************************/}
 begin
  //Переключение окна консоли на кодовую страницу CP1251 (Win-1251).
  //Если после переключения русские буквы показываются неверно,
  //следует открыть системное меню консольного окна - щелчком мыши в левом
  //верхнем углу окна консоли. И выбрать:
  //Свойства - закладка "Шрифт" - выбрать шрифт: "Lucida Console".
  SetConsoleCP(1251);
  SetConsoleOutputCP(1251);
// ==================================
  // init all
  init_all();
      // set blocker pieces on board
    set_bit(block, c5);
    set_bit(block, f2);
    set_bit(block, g7);
    set_bit(block, b2);
    set_bit(block, g5);
    set_bit(block, e2);
    set_bit(block, e7);
    print_bitboard(block);
      // print rook attacks
    print_bitboard(get_rook_attacks(e5, block));
    // print bishop attacks
    print_bitboard(get_bishop_attacks(d4, block));
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;
end.

Надо бы докапаться до сути и понять как это работает.

Bitboard в программировании шахмат №2 28 Янв 2023 14:59 #129

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Протестировал магические квадраты на задаче неприкосновенный король.
Конечно это достаточно условный тест с некоторыми допущениями.
Время складывается из работы основной тестируемой функции и условно постоянной величины, складывающейся из функции прорисовки, оценки позиции и т.д.
Но примем допущения, что эта величина одинакова для всех.
Еще в магических квадратах пришлось просчитывать дополнительно ходы черного короля с учетом шахов.
В общем результат при depth=8

46.jpg


Если есть числа, которые работают, то зачем искать другие другие числа.
Last Edit: 28 Янв 2023 15:00 by alexlaw.

Bitboard в программировании шахмат №2 31 Янв 2023 13:54 #130

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Уроки
17.Bitboard CHESS ENGINE in C: defining BITBOARDS, OCCUPANCIES and helper variables
18.Bitboard CHESS ENGINE in C: printing CHESS BOARD position and game state variables
19.Bitboard CHESS ENGINE in C: parsing FEN string to initialize BITBOARDS, OCUUPANCIES & board state
20.Bitboard CHESS ENGINE in C: getting QUEEN ATTACKS by looking up bishop & rook attack tables

Пока, что каких-то особых секретов в этих уроках нет.
Но необходимо двигаться в ногу с Максом, иначе дальше двигаться будет невозможно.
Итак вкратце:
Атаки ферзя - объединяем атаки слона и ладьи
// get queen attacks
function get_queen_attacks(square:TBoard_squares;occupancy:U64):U64;
begin
result:=get_bishop_attacks(square,occupancy) or get_rook_attacks(square,occupancy);
end;
Позиция и вспомогательные переменные
uses
  SysUtils,Windows,TypInfo;
type
    U64 = UInt64;
    TBoard_squares = (
    a8, b8, c8, d8, e8, f8, g8, h8,
    a7, b7, c7, d7, e7, f7, g7, h7,
    a6, b6, c6, d6, e6, f6, g6, h6,
    a5, b5, c5, d5, e5, f5, g5, h5,
    a4, b4, c4, d4, e4, f4, g4, h4,
    a3, b3, c3, d3, e3, f3, g3, h3,
    a2, b2, c2, d2, e2, f2, g2, h2,
    a1, b1, c1, d1, e1, f1, g1, h1
    );
    // sides to move (colors)
    TSide = (white, black, both);
    // bishop and rook
    Tbishop = (rook, bishop);
    //Pawn
    TPawn_attacks=array[TSide,TBoard_squares] of U64;
    //прыгающие фигуры
    TChip_attacks=array[TBoard_squares] of U64;
    // encode pieces
    Tencode_pieces=( P_, N_, B_, R_, Q_, K_, p, n, b, r, q, k);
{// castling rights binary encoding
    рокеровка
/*

    bin  dec

   0001    1  white king can castle to the king side
   0010    2  white king can castle to the queen side
   0100    4  black king can castle to the king side
   1000    8  black king can castle to the queen side

   examples

   1111       both sides an castle both directions
   1001       black king => queen side
              white king => king side

*/}
   Tcastling = (wk = 1, wq = 2, bk = 4, bq = 8 );
var
{/**********************************\
 ==================================

            Chess board
 
 ==================================
\**********************************/

/*
                            WHITE PIECES


        Pawns                  Knights              Bishops
        
  8  0 0 0 0 0 0 0 0    8  0 0 0 0 0 0 0 0    8  0 0 0 0 0 0 0 0
  7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0
  6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0
  5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0
  4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0
  3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0
  2  1 1 1 1 1 1 1 1    2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0
  1  0 0 0 0 0 0 0 0    1  0 1 0 0 0 0 1 0    1  0 0 1 0 0 1 0 0

     a b c d e f g h       a b c d e f g h       a b c d e f g h


         Rooks                 Queens                 King

  8  0 0 0 0 0 0 0 0    8  0 0 0 0 0 0 0 0    8  0 0 0 0 0 0 0 0
  7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0
  6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0
  5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0
  4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0
  3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0
  2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0
  1  1 0 0 0 0 0 0 1    1  0 0 0 1 0 0 0 0    1  0 0 0 0 1 0 0 0

     a b c d e f g h       a b c d e f g h       a b c d e f g h


                            BLACK PIECES


        Pawns                  Knights              Bishops

  8  0 0 0 0 0 0 0 0    8  0 1 0 0 0 0 1 0    8  0 0 1 0 0 1 0 0
  7  1 1 1 1 1 1 1 1    7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0
  6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0
  5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0
  4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0
  3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0
  2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0
  1  0 0 0 0 0 0 0 0    1  0 0 0 0 0 0 0 0    1  0 0 0 0 0 0 0 0

     a b c d e f g h       a b c d e f g h       a b c d e f g h


         Rooks                 Queens                 King

  8  1 0 0 0 0 0 0 1    8  0 0 0 1 0 0 0 0    8  0 0 0 0 1 0 0 0
  7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0    7  0 0 0 0 0 0 0 0
  6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0
  5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0
  4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0
  3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0
  2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0    2  0 0 0 0 0 0 0 0
  1  0 0 0 0 0 0 0 0    1  0 0 0 0 0 0 0 0    1  0 0 0 0 0 0 0 0

     a b c d e f g h       a b c d e f g h       a b c d e f g h

}
 // piece bitboards
 bitboards_12:array[Tencode_pieces] of U64;
{
                             OCCUPANCIES
     White occupancy       Black occupancy       All occupancies

  8  0 0 0 0 0 0 0 0    8  1 1 1 1 1 1 1 1    8  1 1 1 1 1 1 1 1
  7  0 0 0 0 0 0 0 0    7  1 1 1 1 1 1 1 1    7  1 1 1 1 1 1 1 1
  6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0    6  0 0 0 0 0 0 0 0
  5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0    5  0 0 0 0 0 0 0 0
  4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0    4  0 0 0 0 0 0 0 0
  3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0    3  0 0 0 0 0 0 0 0
  2  1 1 1 1 1 1 1 1    2  0 0 0 0 0 0 0 0    2  1 1 1 1 1 1 1 1
  1  1 1 1 1 1 1 1 1    1  0 0 0 0 0 0 0 0    1  1 1 1 1 1 1 1 1
}
 // occupancy bitboards
 occupancies_3:array[TSide] of U64;
 // side to move
 side:TSide = both;
 // enpassant square
 enpassantInt:integer=-1;
 enpassant:TBoard_squares=a8;
 // castling rights
 castle:integer=0;
 // ASCII pieces
 ascii_pieces:array[0..11] of char = 'PNBRQKpnbrqk';
 //===========================================
// piece bitboards
bitboards_12:array[Tencode_pieces] of U64; - битборды по типу и цвету для фигур
// occupancy bitboards
occupancies_3:array[TSide] of U64; - битбоарды белых, черных и всех фигур
// side to move
side:TSide = both; - белые, черные или все
// castling rights
castle:integer=0; - флаг рокеровки
bin dec

0001 1 white king can castle to the king side
0010 2 white king can castle to the queen side
0100 4 black king can castle to the king side
1000 8 black king can castle to the queen side
// enpassant square - флаг и поле (взятие на проходе)
enpassantInt:integer=-1;
enpassant:TBoard_squares=a8;//заведомо ложное поле
отладочная информация и визуализация (вывод досок в консоль, парсинг fen строки
// ASCII pieces
ascii_pieces:array[0..11] of char = 'PNBRQKpnbrqk';
{/**********************************\
 ==================================
 
           Input & Output
 
 ==================================
\**********************************/}
// print bitboard
procedure print_bitboard(bb:U64);
var
rank_,file_,sq:integer;
begin
Writeln('');
  // loop over board ranks
  for rank_ := 0 to 7 do  begin
        // loop over board files
        for file_ := 0 to 7 do  begin
           // convert file & rank into square index
           sq:=rank_*8 + file_;
           //// print ranks
           if file_ = 0 then begin
           Write(8 - rank_);Write(' ');
           end;
           Write(' ');
           // print bit state (either 1 or 0)
           Write(get_bit(bb,sq));
        end;
        // print new line every rank
        Writeln('');
  end;
  // print new line
  Writeln('');
  // print board files
  Writeln('   a b c d e f g h');
  Writeln('');
  // print bitboard as unsigned decimal number
  Write('bitboard = ',bb);
  Writeln('');
end;
// print board
procedure print_board();
var
rank_,file_,sq:integer;
bb_piece:Tencode_pieces;
flag:boolean;
begin
Writeln('');
  // loop over board ranks
  for rank_ := 0 to 7 do  begin
        // loop over board files
        for file_ := 0 to 7 do  begin
           // convert file & rank into square index
           sq:=rank_*8 + file_;
           //// print ranks
           if file_ = 0 then begin
           Write(8 - rank_);Write(' ');
           end;
           Write(' ');
           flag:=true;
               // loop over all piece bitboards
               for bb_piece := P_ to k do  begin
                 if get_bit(bitboards_12[bb_piece],sq)>0 then begin
                       Write(ascii_pieces[integer(bb_piece)]);
                       flag:=false;
                 end;
               end;
           if flag then   Write('.');
        end;
        // print new line every rank
        Writeln('');
  end;
  // print new line
  Writeln('');
  // print board files
  Writeln('   a b c d e f g h');
  Writeln('');
  Write('side      = ');
  //Write(GetEnumName(TypeInfo(TSide), ord(TSide(integer(side)))));
  //TSide = (white, black, both);
  if side=white then Write('white');
  if side=black then Write('black');
  Writeln('');
  Write('castle    = ');
  if (castle and integer(Tcastling(wk)))>0 then Write('K') else Write('-');
  if (castle and integer(Tcastling(wq)))>0 then Write('Q') else Write('-');
  if (castle and integer(Tcastling(bk)))>0 then Write('k') else Write('-');
  if (castle and integer(Tcastling(bq)))>0 then Write('q') else Write('-');
  Writeln('');
  Write('enpassant = ');
  if enpassantInt=-1 then Write('no') else begin
  //enpassant:=TBoard_squares(enpassantInt);
  Write(GetEnumName(TypeInfo(TBoard_squares), ord(enpassantInt)));
  end;
  Writeln('');
end;
// parse FEN string
function parse_fen(sfen:String):boolean;
var
// i,j - индекс массива
// len_fen - длина строки fen
// n64 - счетчик шахматных клеток (64 клетки)
// num - позиция символа в strN или strF
i,j,len_fen,n64,num:integer;
//строки для цифр из fen строки -  strN, фигур - strF, единичного символа - s01
strN,strF,s01,strA:string;
bt:Byte;
bb_piece:Tencode_pieces;
begin
 //если fen строка пустая, то ошибка fen строки
 result:=false;
 if sfen='' then exit;
// reset board position (bitboards)
bt:=0;
FillChar(bitboards_12, 12*SizeOf(UInt64), bt);
// reset occupancies (bitboards)
FillChar(occupancies_3, 3*SizeOf(UInt64), bt);
// reset game state variables
// side to move
side := black;
// enpassant square
enpassantInt:=-1;
enpassant:=a8;//заведомо ложное поле
// castling rights
castle:=0;
// инициализация строк для парсинга fen строки
 strN:='12345678';
 strF:='PNBRQKpnbrqk';
 strA:='abcdefgh';
//определяем длину fen строки
   len_fen:=length(sfen);
//сбрасываем счетчик
   n64:=-1;
//перебираем символы fen строки
      for i := 1 to len_fen do begin
      //берем один символ  fen строки на позиции i
      //возвращает подстроку строки sfen начинающуюся с индекса i длиной 1 символ
         s01:=copy(sfen,i,1);
      //возвр. позицию символа s01 в строке strN, если нет символа, то 0
      //сначала проверяем s01 - это цифра?
         num:=pos(s01,strN);
      //continue прерывает только выполнение текущей итерации,
      //текущего выполнения тела цикла
      //и передает управление на следующую итерацию.
         if s01='/' then continue;
      //если пробел заканчиваем парсинг   
         if s01=' ' then begin
         num:=pos(' ',sfen);
         sfen:=copy(sfen,num+1,len_fen-num);
             for j := 1 to length(sfen) do begin
               s01:=copy(sfen,j,1);
               if s01=' ' then continue;
               // side to move
               if s01='w' then begin side := white; continue;end;
               case Ord(sfen[j]) of
                    Ord('K'):begin castle:=castle or integer(wk);end;
                    Ord('Q'):begin castle:=castle or integer(wq);end;
                    Ord('k'):begin castle:=castle or integer(bk);end;
                    Ord('q'):begin castle:=castle or integer(bq);end;
               end;
               if (((sfen[j] >= 'a') and (sfen[j] <= 'h'))  and ((sfen[j+1] = '3') or (sfen[j+1] = '6'))) then begin
                  enpassantInt:=pos(copy(sfen,j,1),strA)-1+8*(8-(pos(copy(sfen,j+1,1),strN)));
                  enpassant:=TBoard_squares(enpassantInt);
               end;
              // Writeln(sfen[j]);
              end;
         break;
         end;
      //увеличиваем счетчик шахматных клеток n64
      // если num=0, значит символ s01 фигура
         if num=0 then begin
              Inc(n64);
      // иначе цифра
         end else begin
              n64:=n64+num;
         end;
      //если клеток больше 64(0..63), то ошибка fen строки
         if n64>63 then exit;
      //проверяем s01 - это символ фигуры?
          num:=pos(s01,strF);
      //если num - это не допустимый символ,  то ошибка fen строки
          if ((num=0) and (pos(s01,strN)=0))then exit;
      //заносим фигуры в массивы    
          if num>0 then begin
           //Tencode_pieces=( P_, N_, B_, R_, Q_, K_, p, n, b, r, q, k);
          set_bit(bitboards_12[Tencode_pieces(num-1)],TBoard_squares(n64));
          end;
      end;//for
//если клеток не равно 64(0..63), то ошибка fen строки
  if n64<>63 then exit;
//если королей не равно 1, то ошибка fen строки
if count_bits(bitboards_12[K_])<>1 then exit;
if count_bits(bitboards_12[k])<>1 then exit;
               // loop over white  pieces bitboardsoop over all piece bitboards
               for bb_piece := P_ to K_ do
               // populate white occupancy bitboard
               occupancies_3[white] := occupancies_3[white] or bitboards_12[bb_piece];
               // loop over black pieces bitboardsoop over all piece bitboards
               for bb_piece := p to k do
               // populate black occupancy bitboard
               occupancies_3[black] := occupancies_3[black] or bitboards_12[bb_piece];
               // init all occupancies
               occupancies_3[both] := occupancies_3[both] or occupancies_3[white] or occupancies_3[black];
//парсинг завершен успешно
//print_board();
result:=true;
end;

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

Bitboard в программировании шахмат №2 01 Фев 2023 08:13 #131

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Урок 21.Bitboard CHESS ENGINE in C: implementing routine to find out whether SQUARE IS ATTACKED
Процедура для определения того, подвергается ли поле доски атаке.
На СИ конечно это все короче, но как есть
// is square current given attacked by the current given side
function is_square_attacked(square:TBoard_squares;sd:TSide):integer;
begin
// attacked by white pawns
if ((sd = white) and ((pawn_attacks[black][square] and bitboards_12[P_])>0)) then
begin
  result:=1;exit;
end;
// attacked by black pawns
if ((sd = black) and ((pawn_attacks[white][square] and bitboards_12[p])>0)) then
begin
  result:=1;exit;
end;
// attacked by knights
if ((sd = white) and ((knight_attacks[square] and bitboards_12[N_])>0)) then
begin
  result:=1;exit;
end;
if ((sd = black) and ((knight_attacks[square] and bitboards_12[n])>0)) then
begin
  result:=1;exit;
end;
// attacked by bishops
if ((sd = white) and ((get_bishop_attacks(square, occupancies_3[both]) and bitboards_12[B_])>0)) then
begin
  result:=1;exit;
end;
if ((sd = black) and ((get_bishop_attacks(square, occupancies_3[both]) and bitboards_12[b])>0)) then
begin
  result:=1;exit;
end;
// attacked by rooks
if ((sd = white) and ((get_rook_attacks(square, occupancies_3[both]) and bitboards_12[R_])>0)) then
begin
  result:=1;exit;
end;
if ((sd = black) and ((get_rook_attacks(square, occupancies_3[both]) and bitboards_12[r])>0)) then
begin
  result:=1;exit;
end;
// attacked by queens
if ((sd = white) and ((get_queen_attacks(square, occupancies_3[both]) and bitboards_12[Q_])>0)) then
begin
  result:=1;exit;
end;
if ((sd = black) and ((get_queen_attacks(square, occupancies_3[both]) and bitboards_12[q])>0)) then
begin
  result:=1;exit;
end;
// attacked by kings
if ((sd = white) and ((king_attacks[square] and bitboards_12[K_])>0)) then
begin
  result:=1;exit;
end;
if ((sd = black) and ((king_attacks[square] and bitboards_12[k])>0)) then
begin
  result:=1;exit;
end;
  result:=0;
end;
// print attacked squares
procedure print_attacked_squares(sd:TSide);
var
rank_,file_,sq:integer;
begin
Writeln('');
  // loop over board ranks
  for rank_ := 0 to 7 do  begin
        // loop over board files
        for file_ := 0 to 7 do  begin
           // convert file & rank into square index
           sq:=rank_*8 + file_;
                      //// print ranks
           if file_ = 0 then begin
           Write(8 - rank_);Write(' ');
           end;
           Write(' ');
           // check whether current square is attacked or not
           Write(is_square_attacked(TBoard_squares(sq),sd));
        end;
        // print new line every rank
        Writeln('');
  end;
  // print new line
  Writeln('');
  // print board files
  Writeln('   a b c d e f g h');
  Writeln('');
end;
if parse_fen('r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1 ')=false then Writeln('Ошибка FEN строки ...');
  print_board();
  print_attacked_squares(white);
  Writeln('Нажмите <ENTER>, чтобы выйти ...');
  Readln;

48.jpg

Вроде функция работает правильно.
Алгоритм такой:
Все ходы в шахматах (за исключением ходов пешек и рокировках) обладают очень интересным свойством.
Если фигура атакует из клетки A в клетку B, то если ее переместить в клетку В она всегда будет атаковать клетку А.
А из этого следует, что поставив на клетку В, которую мы хотим проверить, например слона он будет бить вражеского слона на клетке А тогда и только тогда, когда слон А бьет клетку В.
Аналогичная логика работает со всеми фигурами

Bitboard в программировании шахмат №2 01 Фев 2023 12:57 #132

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Хотел обобщить шаги для создания шахматного движка на основе битбоард.
Итак.
1. Атаки прыгающих фигур (король,конь,пешка)
2. Атаки скользящих фигур (слон,ладья,ферзь)
3. Представление данных о позиции в памяти компа.
4. Интерфейс (взаимодействие с человеком) для наглядного представления работы движка.
5. Функции
- подсчет битов в числе
- нахождение первого установленного бита в числе
- проверка установлен ли бит в любой позиции числа
- сброс любого бита в числе
- нахождение для каждого поля доски всех атак на это поле со стороны фигур, принадлежащих белым или черным

Далее Макс, ну и я))) преступим к реализации генератора ходов, т.е. будем учить движок ходить по шахматным правилам.
На самом деле, это очень даже интересно.
А пока видео от Макса, как он проводил тесты скорости.

Last Edit: 04 Фев 2023 07:06 by alexlaw.
The following user(s) said Thank You: Andralex

Bitboard в программировании шахмат №2 04 Фев 2023 07:17 #133

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
22.Bitboard CHESS ENGINE in C: writing GENERATE MOVES function skeleton (скелет GENERATE MOVES)
23.Bitboard CHESS ENGINE in C: generating QUIET PAWN moves (тихие ходы пешек)
24.Bitboard CHESS ENGINE in C: generating PAWN CAPTURE moves (ходы взятие пешек)
25.Bitboard CHESS ENGINE in C: generating CASTLING MOVES (рокеровка)
26.Bitboard CHESS ENGINE in C: generating SLIDER & LEAPER piece MOVES by attack tables lookup
(генерация ходов скользящих и прыгающих фигур с помощью таблиц атак)

Итак генератор ходов, если быть точным, то псевдо ходов, так сказал Макс в одном из комментариев.
Потому что король может пойти под шах, и этот момент будет отслеживаться в функции - сделать ход
Warning: Spoiler! [ Click to expand ]









r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1
Для этой позиции должно быть 48 ходов
Warning: Spoiler! [ Click to expand ]
Last Edit: 04 Фев 2023 07:21 by alexlaw.

Bitboard в программировании шахмат №2 04 Фев 2023 07:31 #134

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Гдето я прочитал, что наибольшее количество легальных ходов в шахматной позиции составляет 218 ходов.
Но на вскидку не нашел эту позицию.
Какая она, эта позиция?
Мне оч даже любопытно.

Bitboard в программировании шахмат №2 04 Фев 2023 08:29 #135

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Мне кажется следующее видео Макса оч важно.
По сути это и был вопрос с которым я изначально обратился на форум.

Bitboard в программировании шахмат №2 04 Фев 2023 09:11 #136

  • Vladimirovich
  • Vladimirovich's Avatar
  • NOW ONLINE
  • Инквизитор
  • Posts: 107223
  • Thank you received: 2097
  • Karma: 105
alexlaw wrote:
Гдето я прочитал, что наибольшее количество легальных ходов в шахматной позиции составляет 218 ходов.
Но на вскидку не нашел эту позицию.
Какая она, эта позиция?
Мне оч даже любопытно.

Да что-то такое было... Но это дикость :)
Надо видимо пешек наставить на 7ю с кучей взятий и т.д.

Практический рекорд 75
Список мировых шахматных рекордов
Каждому - своё.

Bitboard в программировании шахмат №2 04 Фев 2023 21:37 #137

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
27.Bitboard CHESS ENGINE in C: binary formatting of MOVE ITEMS
(двоичное форматирование ЭЛЕМЕНТОВ ПЕРЕМЕЩЕНИЯ)
28.Bitboard CHESS ENGINE in C: encoding & decoding MOVE ITEMS

Warning: Spoiler! [ Click to expand ]


Warning: Spoiler! [ Click to expand ]


В делфи нет макросов, сделал "форматирование ЭЛЕМЕНТОВ ПЕРЕМЕЩЕНИЯ" через функции.

Bitboard в программировании шахмат №2 05 Фев 2023 15:33 #138

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
29.Bitboard CHESS ENGINE in C: implementing MOVE LIST + ADD MOVE, PRINT MOVE, PRINT MOVE LIST functions
(реализация функций СПИСКА ПЕРЕМЕЩЕНИЯ + ДОБАВЛЕНИЕ ПЕРЕМЕЩЕНИЯ, ПЕЧАТЬ ПЕРЕМЕЩЕНИЯ, ПЕЧАТЬ СПИСКА ПЕРЕМЕЩЕНИЙ)
30.Bitboard CHESS ENGINE in C: populating MOVE LIST with newly GENERATED MOVES
(заполнение СПИСКА ПЕРЕМЕЩЕНИЙ вновь СГЕНЕРИРОВАННЫМИ ПЕРЕМЕЩЕНИЯМИ)

File Attachment:

File Name: bbc_lesson29_30.zip
File Size: 15 KB


Попробовал списки делфи для хранения, добавления и печати списков ходов.
Warning: Spoiler! [ Click to expand ]

Не уверен, что это лучший вариант.
Но вроде работает.


Warning: Spoiler! [ Click to expand ]

Bitboard в программировании шахмат №2 06 Фев 2023 08:30 #139

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
alexlaw wrote:
1. Атаки прыгающих фигур (король,конь,пешка)
2. Атаки скользящих фигур (слон,ладья,ферзь)
3. Представление данных о позиции в памяти компа.
4. Интерфейс (взаимодействие с человеком) для наглядного представления работы движка.
5. Функции
- подсчет битов в числе
- нахождение первого установленного бита в числе
- проверка установлен ли бит в любой позиции числа
- сброс любого бита в числе
- нахождение для каждого поля доски всех атак на это поле со стороны фигур, принадлежащих белым или черным
6. Генератор ходов
7. Сохранять и восстанавливать состояние текущей позиции (или отменять ход) после применения функции сделать ход (MAKE MOVE)

Мне кажется, что реализация "отменить ход" - сложнее, чем сохранить позицию с флагами и затем восстановить.
Есть интереснаяфункция memcpy (СИ).
В делфи тоже она есть - Move
Я не знал об этом.
Операция "@" - это получение адреса объекта. Операция "^" - получение
объекта по его адресу (под объектом я понимаю тут всё, что может занимать
память, а не только то, что называют объектом в ООП). Теперь разберёмся,
что такое нетипизированный параметр. Это такой параметр, что при вызове
функции надо указать некий объект, а реально функции будет передан
адрес этого объекта. Таким образом, функция Move фактически получает два адреса,
хотя формально ей передаются два объекта, и она копирует байты из одного
адреса в другой. Следовательно, на входе нам нужно передать в неё объекты,
которые располагаются по тем адресам, которые нас интересуют
Move(Source,Dest[j],Count);
Move(Source^,Dest^[j],Count);


Както так
31.Bitboard CHESS ENGINE in C: preserving & restoring BOARD STATE aka COPY/MAKE approach

// preserve board state
procedure copy_board();
begin
Move(bitboards_12[P_],bitboards_12_copy[P_],96);
Move(occupancies_3[white],occupancies_3_copy[white],24);
Move((@add_move^.move[0])^,(@add_move_copy^.move[0])^,256*SizeOf(integer));
Move((@add_move^.count)^,(@add_move_copy^.count)^,SizeOf(integer));
side_copy:=side;
enpassantInt_copy:=enpassantInt;
enpassant_copy:=enpassant;
castle_copy:=castle;
end;
// restore board state
procedure take_back();
begin
Move(bitboards_12_copy[P_],bitboards_12[P_],96);
Move(occupancies_3_copy[white],occupancies_3[white],24);
Move((@add_move_copy^.move[0])^,(@add_move^.move[0])^,256*SizeOf(integer));
Move((@add_move_copy^.count)^,(@add_move^.count)^,SizeOf(integer));
side:=side_copy;
enpassantInt:=enpassantInt_copy;
enpassant:=enpassant_copy;
castle:=castle_copy;
end;

Я кстати не знаю почему Макс не сохраняет ходы с флагами, а только доски.
Дальше у него идут уроки по MAKE MOVE (сделать ход)
Last Edit: 06 Фев 2023 08:32 by alexlaw.

Bitboard в программировании шахмат №2 06 Фев 2023 11:58 #140

  • Vladimirovich
  • Vladimirovich's Avatar
  • NOW ONLINE
  • Инквизитор
  • Posts: 107223
  • Thank you received: 2097
  • Karma: 105
alexlaw wrote:
Есть интереснаяфункция memcpy (СИ).
В делфи тоже она есть - Move
Я не знал об этом.
Это не совсем одно и то же...
Move это C-аналог memmove, а не memcpy
Аналог memcpy это CopyMemory вроде (еще Copy есть, но это тоже немного другое)

Разница довольно тонкая, но в Дельфи надо отдельно разбираться с особенностями. Может там и без разницы, не знаю.
В С там все понятно.

Но в любом случае это очень низкоуровневые операции. Для Дельфи и объектов плохо рекомендовано.
Получить облом в виде порчи памяти или утечек оной очень легко.
Каждому - своё.
Last Edit: 06 Фев 2023 12:13 by Vladimirovich.

Bitboard в программировании шахмат №2 06 Фев 2023 13:14 #141

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Сразу задался вопросом, правильно или нет использовать функцию Move или реализовывать как то по другому.
Ответ на цитатуVladimirovich wrote:
Аналог memcpy это CopyMemory вроде
нашел.

При вызове CopyMemory Delphi вызывает не API-функцию с таким именем, а свою, исходный код которой можно найти в Windows.pas:
procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;

Еще провел тест
init_all();
  if parse_fen('N7/8/2K5/8/8/8/8/7k w - - 0 1')=false then Writeln('Ошибка FEN строки ...');
  New(add_move);New(add_move_copy);
  generate_moves();
  print_move_list();
  copy_board();
  print_move_list();








N7/8/2K5/8/8/8/8/7k w - - 0 1


Warning: Spoiler! [ Click to expand ]


Исходную память не нарушил, хотя почему назвали Move, не понятно
Для меня важно, чтобы не вылезла какая нибудь трудноуловимая ошибка.
Но вроде все работает, как задумал Макс, только в реализации делфи.
Будем двигаться дальше вместе с Максом
Last Edit: 06 Фев 2023 13:16 by alexlaw.

Bitboard в программировании шахмат №2 06 Фев 2023 13:23 #142

  • Vladimirovich
  • Vladimirovich's Avatar
  • NOW ONLINE
  • Инквизитор
  • Posts: 107223
  • Thank you received: 2097
  • Karma: 105
alexlaw wrote:
Для меня важно, чтобы не вылезла какая нибудь трудноуловимая ошибка.
Это возникнет, если адреса или Count нарушить
Если нет, то все хорошо. Иначе будет больно :)

P.S. Главная разница в том, что изначальная memcpy в С вообще ничего не проверяет, в отличие от memmove.
Поэтому она быстрее.
Понятно, что поздние реализации много чего накрутили поверх, так что надо смотреть конкретно в каждом случае
Каждому - своё.
Last Edit: 06 Фев 2023 13:29 by Vladimirovich.

Bitboard в программировании шахмат №2 07 Фев 2023 09:41 #143

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
32.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (moving pieces)
Скелет функции - MAKE MOVE
Мне нравится, что Макс дает инфу по чуть.
Не спешит сразу все.
Короче можно уже подвигать фигурами.

lesson32.gif


Warning: Spoiler! [ Click to expand ]

Bitboard в программировании шахмат №2 07 Фев 2023 10:00 #144

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Кстати заметил такую вещь
add_move^.move[i]
Warning: Spoiler! [ Click to expand ]

Скобок "[]" - нет.
Буду иметь ввиду.

Bitboard в программировании шахмат №2 07 Фев 2023 20:39 #145

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
33.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (handling captures)
(ходы взятия)
34.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (handling pawn promotions)
(превращение пешек)
35.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (handling enpassant moves)
(взятие на проходе)
36.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (handling double pawn pushes)
(установка битого поля)
37.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (handling castling moves)
(рокеровка)
38.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (updating castling rights)
(обновление флагов рокеровки)
39.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (updating occupancy bitboards)
(массивы занятости - белые, черные, все фигуры)
40.Bitboard CHESS ENGINE in C: implementing MAKE MOVE function (checking whether the king is in check)
(проверка на легальность хода - король под ударом или нет)

Узнал много нового.
Результат 40 уроков
Last Edit: 08 Фев 2023 06:52 by Vladimirovich. Reason: unused zip removed

Bitboard в программировании шахмат №2 09 Фев 2023 21:13 #146

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
К сожалению я не смог адаптировать код СИ
// perft driver
static inline void perft_driver(int depth)
{
    // reccursion escape condition
    if (depth == 0)
    {
        // increment nodes count (count reached positions)
        nodes++;
        return;
    }
    
    // create move list instance
    moves move_list[1];
    
    // generate moves
    generate_moves(move_list);
    
        // loop over generated moves
    for (int move_count = 0; move_count < move_list->count; move_count++)
    {   
        // preserve board state
        copy_board();
        
        // make move
        if (!make_move(move_list->moves[move_count], all_moves))
            // skip to the next move
            continue;
        
        // call perft driver recursively
        perft_driver(depth - 1);
        
        // take back
        take_back();
    }
}

Т.е. могу сохранить одну позицию с флагами.
Когда больше одной позиции то позиции, точнее ходы теряются.
Пришлось делать заплатки в виде стека.
В итоге тест perft не прошел.
Причем только в одной тестовой позиции и на глубине больше 5







8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -

Warning: Spoiler! [ Click to expand ]


В других позициях прошел

Warning: Spoiler! [ Click to expand ]


Прогнал через профайлер

Warning: Spoiler! [ Click to expand ]

Bitboard в программировании шахмат №2 10 Фев 2023 07:39 #147

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Одну проблему решил)))
Избавился от стека, он жрал много времени

Warning: Spoiler! [ Click to expand ]


Стал пошустрее работать генератор ходов.

Но косяк где-то есть.
Тесты perft не для всех позиций проходит корректно.

Bitboard в программировании шахмат №2 10 Фев 2023 08:13 #148

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Посмотрел, как функция теперь много кушает времени
Warning: Spoiler! [ Click to expand ]


И это конечно же битовые операции, на то это и есть битбоард.

Посмотрел какие есть алгоритмы

Обстоятельно о подсчёте единичных битов

Есть куда развиваться))

Но надо найти косяк в генераторе, - будем искать)

Bitboard в программировании шахмат №2 10 Фев 2023 08:34 #149

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Итак есть позиция







8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -
На глубине 5 все хорошо

Warning: Spoiler! [ Click to expand ]


На глубине 6 уже не все хорошо

Warning: Spoiler! [ Click to expand ]


Нужно найти, где потерян ход и почему

Пока не соображу, как это сделать.
Исходные данные.
1. Эталонная прога от Макса (можно внести изменения) _ Какие?
2. Прога, где есть ошибка

У кого есть, что предложить - алгоритм поиска ошибки?

Ясно, что нужно найти - в каком месте (какой ход) теряется.
Буду признателен за идею

PS: Заметил - ход b4b3 - число ходов совпадает
Last Edit: 10 Фев 2023 08:59 by alexlaw.

Bitboard в программировании шахмат №2 10 Фев 2023 13:40 #150

  • alexlaw
  • alexlaw's Avatar
  • OFFLINE
  • Дьяк
  • Posts: 194
  • Thank you received: 10
  • Karma: 1
Итак начал вырисовываться план.
1. Находим из предыдущей таблицы наименьшую разницу в ходах
- b4a4 - 745667
- b4a4 - 745500
Разница 167 ходов
2. Обрезаем программно все другие ходы
- if ((depth=6) and (j<>5))then continue; Делфи
- if ((depth==6) & (move_count != 5)) continue; Си
3. Делаем проверку (сначала depth=5)
- выводим на глубине 1 - ходы короля
Делфи
if ((depth = 1) and (Tencode_pieces(get_source(add_move^.move[j],get_move_piece))=K_)) then begin
 old_nodes := nodes - cummulative_nodes;
 cummulative_nodes:=nodes;
 Writeln('move_test:',square_to_coordinates[integer(get_source(add_move^.move[j],get_move_source))],
 square_to_coordinates[integer(get_source(add_move^.move[j],get_move_target))],
 promoted_pieces[get_source(add_move^.move[j],get_move_promoted)],' nodes:',old_nodes);
end;//test
Си
if ((depth == 1) & (get_move_piece(move_list->moves[move_count])==K))
       {

        old_nodes = nodes - cummulative_nodes;
        cummulative_nodes = nodes;
        printf("     move: %s%s%c  nodes: %ld\n", square_to_coordinates[get_move_source(move_list->moves[move_count])],
                                                 square_to_coordinates[get_move_target(move_list->moves[move_count])],
                                                get_move_promoted(move_list->moves[move_count]) ? promoted_pieces[get_move_promoted(move_list->moves[move_count])] : ' ',
                                                 old_nodes);
       }

Warning: Spoiler! [ Click to expand ]


Так уже хорошо))

Далее надо поймать разницу при depth=6 и напечатать позицию

PS
Порядок ходов почему то разный

Warning: Spoiler! [ Click to expand ]


Сравнил
Первых четырех ходов у меня нет

Warning: Spoiler! [ Click to expand ]


Значит гдето близко разгадка))
Last Edit: 10 Фев 2023 14:04 by alexlaw.
Moderators: Grigoriy
Рейтинг@Mail.ru

Научно-шахматный клуб КвантоФорум