Хотите озадачить начинающего шахматиста?
Попросите его поставить мат конём и слоном.

Хотите озадачить начинающего программиста?
Попросите его рассчитать мат конём и слоном.

image

Шахматные задачи будоражат воображение программиста,
именно поэтому для практической демонстрации комбинаторики
я выбрал самую сложную шахматную задачу из цикла «мат одинокому королю».

Постановка цели


Цель проекта — создать базу решений, то есть список правильных ходов для всех возможных расположений белого короля, слона, коня и чёрного короля на шахматной доске.

В этой публикации я расскажу, как я решал эту задачу, с какими сложностями пришлось столкнуться, а также продемонстрировать, что в итоге получилось. Используемые технологии: C#, JavaScript, PHP, HTML, CSS.

Будучи весьма посредственным шахматистом, я так и не научился быстро ставить мат конём и слоном. Поэтому я решил компенсировать этот недостаток своими навыками программирования, перебрать все возможные позиции и найти для каждой правильный ход.

Прежде чем написать хоть строчку кода, я несколько недель вынашивал «наполеоновский» план, как я это буду делать. Мне очень хотелось начать решать эту задачу с конца, с перебора всех матовых комбинаций. А потом делать по одному ходу назад, пока не будут исчерпаны все возможные варианты.

Сколько всего вариантов?


На шахматной доске 64 клетки. У нас четыре фигуры.
Количество возможных комбинаций — 64 * 64 * 64 * 64 = 16,777,216.

Можно оставить только белопольного слона.
Количество вариантов уменьшится вдвое: 64 * 32 * 64 * 64 = 8,388,608.
Именно столько позиций будет в нашей базе решений.

На самом деле комбинаций ещё меньше: на одной клетке не может стоять две фигуры, короли не могут стоять на соседних клетках, чёрный король не может быть под шахом и так далее. Забегая вперёд скажу, что в базе решений оказалось 5,609,790 комбинаций, массив будет заполнен на 67%.

Однако для упрощения алгоритма и ускорения доступа к данным базы я решил «не мелочиться» и создать четырёхмерный массив для всех комбинаций.

Для хранения каждой комбинации определена такая структура:

    struct Combo
    {
        public Coord whiteKing;
        public Coord whiteBishop;
        public Coord whiteKnight;
        public Coord blackKing;
    }

Внутри используется ещё одна структура Coord для записи координат фигуры, с возможностью вычисления индекса от 0 до 63, а также с перегруженным оператором сравнения.

    public struct Coord
    {
        public byte x; // шахматная вертикаль от 0 до 7 (от a до h)
        public byte y; // шахматная горизонталь от 0 до 7
        
        public int index
        {
            get { return x + y * 8; }
            set { x = (byte) (value % 8); 
                  y = (byte) (value / 8); }
        }
        
        public static bool operator == (Coord a, Coord b)
        {
            return a.x == b.x && a.y == b.y;
        }
    }

Эта структура оказалась очень удобной для передачи в качестве аргумента в различные вспомогательные функции, например:

    bool isCheck (Combo combo); // Проверка позиции на шах
    bool isCheckmate (Combo combo); // на мат
    bool isCheckByBishop (Combo combo); // есть ли шах от слона

Однако для записи результата базы решений этой структуры не достаточно, ещё нам потребуется…

Белый ящик


Целью нашей программы будет создание «белого ящика», в который будут складываться все позиции, в которых «ход белых», и для которых известно — какой именно ход нужно делать, и через сколько ходов будет гарантированно поставлен мат.

Составной частью «белого ящика» является следующая структура:

    struct WhitesMove
    {
        public Combo combo;
        public byte moves;     // сколько ходов до мата
        public Coord moveFrom; // правильный ход - откуда
        public Coord moveTo;   // куда
    }

Для организации «белого ящика» проще всего открыть четырёхмерную матрицу. Каждая размерность этой матрицы соответствует возможной позиции каждой фигуры:

    WhitesMove [ , , , ] box = new WhitesMove [64, 32, 64, 64];

первая размерность — координата белого короля.
вторая размерность — координата белого слона / 2.
третья размерность — координата белого коня.
четвёртая размерность — координата чёрного короля.

