Я так понимаю автора как раз интересует как битовыми операциями найти этого ближайшего к ладье коня на линии d и отсечь оставшиеся поля.
Не вопрос. Одна битовая 64-маска - наличие фигуры вообще
Вторая цвет.
Т.е найти коня просто. Притом определить, надо ли включать d6 в маску запрещения или нет.
Отсечь сложнее
Если он 1 на линии d да, а если на d5 белый слоник, на d7 черная пешка на d8 черный ферзь, то надо как-то понять что ладья ничего не берёт.
Я про это. alexlaw wrote:
Если он 1 на линии d да, а если на d5 белый слоник, на d7 черная пешка на d8 черный ферзь, то надо как-то понять что ладья ничего не берёт.
Я про это.
Ну да, белая фигура по ходу должна резать все, что за ней. - красные клетки на картинке ранее
Точную битовую формулу сейчас крайне лень писать, должно быть построено на битовых сдвигах в направлении, но в хедере воблы все должно быть.
Первый шаг к вращаемым bitbord - FirstRankAttacks256x8
Атаки первого ранга (атаки по одной горизонтали)
Предположим, что мы (временно) уменьшаем шахматную доску до одного разряда (биты 0-7). Занятость битовой маски составляет один байт с 256 различными состояниями бит. Атака ладьи с одного из восьми полей на этой одиночной горизонтали также составляет всего один байт. Таким образом, мы можем создать массив байтов[256][8], проиндексированный по всем 256 занятиям полей фигурами и одном из 8 положением ладьи и предварительно рассчитать атаку этой ладьи по этой горизонтали.
BYTE arrFirstRankAttacks256x8[256][8]; // 2048 Bytes = 2KByte
Теперь для нахождения атаки ладьи достаточно просто обратиться к массиву arrFirstRankAttacks256x8[256][8], где первый индекс расположение фигур на горизонтали, второй индекс положение ладьи.
firstRankAttack = arrFirstRankAttacks256x8[rankOccupancy][squareOnRank];
Вроде все понятно и реализовывается просто. Тестовая прога
В статье сказано, что что внешние квадраты не имеют значения (крайние биты) и массива [64][8] вполне достаточно для реализации идеи предварительного расчета атак ладьи и получения этих атак простым обращением к массиву -
BYTE arrFirstRankAttacks64x8[64][8]; // 512 Bytes = 1/2KByte
К сожаление у меня не получилось использовать массив [64][8];
Как это сделать пока не соображу(
Получилось)
Агоритм такой:
1. Цикл1 i := 0 to 63 //всевозможные комбинации расположурия фигур (игнорируем первый и последний бит горизонтали
2. Цикл2 j := 0 to 7 //поз белой ладьи, 0 и 7 ладья расположена на краях горизонтали
3. AllPiece(все фигуры на горизонтали) << 1(сдвигаем на 1 бит в сторону LSB (Наименьший значащий бит))
4. Находим линию атаки от позиции ладьи до ближайших фигур для (AllPiece<<1) и объеденяем их операцией OR
5. Для позиций ладьи 0 и 7 атаки находим для AllPiece без исключения позиции ладьи (ладья атакует сама себя)
При других индексах позиции ладьи исключаем ее (ладья НЕ атакует сама себя)
6. заполняем массив arrFirstRankAttacks64x8[64][8]
Массив arrFirstRankAttacks64x8[64][8] заполняется один раз при запуске программы
Получение значений массива в зависимости от положения фигур и ладьи
1.n=arrFirstRankAttacks64x8[(AllPiece >> 1) & 63][squareOnRank]
где squareOnRank - позиция ладьи
AllPiece - битовая маска всех фигур на горизонтали
Для горизонтали мы научились и это просто, т.к. соседние биты идут подряд.
Расположение всех фигур на горизонтале A8-H8 будет соответствовать число 255.
Младший бит у нас A8 -LSB, старший H1 - MSB.
Сегодня наконец то мне пришла идея, как реализовать концепцию предварительно рассчитанных атак ладьи по вертикали.
Как пишут умные люди для этого нужно иметь еще один битбоард повернутый на 90 градусов и обновлять его одновременно с основным.
Мне такая идея не по душе.
Итак имеем допустим такую позицию
Позиция черных фигур соответствует числу U64 - 72340172838076673
А нам нужно, чтобы позици укладывалась в число 255
Идея такая
Перенести биты с вертикали А1-А8 на горизонталь А8-H8, повернуть на 90 градусов относительно A8.
function rotate90degree(U64: UInt64):UInt64;
var
i:Integer;
Temp64,result64: UInt64;
begin
result:=0;
Temp64:=U64 and 72340172838076673;
for i := 0 to 7 do begin
if (Temp64 and LineA1H8[i*8])>0 then result:=result or (LineA1H8[i*8] and 255);
end;
end;
Будьте внимательны.alexlaw wrote:
Атаки первого ранга (атаки по одной горизонтали)
Нам же нужно заполнить массив предварительных атак ладьи по вертикале - Атаки первого ранга по вертикале
Размерность - первый индекс 255
Да не нужно никаких атак первого и пр. ранга.
Все атаки ладьи это 64-число
На него накладываются другие маски - свои и чужие фигуры и т.д и получается итоговое 64-число
Я же привел типовые картинки
А 255 это уже совсем ни к чему в данной концепции
Впрочем, как хотите
Я не тактик, я стратег
Любимый анекдот в тему
Жили-были мыши и все их обижали. Как-то пошли они к мудрому филину
и говорят:
— Мудрый филин, помоги советом. Все нас обижают, коты разные, совы.
Что нам делать?
Филин подумал и говорит:
— А вы станьте ёжиками. У ёжиков иголки, их никто не обижает.
Мыши обрадовались и побежали домой. Но по дороге одна мышка сказала:
— Как же мы станем ёжиками? — и все побежали обратно, чтобы задать
этот вопрос мудрому филину.
Прибежав, они спросили:
— Мудрый филин, а как же мы станем ёжиками?
И ответил филин:
— Я не тактик, я страгег.
Пришел мужик в гости к соседу, смотрит, а тот шахматную позицию анализирует.
- А жена твоя где?
- В сарае - дрова колет.
- Ну-у, сосед, и не стыдно тебе? Ты тут сидишь в тепле, позицию анализируешь, а она там на холоде дрова колет.
- А что я могу сделать, если она в шахматы играть не умеет?
Жена - мужу:
- Ну и где ты был???!!!
- С Серегой в шахматы играли...
- А почему-же от тебя водкой пахнет?!
- А что, от меня должно шахматами пахнуть???
Терзают меня смутные сомнения, что это метод не даст преимущество в скорости.
Надо прогнать через профайлер и будет видно. что быстрее.
Потом навпишу результат
Delphi 10 Lite - модификация Delphi 2006, не требующая наличия .NET. Размер архива - 63.7 MB, что тем не менее позволяет создавать полноценные программы. Особенности:
- Очень маленький размер дистрибутива. Включены только Standard Components и Database Components.
- Выключены все установочные опции, КРОМЕ "Source code".
- Добавлен программный шрифт Monospac821 BT. Рекомендуемые установки: размер 8 с включенным ClearType.
- Утилита Delphi Tweaks, расположенная в программной группе "Delphi 10 Lite", позволяет настраивать Delphi IDE. Оптимальные настройки уже применены, так что на самом деле нет необходимости запускать Delphi Tweaks кроме тех случаев, когда вы захотите вернуть стандартные настройки.
- BORLNDMM.DLL обновлена до FastMM v4.62.
- Refactoring, ErrorInsite и поддержка ActiveX отключены, т.к. требуют наличия .NET Framework.
- Welcome Page удалена.
- Добавлена утилита OpenHelp из Delphi 7.
- Опциональные компоненты вынесены в отдельные установщики.
- Справочная система заменена справкой из Delphi 7, которая намного лучше и также не требует .NET Framework SDK.
- Update 1 уже применен (версия IDE = 10.0.2166.28377)
Стараюсь комментировать код, надеюсь не очень запутанно
Исправил ошибку
unit VisualBoard;//UI-визуализаци польз. итерфейса alexlaw@list.ru
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Menus;
type
TFormBoard = class(TForm)
ChessBoard: TImage;//изображение шахматной доски
Desk: TImage;//изображение клеток шахматного поля
Piece: TImage;//изображение всех фигур
SelectBox: TImage;//изображение рамки выбора
MainMenu1: TMainMenu;
Menu1: TMenuItem;
PosTest: TMenuItem;
Position1: TMenuItem;
Position2: TMenuItem;
Position3: TMenuItem;
Position4: TMenuItem;
Position5: TMenuItem;
Position6: TMenuItem;
InputFEN: TMenuItem;
//https://mf.grsu.by/UchProc/livak/arxiv_22102010/kursi/programming/lections/delphi/focus.htm?ysclid=lb931bk0vc792245318
//OnMouseDown-Нажатие клавиши мыши над компонентом.
//Возможно распознавание нажатой кнопки и координат курсора мыши.
procedure ChessBoardMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure InputFENClick(Sender: TObject);
procedure PositionClick(Sender: TObject);
//OnClick
//Щелчок мыши на компоненте и некоторые другие действия пользователя
procedure ChessBoardClick(Sender: TObject);
//OnMouseMove
//Перемещении курсора мыши над компонентом.
//Возможно распознавание нажатой кнопки и координат курсора мыши.
procedure ChessBoardMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Board: TFormBoard;
//дата
ProgrammDate:String = '04.12.2022';
Xmouse,Ymouse,NumPos:Integer;
//0-KING, 1-QUEEN, 2-ROOK, 3-BISHOP, 4-KNIGHT, 5-PAWN
WPieceArray: array [0..5] of UInt64 = (0,0,0,0,0,0);
BPieceArray: array [0..5] of UInt64 = (0,0,0,0,0,0);
CONST
//размеры игрового поля доски
DescHeight:Integer=480;
DescWidth:Integer=480;
//смещение игрового поля доски от начала координат
dX:Integer=24;
dY:Integer=20;
//размер клетки игрового поля
cell:Integer=60;
//установлен ровно один бит
MaskOneBit: array [0..63] of UInt64 = (
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,
524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,
268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,
34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,
2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,
70368744177664,140737488355328,281474976710656,562949953421312,1125899906842624,
2251799813685248,4503599627370496,9007199254740992,18014398509481984,36028797018963968,
72057594037927936,144115188075855872,288230376151711744,576460752303423488,
1152921504606846976,2305843009213693952,4611686018427387904,9223372036854775808);
implementation
{$R *.dfm}
//----------------------------------------------------------------------
//ниже инфа пока не используется
{P=1, N=2, K=3, B=5, R=6 и Q=7.
При анализе этих чисел проверяется результат piece_type&4,
и если результат ненулевой, это дальнобойная фигура.
Далее, если результат piece_type&1 отличен от нуля, эта фигура ходит по диагонали,
а если результат piece_type&2 ненулевой, то фигура может двигаться вдоль горизонталей/вертикалей.
https://www.pvsm.ru/game-development/17378?ysclid=l9zgbf9nj6679415818 }
//----------------------------------------------------------------------
//функция парсинга fen строки в массивы фигур WPiece, BPiece
//0-KING, 1-QUEEN, 2-ROOK, 3-BISHOP, 4-KNIGHT, 5-PAWN
function FenToU64(sfen:String):boolean;
var
// i - индекс массива
// k - длина строки fen
// n - счетчик шахматных клеток (64 клетки)
// num - позиция символа в strN или strF
i,k,n,num:integer;
//строки для цифр из fen строки - strN, фигур - strF, единичного символа - s01
strN,strF,s01:string;
//массивы фигур
WPieceNew: array [0..5] of UInt64;
BPieceNew: array [0..5] of UInt64;
begin
//если fen строка пустая, то ошибка fen строки
result:=false;
if sfen='' then exit;
// инициализация строк для парсинга fen строки
strN:='12345678';
strF:='KQRBNPkqrbnp';
//инициализация локальных массивов фигур
for i := 0 to 5 do begin
WPieceNew[i]:=0;
BPieceNew[i]:=0;
end;
//определяем длину fen строки
k:=length(sfen);
//сбрасываем счетчик
n:=-1;
//перебираем символы fen строки
for i := 1 to k 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 break;
//увеличиваем счетчик шахматных клеток n
// если num=0, значит символ s01 фигура
if num=0 then begin
n:=n+1;
// иначе цифра
end else begin
n:=n+num;
end;
//если клеток больше 64(0..63), то ошибка fen строки
if n>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
if num<7 then begin
WPieceNew[num-1]:=WPieceNew[num-1] or MaskOneBit[n];
end else begin
BPieceNew[num-7]:=BPieceNew[num-7] or MaskOneBit[n];
end;
end;
end;//for
//если клеток не равно 64(0..63), то ошибка fen строки
if n<>63 then exit;
//если королей не равно 1, то ошибка fen строки
// if CountBitsInt64(WPieceNew[0])<>1 then exit;
// if CountBitsInt64(BPieceNew[0])<>1 then exit;
// заполняем глобальные массивы фигур WPiece,BPiece
for i := 0 to 5 do begin
WPieceArray[i]:=WPieceNew[i];
BPieceArray[i]:=BPieceNew[i];
end;
//ShowMessage('парсинг завершен успешно');
//парсинг завершен успешно
result:=true;
end;
//процедура очистки изображения шахматной доски
procedure ClearDesk ();
var
bmp: tbitmap;
begin
try
//создаем временный bmp
bmp := tbitmap.Create;
//размером с Desk-изображение клеток шахматного поля
bmp.Height:=DescHeight;
bmp.Width:=DescWidth;
//CopyRect (Dest: TRect; Canvas: TCanvas; Source: TRect) ;
//копируем область рисунка Source(Desk) с координатами rect(0,0,DescWidth,DescHeight)
//на наш bmp в область с коорд. rect(0,0,bmp.Width,bmp.Height)
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.Desk.Canvas,rect(0,0,DescWidth,DescHeight));
//cmSrcCopy Копирует изображение источника на канву
// http://it.kgsu.ru/Delphi_6/dlph0039.html
Board.ChessBoard.Canvas.CopyMode:=cmSrcCopy;
//рисуем bmp на ChessBoard(изображение шахматной доски)
//по сути стираем все, что было на ней в виде фигур
Board.ChessBoard.Canvas.Draw(dX, dY, bmp);
finally
bmp.free;
end;
end;
//процедура рисования фигуры типа - NumP в клетке - Pos, цветом ColorP
procedure DrawPiece(Pos,NumP,ColorP: Integer);
var
bmp: tbitmap;
a,b: Integer;
begin
try
//создаем временный bmp
bmp := tbitmap.Create;
//размер клетки игрового поля
bmp.Height:=cell;
bmp.Width:=cell;
//Пример с2 - Pos:=50;
// 00110010 and 00000111 = 00000010; 50 and 7 = 2
// 00110010 shr 3 = 00000110; 50 shr 3 = 6
//A8 - a=0,b=0 H1 - a=7,b=7
a:=Pos and 7;//0..7 горизонталь (буквы)
b:=Pos shr 3;//0..7 вертикаль (цифры)
//выбераем фигуру из рисунка Piece (изображение всех фигур)
//CopyRect (Dest: TRect; Canvas: TCanvas; Source: TRect) ;
//копируем область рисунка Source(Piece) с координатами rect
//на наш bmp в область с коорд. rect(0,0,cell,cell) 60x60
//по сути рисуем выбранную фигуру NumP цвета ColorP на bmp
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.Piece.Canvas,rect(cell*NumP,cell*ColorP,cell*NumP+cell,cell*ColorP+cell));
//устанавливае прозрачным фон (желтый)
bmp.TransparentColor:=clYellow;
bmp.Transparent:=true;
//рисуем фигуру на ChessBoard-изображении шахматной доски
Board.ChessBoard.Canvas.Draw(dX+cell*a, dY+cell*b, bmp);
finally
bmp.free;
end;
end;
//рисуем позицию на доске
procedure DrawPieceBoard(APiece:array of UInt64;ColorPiece: Integer);
var
//тип фигуры
NumPiece: Integer;
i,j: Integer;
begin
NumPiece:=0;
//перебираем все массивы типа фигур
while NumPiece<6 do begin
//находим установлененый бит в APiece[NumPiece]
for i:=63 downto 0 do begin
j := (APiece[NumPiece] shr i) and 1;
case j of
1:begin
//если бит установлен рисуем фигуру в позиции i
DrawPiece(i,NumPiece,ColorPiece);
end;
end;
end;
NumPiece:=NumPiece+1;
end;
end;
//кликнули по изображению шахматной доски
procedure TFormBoard.ChessBoardClick(Sender: TObject);
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
//ShowMessage('Кликнули по полю - '+IntToStr(NumPos));
//тест
//рисуем белую ладью в клетке NumPos
ClearDesk ();
DrawPiece(NumPos,2,0);
//тест
end;
//Нажатие клавиши мыши над компонентом ChessBoard - изображение шахматной доски
procedure TFormBoard.ChessBoardMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
if Button=mbLeft then DrawPiece(NumPos,2,0);
if Button=mbRight then DrawPiece(NumPos,2,1);
end;
//отслеживаем координаты мыши на изображении шахматной доски
procedure TFormBoard.ChessBoardMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Xmouse:=X+Board.Left;Ymouse:=Y+Board.Top;
//div целочисленное деление
//вычисляем номер поля A8 - 0, H1 - 63
NumPos:= ((X-dX) div cell)+8*((Y-dY) div cell);
end;
procedure TFormBoard.InputFENClick(Sender: TObject);
var
fenpos:String;
begin
fenpos:= InputBox('Установить позицию', 'Введите FEN строку', 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR');
if not FenToU64(fenpos) then ShowMessage('Ошибка FEN строки') else begin
ClearDesk ();
DrawPieceBoard(WPieceArray,0);
DrawPieceBoard(BPieceArray,1);
end;
end;
//клик по меню выбора стандартной тестовой позиции
procedure TFormBoard.PositionClick(Sender: TObject);
var
fenpos:String;
begin
ShowMessage('Кликнули по '+IntToStr((Sender as TMenuItem).Tag));
fenpos:='';
case (Sender as TMenuItem).Tag of
1 : fenpos:='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';//нач. позиция
2 : fenpos:='r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R';
3 : fenpos:='8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8';
4 : fenpos:='r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1';
5 : fenpos:='rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R';
6 : fenpos:='r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1';
end;
if not FenToU64(fenpos) then ShowMessage('Ошибка FEN строки') else begin
ClearDesk ();
DrawPieceBoard(WPieceArray,0);
DrawPieceBoard(BPieceArray,1);
end;
end;
end.
В шахматных боях без правил разрешается использовать не только фигуры, но так же доску, часы, стул и стол.
//Нажатие клавиши мыши над компонентом ChessBoard - изображение шахматной доски
procedure TFormBoard.ChessBoardMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
if Button=mbLeft then DrawPiece(NumPos,2,0);
if Button=mbRight then DrawPiece(NumPos,2,1);
end;
Гроссмейстер от нечего делать начинает играть в шахматы с соседом по купе... и проигрывает партию. Поражённый гроссмейстер восклицает:
- И подумать только: вы могли бы поставить мне мат ещё на три хода раньше, если бы пошли ладьёй!
- Как? Ладью тоже можно передвигать? - спрашивает попутчик.
Добавил в отдельный файл fun.pas некоторые процедуры, которые понадобятся в дальнейшем, и это файл буду дополнять другими нужными процедурами.
unit fun;
interface
function CountBitsInt64(const integer64:UInt64):integer;
function SeniorBit(const Lo, Hi: LongWord): Integer;
function JuniorBit(const Lo, Hi: LongWord): Integer;
procedure init ();
procedure maskLine ();
var
//битовые маски из поля 0..63 до края доски в направлении из литера 1 в литера2
//бит поля также включен в маске
LineA1A8: array [0..63] of UInt64;
LineA8A1: array [0..63] of UInt64;
LineA1H1: array [0..63] of UInt64;
LineH1A1: array [0..63] of UInt64;
LineA1H8: array [0..63] of UInt64;
LineH8A1: array [0..63] of UInt64;
LineA8H1: array [0..63] of UInt64;
LineH1A8: array [0..63] of UInt64;
implementation
uses VisualBoard;
//Использование ассемблера в Дельфи
//http://biguniverse.narod.ru/gybels.pdf
//Подсчет количества установленных бит в integer (32 бита)
function CountBits(const Value: integer): integer;
asm
mov ECX,EAX
xor EAX,EAX
test ECX,ECX
jz @@ending
@@counting:
shr ECX,1
adc EAX,0
test ECX,ECX
jnz @@counting
@@ending:
end;
//Подсчет количества установленных бит в Int64 (64 бита)
function CountBitsInt64(const integer64:UInt64):integer;
begin
result:=CountBits(integer64)+CountBits(integer64 shr 32);
end;
//Команда BSR просматривает биты второго операнда от младшего к старшему
// и помещает индекс последнего единичного бита в регистр (для 32 бит)
function LastOne(const Value: integer): integer;
asm
bsr ECX,EAX
mov EAX,ECX
end;
function FirstOne(const Value: integer): integer;
asm
bsf ECX,EAX
mov EAX,ECX
end;
//Входное значение передается в двух частях (длинные слова Lo и Hi).
//Результат равен 0, если вход равен 0, в противном случае результат будет в [1..64].
// Lo - младшие 32 бита Hi - старшие 32 бита сдвигаем на место младших(U64 <<
//SeniorBit(U64,U64 shr 32)-1; - возвращае позицию бита 0...63
function SeniorBit(const Lo, Hi: LongWord): Integer;
asm
OR EDX,EDX
JZ @@Lo
MOV EAX,EDX
MOV EDX,32
@@Lo:
OR EAX,EAX
JZ @@Done
BSR EAX,EAX
ADD EAX,EDX
INC EAX
@@Done:
end;
//JuniorBit(Temp64,Temp64 shr 32); - возвращае позицию бита 1...64
function JuniorBit(const Lo, Hi: LongWord): Integer;
begin
if Lo=0 then begin
result:=FirstOne(Hi) + 32;
end else result:=FirstOne(Lo);
end;
procedure init ();
var
i: Integer;
begin
for i := 0 to 63 do begin
LineA1A8[i]:=0;
LineA8A1[i]:=0;
LineA1H1[i]:=0;
LineH1A1[i]:=0;
LineA1H8[i]:=0;
LineH8A1[i]:=0;
LineA8H1[i]:=0;
LineH1A8[i]:=0;
end;
end;
//расчет битовой маски из поля 0..63 до края доски (во всех 8 напралениях)
//направление ясно определяют поля в названии LineXX
procedure maskLine ();
var
i,j,z,k: Integer;
begin
for i := 0 to 63 do begin
z:=i div 8;
for j := 0 to z do begin
k:=i-j*8;
LineA1A8[i]:= LineA1A8[i] or MaskOneBit[k];
if j<=(7 - k mod 8) then begin
LineA1H8[i]:=LineA1H8[i] or (MaskOneBit[k] shl j);
end;
if j<=(k mod 8) then begin
LineH1A8[i]:=LineH1A8[i] or (MaskOneBit[k] shr j);
end;
end;
z:=7 - i div 8;
for j := 0 to z do begin
k:=i+j*8;
LineA8A1[i]:= LineA8A1[i] or MaskOneBit[k];
if j<=(7 - k mod 8) then begin
LineA8H1[i]:=LineA8H1[i] or (MaskOneBit[k] shl j);
end;
if j<=(k mod 8) then begin
LineH8A1[i]:=LineH8A1[i] or (MaskOneBit[k] shr j);
end;
end;
z:=7 - i mod 8;
for j := 0 to z do begin
LineA1H1[i]:=LineA1H1[i] or (MaskOneBit[i+j]);
end;
z:=i mod 8;
for j := 0 to z do begin
LineH1A1[i]:=LineH1A1[i] or (MaskOneBit[i-j]);
end;
end;
end;
end.
Основной файл
unit VisualBoard;//UI-визуализаци польз. итерфейса alexlaw@list.ru
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Menus;
type
TFormBoard = class(TForm)
ChessBoard: TImage;//изображение шахматной доски
Desk: TImage;//изображение клеток шахматного поля
Piece: TImage;//изображение всех фигур
SelectBox: TImage;//изображение рамки выбора
MainMenu1: TMainMenu;
Menu1: TMenuItem;
PosTest: TMenuItem;
Position1: TMenuItem;
Position2: TMenuItem;
Position3: TMenuItem;
Position4: TMenuItem;
Position5: TMenuItem;
Position6: TMenuItem;
InputFEN: TMenuItem;
procedure FormCreate(Sender: TObject);
//https://mf.grsu.by/UchProc/livak/arxiv_22102010/kursi/programming/lections/delphi/focus.htm?ysclid=lb931bk0vc792245318
//OnMouseDown-Нажатие клавиши мыши над компонентом.
//Возможно распознавание нажатой кнопки и координат курсора мыши.
procedure ChessBoardMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure InputFENClick(Sender: TObject);
procedure PositionClick(Sender: TObject);
//OnClick
//Щелчок мыши на компоненте и некоторые другие действия пользователя
procedure ChessBoardClick(Sender: TObject);
//OnMouseMove
//Перемещении курсора мыши над компонентом.
//Возможно распознавание нажатой кнопки и координат курсора мыши.
procedure ChessBoardMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Board: TFormBoard;
//дата
ProgrammDate:String = '07.12.2022';
Xmouse,Ymouse,NumPos:Integer;
//0-KING, 1-QUEEN, 2-ROOK, 3-BISHOP, 4-KNIGHT, 5-PAWN
//массивы фигур
WPieceArray: array [0..5] of UInt64 = (0,0,0,0,0,0);
BPieceArray: array [0..5] of UInt64 = (0,0,0,0,0,0);
//Белые и черные фигуры в одном 64 битном числе
WhitePieceU64:UInt64 = 0;
BlackPieceU64:UInt64 = 0;
//все фигуры в одном 64 битном числе
AllPieceU64:UInt64 = 0;
CONST
//размеры игрового поля доски
DescHeight:Integer=480;
DescWidth:Integer=480;
//смещение игрового поля доски от начала координат
dX:Integer=24;
dY:Integer=20;
//размер клетки игрового поля
cell:Integer=60;
//установлен ровно один бит
MaskOneBit: array [0..63] of UInt64 = (
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,
524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,
268435456,536870912,1073741824,2147483648,4294967296,8589934592,17179869184,
34359738368,68719476736,137438953472,274877906944,549755813888,1099511627776,
2199023255552,4398046511104,8796093022208,17592186044416,35184372088832,
70368744177664,140737488355328,281474976710656,562949953421312,1125899906842624,
2251799813685248,4503599627370496,9007199254740992,18014398509481984,36028797018963968,
72057594037927936,144115188075855872,288230376151711744,576460752303423488,
1152921504606846976,2305843009213693952,4611686018427387904,9223372036854775808);
implementation
uses fun;
{$R *.dfm}
//----------------------------------------------------------------------
//ниже инфа пока не используется
{P=1, N=2, K=3, B=5, R=6 и Q=7.
При анализе этих чисел проверяется результат piece_type&4,
и если результат ненулевой, это дальнобойная фигура.
Далее, если результат piece_type&1 отличен от нуля, эта фигура ходит по диагонали,
а если результат piece_type&2 ненулевой, то фигура может двигаться вдоль горизонталей/вертикалей.
https://www.pvsm.ru/game-development/17378?ysclid=l9zgbf9nj6679415818 }
//----------------------------------------------------------------------
//функция парсинга fen строки в массивы фигур WPiece, BPiece
//0-KING, 1-QUEEN, 2-ROOK, 3-BISHOP, 4-KNIGHT, 5-PAWN
function FenToU64(sfen:String):boolean;
var
// i - индекс массива
// k - длина строки fen
// n - счетчик шахматных клеток (64 клетки)
// num - позиция символа в strN или strF
i,k,n,num:integer;
//строки для цифр из fen строки - strN, фигур - strF, единичного символа - s01
strN,strF,s01:string;
//массивы фигур
WPieceNew: array [0..5] of UInt64;
BPieceNew: array [0..5] of UInt64;
begin
//если fen строка пустая, то ошибка fen строки
result:=false;
if sfen='' then exit;
// инициализация строк для парсинга fen строки
strN:='12345678';
strF:='KQRBNPkqrbnp';
//инициализация локальных массивов фигур
for i := 0 to 5 do begin
WPieceNew[i]:=0;
BPieceNew[i]:=0;
end;
WhitePieceU64:=0;
BlackPieceU64:=0;
//определяем длину fen строки
k:=length(sfen);
//сбрасываем счетчик
n:=-1;
//перебираем символы fen строки
for i := 1 to k 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 break;
//увеличиваем счетчик шахматных клеток n
// если num=0, значит символ s01 фигура
if num=0 then begin
n:=n+1;
// иначе цифра
end else begin
n:=n+num;
end;
//если клеток больше 64(0..63), то ошибка fen строки
if n>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
if num<7 then begin
WPieceNew[num-1]:=WPieceNew[num-1] or MaskOneBit[n];
//белые фигуры в одно 64 битное число
WhitePieceU64:=WhitePieceU64 or WPieceNew[num-1];
end else begin
BPieceNew[num-7]:=BPieceNew[num-7] or MaskOneBit[n];
//черные фигуры в одно 64 битное число
BlackPieceU64:=BlackPieceU64 or BPieceNew[num-7];
end;
end;
end;//for
//если клеток не равно 64(0..63), то ошибка fen строки
if n<>63 then exit;
//если королей не равно 1, то ошибка fen строки
if CountBitsInt64(WPieceNew[0])<>1 then exit;
{
ShowMessage('Белый король на поле - ' +
IntToStr(SeniorBit(WPieceNew[0],WPieceNew[0] shr 32)-1) +' '+ IntToStr(JuniorBit(WPieceNew[0],WPieceNew[0] shr 32)));
}
if CountBitsInt64(BPieceNew[0])<>1 then exit;
// заполняем глобальные массивы фигур WPiece,BPiece
for i := 0 to 5 do begin
WPieceArray[i]:=WPieceNew[i];
BPieceArray[i]:=BPieceNew[i];
end;
//все фигуры в одно 64 битное число
AllPieceU64:=WhitePieceU64 or BlackPieceU64;
//ShowMessage('парсинг завершен успешно');
//парсинг завершен успешно
result:=true;
end;
//процедура очистки изображения шахматной доски
procedure ClearDesk ();
var
bmp: tbitmap;
begin
try
//создаем временный bmp
bmp := tbitmap.Create;
//размером с Desk-изображение клеток шахматного поля
bmp.Height:=DescHeight;
bmp.Width:=DescWidth;
//CopyRect (Dest: TRect; Canvas: TCanvas; Source: TRect) ;
//копируем область рисунка Source(Desk) с координатами rect(0,0,DescWidth,DescHeight)
//на наш bmp в область с коорд. rect(0,0,bmp.Width,bmp.Height)
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.Desk.Canvas,rect(0,0,DescWidth,DescHeight));
//cmSrcCopy Копирует изображение источника на канву
// http://it.kgsu.ru/Delphi_6/dlph0039.html
Board.ChessBoard.Canvas.CopyMode:=cmSrcCopy;
//рисуем bmp на ChessBoard(изображение шахматной доски)
//по сути стираем все, что было на ней в виде фигур
Board.ChessBoard.Canvas.Draw(dX, dY, bmp);
finally
bmp.free;
end;
end;
//процедура рисования фигуры типа - NumP в клетке - Pos, цветом ColorP
procedure DrawPiece(Pos,NumP,ColorP: Integer);
var
bmp: tbitmap;
a,b: Integer;
begin
try
//создаем временный bmp
bmp := tbitmap.Create;
//размер клетки игрового поля
bmp.Height:=cell;
bmp.Width:=cell;
//Пример с2 - Pos:=50;
// 00110010 and 00000111 = 00000010; 50 and 7 = 2
// 00110010 shr 3 = 00000110; 50 shr 3 = 6
//A8 - a=0,b=0 H1 - a=7,b=7
a:=Pos and 7;//0..7 горизонталь (буквы)
b:=Pos shr 3;//0..7 вертикаль (цифры)
//выбераем фигуру из рисунка Piece (изображение всех фигур)
//CopyRect (Dest: TRect; Canvas: TCanvas; Source: TRect) ;
//копируем область рисунка Source(Piece) с координатами rect
//на наш bmp в область с коорд. rect(0,0,cell,cell) 60x60
//по сути рисуем выбранную фигуру NumP цвета ColorP на bmp
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.Piece.Canvas,rect(cell*NumP,cell*ColorP,cell*NumP+cell,cell*ColorP+cell));
//устанавливае прозрачным фон (желтый)
bmp.TransparentColor:=clYellow;
bmp.Transparent:=true;
//рисуем фигуру на ChessBoard-изображении шахматной доски
Board.ChessBoard.Canvas.Draw(dX+cell*a, dY+cell*b, bmp);
finally
bmp.free;
end;
end;
//рисуем позицию на доске
procedure DrawPieceBoard(APiece:array of UInt64;ColorPiece: Integer);
var
//тип фигуры
NumPiece: Integer;
i,j: Integer;
begin
NumPiece:=0;
//перебираем все массивы типа фигур
while NumPiece<6 do begin
//находим установлененый бит в APiece[NumPiece]
for i:=63 downto 0 do begin
j := (APiece[NumPiece] shr i) and 1;
case j of
1:begin
//если бит установлен рисуем фигуру в позиции i
DrawPiece(i,NumPiece,ColorPiece);
end;
end;
end;
NumPiece:=NumPiece+1;
end;
end;
//рисуем рамку выбора в полях соотвтствующим уст. битам в u:UInt64
procedure DrawMoveBox(u:UInt64);
var
bmp: tbitmap;
a,b,i: Integer;
begin
if u=0 then exit;
try
bmp := tbitmap.Create;
bmp.Height:=cell;
bmp.Width:=cell;
bmp.TransparentColor:=clWhite;
bmp.Transparent:=true;
//рамка выбора cell*6,0,cell*7 в рисунке Piece-изображение всех фигур
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.Piece.Canvas,rect(cell*6,0,cell*7,cell));
//пробегаем по числу u:UInt64
for i:=63 downto 0 do begin
//если включен бит
case (u shr i) and 1 of
1:begin
//вычисляем позицию бита на доске
a:=i and 7;
b:=i shr 3;
//рисуем рамку на доске для поля с координатами a,b
Board.ChessBoard.Canvas.Draw(dX+cell*a, dY+cell*b, bmp);
end;
end;
end;
finally
bmp.free;
end;
end;
//кликнули по изображению шахматной доски
procedure TFormBoard.ChessBoardClick(Sender: TObject);
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
//ShowMessage('Кликнули по полю - '+IntToStr(NumPos));
//тест
ClearDesk ();
//рисуем белую фигуру в клетке NumPos
//DrawPiece(NumPos,2,0);
//DrawMoveBox(LineA1A8[NumPos] or LineA8A1[NumPos] or LineA1H1[NumPos] or LineH1A1[NumPos]);
DrawPiece(NumPos,3,0);
DrawMoveBox(LineA1H8[NumPos] or LineH8A1[NumPos] or LineA8H1[NumPos] or LineH1A8[NumPos]);
//тест
end;
//Нажатие клавиши мыши над компонентом ChessBoard - изображение шахматной доски
procedure TFormBoard.ChessBoardMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
if Button=mbLeft then begin
ClearDesk ();
DrawPiece(NumPos,3,0);
end;
if Button=mbRight then DrawPiece(NumPos,2,1);
end;
//отслеживаем координаты мыши на изображении шахматной доски
procedure TFormBoard.ChessBoardMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Xmouse:=X+Board.Left;Ymouse:=Y+Board.Top;
//div целочисленное деление
//вычисляем номер поля A8 - 0, H1 - 63
NumPos:= ((X-dX) div cell)+8*((Y-dY) div cell);
end;
procedure TFormBoard.FormCreate(Sender: TObject);
begin
Board.Caption := ProgrammDate;
init ();
maskLine ();
end;
procedure TFormBoard.InputFENClick(Sender: TObject);
var
fenpos:String;
begin
fenpos:= InputBox('Установить позицию', 'Введите FEN строку', 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR');
if not FenToU64(fenpos) then ShowMessage('Ошибка FEN строки') else begin
ClearDesk ();
DrawPieceBoard(WPieceArray,0);
DrawPieceBoard(BPieceArray,1);
end;
end;
//клик по меню выбора стандартной тестовой позиции
procedure TFormBoard.PositionClick(Sender: TObject);
var
fenpos:String;
begin
//ShowMessage('Кликнули по '+IntToStr((Sender as TMenuItem).Tag));
fenpos:='';
case (Sender as TMenuItem).Tag of
1 : fenpos:='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';//нач. позиция
2 : fenpos:='r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R';
3 : fenpos:='8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8';
4 : fenpos:='r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1';
5 : fenpos:='rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R';
6 : fenpos:='r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1';
end;
if not FenToU64(fenpos) then ShowMessage('Ошибка FEN строки') else begin
//очищаем доску
ClearDesk ();
//рисуем фигуры
DrawPieceBoard(WPieceArray,0);
DrawPieceBoard(BPieceArray,1);
//выделяем все фигуры на доске
DrawMoveBox(AllPieceU64);
end;
end;
end.
– Слушай, ты же программист? Какой язык чаще всего используется программистами?
– Матерный.
Условие задачи
Среди математических развлечений давно известна задача обхода шахматной фигурой коня всех клеток шахматной доски.
Она заключается в нахождении маршрута коня на шахматной доске.
В 1823 году Варнсдорф в брошюре “Простейшее и наиболее общее решение задачи о ходе коня” предложил следующее правило обхода доски размером 8x8.
На каждом ходу ставь коня на такое поле, из которого можно совершить наименьшее число ходов на еще не пройденные поля. Если таких полей несколько, разрешается выбирать любое из них.
На практике это правило легко позволяет строить обходы доски, хотя долгое время не было известно, справедливо ли оно. Опровержение правила Варнсдорфа было найденос помощью ЭВМ “Проминь- 2” , где для любого исходного поля доски указаны контрпримеры. Иными словами, с какого бы поля конь ни начал движение, следуя правилу Варнсдорфа, его можно завести в тупик до полного обхода доски.
Но для нас это не важно и мы пойдем по пути Варнсдорфа.
//рисуем линию из центра клетки a в центр клетки b цветом c
procedure DrawLine(a,b,c:Integer);
var
bmp: tbitmap;
begin
try
bmp := tbitmap.Create;
bmp.Height:=DescHeight;
bmp.Width:=DescWidth;
//копируем доску на bmp
bmp.Canvas.CopyRect(rect(0,0,bmp.Width,bmp.Height),Board.ChessBoard.Canvas,rect(0,0,DescHeight,DescWidth));
Board.Desk.Canvas.CopyMode:=cmSrcCopy;
//выбираем цвет линии
if c=0 then bmp.Canvas.Pen.Color:=clRed else bmp.Canvas.Pen.Color:=clYellow;
//толщина линии
bmp.Canvas.Pen.Width:=5;
bmp.Canvas.Pen.Mode:=pmNop;
//переносим pen в центр клетки a
bmp.Canvas.LineTo(dX+cell*(a and 7) + (cell div 2),dY+cell*(a shr 3) + (cell div 2));
bmp.Canvas.Pen.Mode:=pmCopy;
//рисуем линию
bmp.Canvas.LineTo(dX+5*c+cell*(b and 7) + (cell div 2),dY+5*c+cell*(b shr 3) + (cell div 2));
//отображаем все на доске
Board.ChessBoard.Canvas.Draw(0, 0, bmp);
finally
bmp.free;
end;
end;
//процедура обхода конем шахматной доски
//Pos - позиция коня (0..63) A8-0; H1-63
//integer64 - 64 бит (конь посетил - 0; не посетил - 1)
// все биты вкл - FullU64:UInt64 = 18446744073709551615;
procedure KnightGO(Pos:Integer;integer64:UInt64;flag:boolean);
var
To_:UInt64;
i,best,min,n,j:Integer;
begin
//если все поля посетили то выход
if integer64=0 then exit;
j:=Pos;
min:=8;
//при первом обращении к процедуре искл позицию коня из не посещеных
if (CountBitsInt64(integer64)=64) then
To_:=KnightAttak[Pos] and (integer64 xor MaskOneBit[Pos])
else
//разрешенные ходы коня - маска ходов коня и не посещеные клетки
To_:=KnightAttak[Pos] and integer64;
//если нет доступных ходов то выходим
if To_=0 then exit;
//перебираем разрешенные ходы
for i := 0 to CountBitsInt64(To_)-1 do begin
//находим младший вкл бит (делаем ход из Pos на поле n)
n:=JuniorBit(To_,To_ shr 32);
//считаем кол ходов из поля n
best:= CountBitsInt64(KnightAttak[n] and integer64);
//если кол ходов мин, то запоминаем этот ход и номер поля
if flag then begin
if best<min then begin //не выполняется для 24 27 49
min:=best;
j:=n;
end;
end else begin
if best<=min then begin //не выполняется для 14 36 39
min:=best;
j:=n;
end;
end;
//исключаем ход для следующей итерации цикла
To_:=To_ xor MaskOneBit[n];
end;//for
//заставляет выполнить все задачи которые накопились в данный момент
Application.ProcessMessages;
//рисуем коня
DrawPiece(j,4,0);
//рисуем линию из Pos в j
DrawLine(Pos,j,0);
//рекурсивно двигаемся дальше (пока есть разр. ходы)
KnightGO(j,integer64 xor MaskOneBit[Pos],flag);
end;
//кликнули по изображению шахматной доски
procedure TFormBoard.ChessBoardClick(Sender: TObject);
var
flag:boolean;
begin
if NumPos>63 then exit;
if NumPos<0 then exit;
// ShowMessage('Кликнули по полю - '+IntToStr(NumPos));
//тест
ClearDesk ();
//рисуем белую фигуру в клетке NumPos
//DrawPiece(NumPos,2,0);
//DrawMoveBox(LineA1A8[NumPos] or LineA8A1[NumPos] or LineA1H1[NumPos] or LineH1A1[NumPos]);
//DrawPiece(NumPos,3,0);
//DrawMoveBox(LineA1H8[NumPos] or LineH8A1[NumPos] or LineA8H1[NumPos] or LineH1A8[NumPos]);
//рисуем черного коня из позиции - Кликнули по полю
DrawPiece(NumPos,4,1);
// 18446744073709551615 - все биты вкл
if (NumPos=14) or (NumPos=36) or (NumPos=39) then flag:=true
else flag:=false;
//начинаем обход доски конем
KnightGO(NumPos,18446744073709551615,flag);
//DrawPiece(NumPos,4,0);
// DrawMoveBox(KnightAttak[NumPos]);
//тест
end;
Задача о неприкосновенном короле
У белых — король на с6 (с3, f6 или f3) и ферзь, у чёрных — король. Всегда ли белые могут, не двигая своего короля, дать мат?
Решение удалось получить при помощи ЭВМ (А. Л. Брудно и И. Я. Ландау, 1969). Мат даётся не позднее 23-го хода при любом положении ферзя и чёрного короля.
При других положениях белого короля и свободном чёрном короле мат поставить нельзя.
Какой алгоритм можете предложить, для решения этой задачи?
Я имею ввиду математическую модель.
Какой алгоритм можете предложить, для решения этой задачи?
Стратегический план. Просчитать, на каком поле при неподвижности белого короля его чёрный коллега получает мат. Например, при белом короле на c6 это гибельные для чёрного поля a5, a6, a7, a8, b8, c8 и d8при условии размещения ферзя на b5, b6, b7, c7 и d7 соответственно.
Реализация плана. Манёвры ферзя.
очевидно, первым делом отсекаются ходы ферзя, ведущие к пату. Например, Qh2+ или Qg3.
Если белый король стоит на одной из центральных клеток d4-d5-e4-e5, то неясно, на каком поле ферзь заматует. Очень далеко до края доски, чёрный запросто убежит от шахов.
Ну да. Так и есть.
Осталось логику сформулировать.
Для белых одна логика, для черного падишаха другая.
Например стараться держаться в углу.
Как насчет логического описания?
Сможем совместно?
Не. Я шахматист и головоломки с шахматными фигурками фигурками меня не интересуют, особенно практически бесполезные.
Логики там нет. Есть цепь позиций которую надо построить.
Так, надо придумать маневр для начала выковыривания черного короля с а1
Тут надо создать переменную Radius которая при рассмотрении программой каждого из 8 ходов во вложенных циклах определяет расстояние между королями по
формуле
Radius := √(КЧ2-КБ2),
где КЧ и КБ - координаты королей.
Чем длиннее, тем дальше чёрный король от белого.
Как в боксе, близко к канатам.
PS. Ещё лучше, для упорства чёрных, ввести массив повторённых ходов.
Расстояние определяется проще
Пример h1 - Pos:=63;-черный король
00111111 and 00000111 = 111; 50 and 7 = 7
00111111 shr 3 = 111; 50 shr 3 = 7
с6 - Pos:=18;
18 and 7 = 2
18 shr 3 = 2
A8 - a=0,b=0 H1 - a=7,b=7
a:=Pos and 7;//0..7 горизонталь (буквы)
b:=Pos shr 3;//0..7 вертикаль (цифры)
Расстояние между h1 и c6
(7-2)+(7-2)=10!
По поводу алгоритма - неприкосновенный король.
Можно заметить, что где бы белый король не находился (на с6 (с3, f6 или f3) ) - можно виртуально повернуть доску и сразу отсечь множество вариантов.
Поэтому снова вернулся к вращаемым битбоардам.
Немного по разбирался
//функция позвращает номер поля в повернутом битбоарде
function RotatePos(const Value,mode: integer): integer;
var
a,b,c: Integer;
begin
a:=Value and 7;//0..7 горизонталь (буквы)
b:=Value shr 3;//0..7 вертикаль (цифры)
//0 - нормальное расположение a и b не меняем
result:=a+8*b;
c:=0;
case mode of
//180 - поворот на 180
180:begin
a:=7-a;
b:=7-b;
result:=a+8*b;
end;
//поворот по часовой (вправо) на 90
90:begin
c:=a;
a:=7-b;
b:=c;
result:=63-(a+8*b);
end;
//поворот против часовой (влево) на 90 или по часовой (вправо) на 270
270:begin
c:=b;
b:=7-a;
a:=c;
result:=63-(a+8*b);
end;
end;
end;
В принципе биты повернуть в 64 битном числе оказалось не сложно.