Главное — не перепутать их порядок :) Массив получится на 33% разряженным, но уж очень удобным для обработки. Именно в этом массиве будет храниться 8,388,608 записей для решения комбинаций.

Кстати, прежде чем начать писать все алгоритмы перебора, я создал пустой проект и проинициализировал эту четырёхмерную матрицу, дабы убедиться, что памяти хватит и не надо будет что-то дополнительное изобретать. Видимо, сказался опыт участия в олимпиадах по информатике прошлого тысячелетия, где размер структуры не мог превышать 64 килобайт, ибо Turbo Pascal 7.0.

Идея алгоритма


Кратко опишу основную идею решения этой задачи. В основу взят алгоритм поиска вширь, который пришлось немного доработать, так как в шахматы играют двое и ходы делаются по очереди. Поэтому вместо одной очереди нам потребуется две — «чёрная» и «белая».

    Queue<BlacksMove> blackQueue = new Queue<BlacksMove>();
    Queue<WhitesMove> whiteQueue = new Queue<WhitesMove>();

Со структурой WhitesMove мы уже познакомились. Структура BlacksMove немного проще, так как в ней нет надобности хранить последний ход чёрных.

struct BlacksMove
    {
        public Combo combo;
        public byte moves; 
    }

Сначала в «чёрную очередь» мы разместим все матовые позиции, в которых ход чёрных. Потом из каждой такой позиции будем делать обратный ход за белых и формировать «белую очередь» — список позиций, в которых ход белых.

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

Основной алгоритм в виде псевдокода:

      Очищаем "белую очередь", "чёрную очередь", "белый ящик"
      Ищем все матовые позиции
      Добавляем их в "чёрную очередь"

      Повторять
      {
          Пока "чёрная очередь" не пуста
              Берём позицию из "чёрной очереди"
              Перебираем для неё все обратные ходы белых
                  Если нет шаха чёрному королю
                      Если такой позиции нет в "белом ящике"
                          Добавляем позицию в "белый ящик"
                          Добавляем позицию в "белую очередь"

          Пока "белая очередь" не пуста
              Берём позицию из "белой очереди"
              Перебираем для неё все возможные обратные ходы чёрного короля
                  Если из этой позиции любой ход ведёт
                  к известной позиции из "белого ящика"
                      Добавляем позицию в "чёрную очередь"

      } Пока "чёрная очередь" не пустая

      В "белом ящике" находится база решений


Матовые позиции


Создание базы правильных ходов начинается с поиска всех матовых комбинаций. Использование енумераторов позволило достаточно эффектно описать этот процесс.

    foreach (Combo combo in AllCheckmates())
    {
        BlacksMove checkmate = new BlacksMove { combo = combo, moves = 0 };
        blackQueue.Enqueue(checkmate);
    }

Всего найдено 232 матовые позиции. Напомню, что мы ограничились только белопольным слоном.

Некоторые из них достаточно экзотические, не существующие и «кооперативные», это когда чёрный король сам полез под мат.

Мат. Какой был ход белых?

Шахматистам хорошо известно, что мат конём и белопольным слоном нужно ставить в белом углу. В чёрном углу мат возможен только если чёрные будут подыгрывать. Я специально разместил фото с именно таким псевдоматом в начале статьи, чтобы спровоцировать внимание настоящих шахматистов :)

Мат в один ход


Следующий этап — сделать обратный ход белых. То есть, для каждой найденной матовой позиции сделать все возможные обратные ходы белых.

Как сделать обратный ход? Учитывая, что взятия в наших позициях не предусмотрены, алгоритм достаточно простой — сделать любой ход белых, после которого не будет шаха чёрному королю.

Все найденные таким образом позиции можно уже складывать в «белый ящик», указывая, что до мата один ход, и какой именно ход для этого нужно сделать. Попутно помещаем найденные комбинации в «чёрную очередь».

Вот как выглядит эта часть алгоритма:

    // Пока "чёрная очередь" не пуста
    while (blackQueue.Count > 0)
    {
        // Берём позицию из "чёрной очереди"
        BlacksMove black = blackQueue.Dequeue();
        // Перебираем для неё все обратные ходы белых
        foreach (WhitesMove white in AllWhiteBackMoves(black))
            // Если нет шаха чёрному королю
            if (!isCheck(white.combo))
                // Если такой позиции нет в "белом ящике"
                if (!whiteBox.Exists(white.combo))
                {
                    // Добавляем позицию в "белый ящик"
                    whiteBox.Put (white);
                    // Добавляем позицию в "белую очередь"
                    whiteQueue.Enqueue(white);
                }
    }

Кстати, про yield
Использование енумераторов с yield-механизмом позволяет очень красиво реализовать различные переборы, например, так выглядит функция перебора всех возможных ходов белыми фигурами:

        IEnumerable<WhitesMove> AllWhiteBackMoves(BlacksMove black)
        {
            foreach (WhitesMove white in AllWhiteKingMoves(black))
                yield return white;
            foreach (WhitesMove white in AllWhiteBishopMoves(black))
                yield return white;
            foreach (WhitesMove white in AllWhiteKnightMoves(black))
                yield return white;
        }


Всего было найдено 920 таких позиций, вот самые интересные:

Ход конём:
ход конем 1 ход конем 2 ход конем 3

Ход слоном:
ход слоном 1 ход слоном 2

Ход королём:
ход королем

Мат в полтора хода


Следующий этап — сделать обратный ход чёрных. С этим алгоритмом я провозился дольше всего, было сделано немало ошибок, прежде чем всё заработало верно.

На первый взгляд, всё аналогично предыдущему варианту: для каждой позиции из «белой очереди» необходимо перебрать все возможные ходы чёрного короля. И добавлять все найденные комбинации в «чёрную очередь» — ведь это мат в полтора хода, от которого можно будет потом снова делать обратный ход за белых — будет мат в два хода — и так продолжать, пока не будут пересмотрены все варианты.

В этом и была ошибка. При любом возможном ходе чёрных получается «кооперативный» мат в полтора хода, а на самом деле король не обязательно будет идти под мат. Указал мне на эту ошибку Дмитрий Гринь, который посещал все мои вебинары по созданию этой программы, за что ему отдельное спасибо.

Правильный алгоритм следующий: для каждой позиции N после обратного хода чёрного короля нужно перебрать все возможные его прямые ходы, чтобы убедиться, что все они ведут к знакомым позициям из «белого ящика», то есть ведут к мату. И только после этого позицию N можно добавлять в «чёрную очередь». А если из позиции N чёрный король может «улизнуть», то такой вариант пропускаем. Она встретится на последующих итерациях, когда знакомых позиций будет больше.

Вот как выглядит эта часть алгоритма:

    // Пока "белая очередь" не пуста
    while (whiteQueue.Count > 0)
    {
        // Берём позицию N из "белой очереди"
        WhitesMove white = whiteQueue.Dequeue();
        Combo whiteFigures = white.combo;
        // Перебираем для N все возможные обратные ходы чёрного короля
        foreach (BlacksMove black in AllBlackBackMoves(white))
        {
            bool solved = true;
            // Перебираем все возможные ходы чёрного короля
            foreach (Coord blackKing in AllKingMoves(black.combo.blackKing))
            {
                whiteFigures.blackKing = blackKing; // переставляем чёрного короля
                if (isCheck(whiteFigures)) // под шах не ходим
                    continue;
                if (box.Exists(whiteFigures)) // решённые позиции пропускаем
                    continue;
                solved = false; // чёрный король смог "улизнуть"
                break;
            }
            // Если из этой позиции любой ход ведёт
            // к известной позиции из "белого ящика"
            if (solved)
                // Добавляем позицию в "чёрную очередь"
                blackQueue.Enqueue(black);
        }
    }

Всего было найдено 156 комбинаций «Мат в полтора хода».

Итеративность полуходов


Описанные алгоритмы создания полуходов необходимо зациклить. Из «чёрной очереди» мы формируем «белую очередь», а потом наоборот — из «белой» формируем «чёрную». И так до тех пор, пока не будут исчерпаны все новые позиции. «Белая коробка» заполняется на этапе формирования «белой очереди», так как в неё помещаются позиции, в которых ход белых.

Готовый алгоритм перебора всех вариантов отработал где-то за 12 минут и остановился на 33 ходу. Именно столько максимум ходов нужно, чтобы заматовать чёрного короля конём и слоном из любой позиции.

Кстати, таких «самых сложных» позиций оказалось не так много, всего 156, вот одна из них:

Мат в 33 хода

Мата не будет!


Есть немало позиций, в которых даже после хода белых чёрный король может съесть коня или слона и выйти на ничью. Также есть патовые варианты. Вот несколько самых интересных позиций.

Мата нет Мата нет

Мата нет Мата нет

Как хранить базу решений


Каким способом хранить найденную базу решений?
Самый простой и неправильный способ — использовать сериализацию. Засериализованный четырёхмерный массив структуры занял 1.7 гигабайта(!) на диске. Процесс сериализации длился минут шесть, на десериализацию потребовалось примерно столько же.

Такой вариант, ясное дело, не подходит. К тому же, на практике нет надобности использовать весь четырёхмерный массив. Для конкретной позиции нужна только одна запись.

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

Было решено хранить всю базу решений в одном файле — как линейную развёртку четырёхмерного массива. Для любой возможной позиции вычисляется адрес, по которому записан правильный ответ.

Как максимально компактно записать нужный нам ответ? Позицию фигур хранить не надо, поэтому остаётся только три числа — сколько ходов до мата, чем ходить и куда ходить. Именно так однозначно определяется правильный ход за белых.

6 бит. Сколько ходов до мата — это целое число от 0 до 33.
2 бита. Какая фигура ходит — три возможных варианта, король, слон или конь.
6 бит. Куда фигура ходит — индекс поля на доске от 0 до 63.

Значит, на каждую запись решения достаточно два байта:
1 байт — сколько ходов до мата, или 0, если позиция незнакомая.
2 байт — FFNNNNNN
FF — номер фигуры, которой нужно ходить (1 — король, 2 — слон, 3 — конь)
NNNNNN — координата клетки — куда ходить (от 0 до 63).

Итак, файл базы решений занимает 64 * 32 * 64 * 64 слов = ровно 16 мегабайт. Размещение фигур задаётся координатами каждого слова, в первом байте — количество ходов до мата (или 0 если решения нет), во втором байте хранится правильный ход.

Можно было бы ещё в два раза уменьшить размер файла, если не хранить количество ходов до мата, но так играть будет не интересно.

Координаты чёрнопольного белого слона


Пришло время платить за оптимизацию. Нужно реализовать алгоритм пересчёта координат для комбинаций с «чёрно-белым» слоном.

Это было сделано следующим образом. Если координата слона попадает на чёрное поле, то необходимо координаты всех фигур на доске «перевернуть». При этом координата Y остаётся неизменной, а X меняется на 7-X. Наглядная демонстрация переворота координат см. на рисунке.

Переворот координат

Если слон стоит на белой клетке, то сначала необходимо «перевернуть» координаты всех фигур. Потом искать позицию в базе решений. И ещё раз «перевернуть» считанную оттуда координату правильного хода.

Визуализация базы решений


Итак, Задача решена!
База решений создана.
Но как её продемонстрировать?

Самый наглядный способ — использовать web-технологии, чтобы можно было просто дать ссылку на работающий пример. На моей «формуле программиста» уже был создан фотокурс "Нано-шахматы", где с использованием технологий HTML, CSS, JavaScript и PHP была создана интерактивная шахматная доска для игры вдвоём без правил. Именно этот скрипт был взят за основу.

Я оставил только четыре фигуры, убрал возможность взятия, добавил РНР-функции для считывания правильных ходов из базы решений и «вдохнул жизнь» через JavaScript.

На странице www.videosharp.info/chess вы можете поэкспериментировать с базой решений.
Интерактивный мат конём и слоном
Для каждой позиции рассчитываются ходы как за белых, так и за чёрных.
За белых — лучший ход, который ведёт к мату.
За чёрных — сколько ходов до мата на любой возможный ход.

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

Интересно поиграть, выполняя предложенные ходы или передвигая фигуры на своё усмотрение.

Заключение


Была проделана большая, интересная работа по решению шахматной задачи.
Если вы желаете повторить этот путь — можете посмотреть видеозаписи по созданию этой программы с нуля до результата с подробными пояснениями и самостоятельными заданиями.

Желаю удачи!
Поделиться с друзьями
-->

Комментарии (45)


  1. vitekes
    11.08.2016 19:09
    +5

    похоже автор статьи решил сделать ещё один вариант таблицы Налимова.


    1. FFormula
      11.08.2016 19:12

      Совершенно верно, изначально желание было именно таким. Но хорошенько взвесив все за и против — решил просто поставить мат конём и слоном — это и практика, и много времени тратить не нужно! Видеоуроки по созданию этой программы вышли на 12 часов…


  1. apple01
    11.08.2016 19:57
    +2

    На фото в заголовке статьи нереалистическая ситуация.


    1. FFormula
      11.08.2016 20:56

      Ситация вполне возможная, если чёрный король сам будет лезть под мат.
      Я об этом написал в последнем абзаце, перед разделом «Мат в 1 ход».


      1. web2033
        11.08.2016 21:16
        -1

        И на второй тоже! Каким ходом белые матовали? Очевидно слоном, но тогда король был бы под шахом. Что невозможно.
        На первой невозможная, потому что нет предыдущего возможного хода черных.


        1. Voenniy
          11.08.2016 21:49

          На первой черный король уходит с b1 на a1 из под шаха белым слоном и след ход белых конем — мат. Ситуация возможна, но черные играли в поддавки


        1. FFormula
          11.08.2016 21:50
          +1

          Уважаемый, вы тексты читаете или только картинки смотрите? :)
          Я привёл пример невозможного мата, и написал об этом.


          1. web2033
            11.08.2016 22:33
            -4

            по первой согласен, 2-я не получится, даже с поддавками


            1. FFormula
              11.08.2016 22:43
              +6

              Да, это невозможный мат, который нашёл алгоритм поиска всех матовых комбинаций.
              Такая позиция может появится только если последний ход был превращением пешки в слона :)


        1. geher
          11.08.2016 21:54
          +1

          Вторая невозможная.
          А первая — очень даже.
          Если вывести фигуры в начальную позицию
          Черный король — b1
          Белый — a3
          Конь — a5
          Слон — d1
          Пусть ход белых.
          d1-c2 — шах
          Вместо того, чтобы тихо слопать слона, черные уходят в угол
          b1-a1
          Ну и дальше закономерный мат конем
          a5-b3


          1. FFormula
            11.08.2016 22:09

            Сделал ссылку для вашей комбинации, но переставил коня на поле d4, чтобы слона нельзя было есть:
            http://videosharp.info/chess/?fen=8/8/8/8/3N4/K7/2B5/1k6


      1. apple01
        11.08.2016 21:44

        возможная но нереалистическая, ктож под мат будет лезть намеренно :)


      1. supersonic_snail
        12.08.2016 11:33

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


        1. FFormula
          12.08.2016 11:33

          мат двумя конями невозможен при правильной игре.


          1. supersonic_snail
            12.08.2016 11:36

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


            1. FFormula
              12.08.2016 13:11

              Специально для таких увлечённых я записал процесс создания программы в виде уроков, где подробно объясняю создание всей программы. В конце курса на вип-уроке мы переделываем эту программу для мата другими фигурами. Рекомендую пройти этот курс, пока доступ открыт.


  1. vanxant
    11.08.2016 20:22
    +1

    (для хранения чисел от 0 до 33 нужно таки 6 бит, а не 5)


    1. FFormula
      11.08.2016 20:55

      Точно :) Просчитался, сейчас исправлю.


    1. sanyacomua
      11.08.2016 21:51
      +3

      Зато фигуру и ход можно закодировать 5-ю битами. У коня и короля только 8 вариантов хода — это 3 бита, а у слона не более 13 вариантов. Для слона надо 4 бита, но т.к. фигур всего 3 — то один бит для слона можно взять из фигуры.
      Как-то так:
      0 0 NNN — король
      0 1 NNN — конь
      1 NNNN — слон


      1. FFormula
        11.08.2016 21:51
        +1

        Гениально. Я тоже об этом много думал. Но это неоправданно усложнит алгоритм, а целого байта выиграть всё равно не выйдет.


      1. lgorSL
        15.08.2016 01:15

        Можно уложиться в 3 бита!

        Объяснение
        «перевернуть» задачу и хранить ходы для чёрных.


        1. lgorSL
          15.08.2016 01:38

          Значит, на каждую запись решения достаточно два байта:

          Получается, можно и в 1 байт.
          После моего предыдущего комментария должно быть очевидно
          при сохранении для каждой позиции 5 бит на ход белых и ещё 3 на ход чёрных (из неё же).
          В таком случае счётчик ходов вообще не нужен. В случае чего, его можно будет восстановить, переходя туда-сюда по предлагаемым ходам, пока не будет мат.
          Для описания позиций, из которых результат недостижим, можно в описание хода слона добавить 14ый вариант, который будет это отмечать.


          1. AndrewN
            15.08.2016 08:39

            > В случае чего, его можно будет восстановить, переходя туда-сюда по предлагаемым ходам, пока не будет мат.
            ага, в дереве из ~6-7 млн. узлов, с глубиной до 65 (полуходов), это почти тот же самый алгоритм, что и тот который нам эту базу рассчитывает, можно тогда уж не хранить ее вообще, а на каждом ходе рассчитывать просто лучший ход =)


            1. lgorSL
              15.08.2016 13:34

              После того, как найдены все оптимальные ходы, для любой позиции за можно быстро (за 65 переходов в худшем случае) найти количество ходов до конца игры.
              Непосредственно во время игры рассчитывать 6-7 млн узлов нет смысла, а вот вопрос типа «за сколько ходов выиграют белые» вполне может возникнуть.


              1. AndrewN
                15.08.2016 15:07

                Пусть вы играете за белых и у вас есть один лучший правильный ход, но затем вам надо рассмотреть все ходы за черных, а они могут сыграть уже как угодно (до 8 ходов)


                1. lgorSL
                  15.08.2016 15:16

                  Я же предложил для каждой позиции записывать ещё и оптимальный ход чёрных (это всего лишь 3 бита). Если чёрный будет ходить неоптимально — его проблемы, это только ускорит выигрыш белых.


  1. zuborg
    11.08.2016 21:51
    +2

    Оптимизация размера с одноцветным слоном не самая оптимальная, имхо )
    Можно сократить размер базы в четыре раза, если рассматривать только позиции, в которых черный король находится в верхней половине доски, а белый — в левой (а слон и конь могут занимать любое поле). Ну или выбрать другую пару фигур. Все остальные позиции можно свести к этим одним или двумя отражениями (по вертикали и горизонтали)


    1. FFormula
      11.08.2016 22:05

      У меня была мысль использовать только 16 позиций белого короля (левый нижний угол 4х4), а все остальные комбинации получать отражением.
      Но переделывать уже не стал.


      1. janatem
        12.08.2016 00:26
        +2

        Симметрий больше чем две, так что достаточно рассмотреть всего 10 позиций короля. Кроме того, использовать симметрию можно не только в начальной позиции, но и во всем графе.


        1. AndrewN
          12.08.2016 15:49
          +1

          совершенно верно, это позволит сократить файл до 2,5 МиБ, но значительно усложнит алгоритм расчета графа
          Так же и при чтении этой БД потом придется либо сразу распаковывать ее на «полный граф», либо при каждом ходе делать пересчет координат, читать запись и пересчитывать обратно
          Если уж нужна экономия места — проще использовать сжатие, этот файл достаточно хорошо сжимается (обычным zip-ом до 6 МБ запросто)
          в общем все зависит еще от того, нужна ли скорость или экономия десятка мегабайт (что не так уж и много даже для мобильного приложения)


          1. FFormula
            12.08.2016 17:27
            +1

            Вы как в воду глядите! База решений в 16 мб запокавались зипом в 5.99 мегобайт.


          1. janatem
            12.08.2016 19:36

            Я точно не знаю, как устроены настоящие таблицы Налимова, но и наивный подход к использованию симметрии даст очевидную экономию. В качестве вершин графа нужно брать только «каноничные» позиции (например, где белый король находится на одном из 10 полей треугольника a1-d1-d4). На ребрах графа помимо ходов нужно добавить преобразование симметрии (элемент группы D4), такое что при применении к каноничной позиции получается требуемая. Этот граф и строить быстрее, и хранить проще, и использовать. В нем вершин примерно в 6 раз меньше, чем в исходном. Усложнение алгоритма незначительно: нужно лишь при прохождении графа перемножать преобразования (элементы группы), стоящие на ребрах, по которым проходим.


  1. mpetrunin
    12.08.2016 09:08

    > Количество возможных комбинаций — 64 * 64 * 64 * 64 = 16,777,216.

    У вас проблема с подсчётом комбинаций. Правильная цифра 64*63*62*61. Т.к., если король стоит на клетке, то там никак не может стоять конь.


    1. FFormula
      12.08.2016 11:35

      Речь идёт о размере массива для хранения позиций.

      Далее идёт пояснение, цитирую:

      На самом деле комбинаций ещё меньше: на одной клетке не может стоять две фигуры, короли не могут стоять на соседних клетках, чёрный король не может быть под шахом и так далее. Забегая вперёд скажу, что в базе решений оказалось 5,609,790 комбинаций, массив будет заполнен на 67%.


    1. AndrewN
      12.08.2016 15:39
      +2

      Здесь фишка еще в том, что сама позиция записи в файле является важной информацией — это координаты фигур, если хранить только возможные позиции, тр придется хранить еще и координаты всех фигур, в итоге выйдет очень затратно и займет такой файл еще больше чем описанный


      1. FFormula
        12.08.2016 17:28
        +1

        Андрей, приятно читать ваши комментарии.
        Полное понимание контекста задачи, спасибо!


    1. lgorSL
      15.08.2016 00:55

      У вас проблема с подсчётом комбинаций. Правильная цифра 64*63*62*61. Т.к., если король стоит на клетке, то там никак не может стоять конь.

      По-хорошему, количество комбинаций больше в два раза — важно, какой игрок собирается ходить. Но автор сделал иначе и сохранял только те варианты, в которых должны ходить белые.


      1. FFormula
        15.08.2016 01:00

        Очень весомое замечание.
        Именно поэтому при создании визуализации для выбора хода чёрных пришлось перебирать все возможные ходы.
        Спасибо.


  1. Stormbringer-s
    12.08.2016 11:34
    +1

    возможно я где то ошибаюсь но картинка к посту у вас подозрительная т.к. мат слоном и конем ставиться в углу цвета слона пруфлинк.


    1. FFormula
      12.08.2016 11:34
      +1

      Да, совершенно верно. Я специально такую позицию выбрал, фотографию делал сам специально для статьи.
      Об этом в статье написано в последнем абзаце перед разделом «Мат в 1 ход».


  1. LoadRunner
    12.08.2016 11:55
    +1

    Будучи школьниками, с одноклассником шутили на тему одной интересной позиции.
    Белые: Слон на а1, конь на f6, король на f7 (или g6 — не имеет значения);
    Чёрные: король на h8.
    Ход белых. Мат в один ход.
    Решение простое: конь подпрыгивает и зависает в воздухе. Назвали этот мат, как мат Рица.
    Потом пришёл отец одноклассника и сказал, что мы ничего не понимаем в шахматах и сделал за чёрных простой ход — король подпрыгнул и завис в воздухе.

    P. S. А почему статья здесь, а не на Хабре?


    1. FFormula
      12.08.2016 13:12
      +1

      Спасибо, интересная позиция :)
      Я долго думал, где опубликовать эту статью.
      Почему-то решил это сделать здесь. Видимо зря :)


    1. janatem
      12.08.2016 19:41

      Только задание было «мат в полхода». С той мотивацией, что конь начинает ход, но не заканчивает.


      1. AndrewN
        12.08.2016 21:46

        в четверть хода даже)


        1. LoadRunner
          13.08.2016 00:13

          И не мат вовсе, как оказалось.