Существует вариант хорошо известной проблемы N-ферзей, которая включает в себя королев и рыцарей и, как говорят, «значительно сложнее» 1 . Постановка проблемы заключается в следующем:
Вы должны разместить на шахматной доске равное количество рыцарей que и королев board, чтобы ни одна фигура не атаковала любую другую фигуру. Какое максимальное количество фигур вы можете разместить на доске, и сколько разных способов вы можете сделать это?
В этом код-гольф вызов, вам будет предоставлен входной п от 3 до 32 (в пути , который является наиболее подходящим для вашего языка). Для данного n может быть ноль или более решений вышеуказанной проблемы. Если решения не существует, вы должны ничего не выводить / не возвращать ( ноль , пустая строка , ложь , ...). В противном случае вы должны дать два результата:
- Доска решений (см. Ниже) для размера n, где невозможно добавить шахматную фигуру ферзя или рыцаря, не подвергая атаке какую-либо фигуру. Там должно быть равное количество королев и рыцарей .
- Источник запускаемой программы, который не принимает входные данные и дает (i) другое решение (или ничего ) для того же размера n в том же формате, а также (ii) другую программу для следующего решения (и т. Д. ...).
Обратите внимание, что:
- Последовательность программ никогда не должна возвращать одну и ту же плату дважды, она должна охватывать все возможные решения проблемы размера n и, в конечном итоге, должна завершаться (без вывода).
- Вы можете либо вернуть два значения, вернуть одно и напечатать другое, либо распечатать два возвращаемых значения.
- Однако , если вы печатаете и доску, и следующую программу, доску не следует рассматривать как часть следующей программы (я рекомендую печатать доску в комментарии или использовать как стандартный вывод, так и потоки ошибок).
- Возвращаемое значение должно быть строкой, а не замыканием.
Формат платы
- Доска - это квадрат размера n .
- Ячейка доски может быть пустой, королева или рыцарь.
- Вы должны выбрать различные значения для каждого типа ячеек (т.е. вы можете использовать другие символы, кроме Q, N при печати доски).
- Если вы возвращаете нестроковую доску, это должна быть упорядоченная коллекция из n 2 значений платы (например, матрица, вектор или список в мажорном порядке строки / столбца, ...).
Если вы печатаете доску, вы можете распечатать ее в квадрате или в виде линии. Например, доска решений размером 4 может быть напечатана следующим образом (пробелы не требуются; символы на ваше усмотрение):
Q - - - - - - - - - - - - - N -
Если вы чувствуете это, вы также можете вывести:
♛ · · · · · · · · · · · · · ♞ ·
... но этого достаточно
Q-------------N-
Не имеет значения, выполняете ли вы итерацию по ячейкам в мажорном порядке строк или столбцов, потому что существуют симметричные решения. Например, решения для n = 4:
Q------N-------- Q----------N---- Q------------N-- Q-------------N- -Q----------N--- -Q------------N- -Q-------------N --Q---------N--- --Q----------N-- --Q------------N ---QN----------- ---Q----N------- ---Q---------N-- ---Q----------N- ---NQ----------- ----Q------N---- ----Q----------N N------Q-------- -------QN------- -------Q----N--- ---N----Q------- -------NQ------- --------Q------N N----------Q---- ----N------Q---- -----------QN--- -N----------Q--- --N---------Q--- -------N----Q--- -----------NQ--- N------------Q-- --N----------Q-- ---N---------Q-- N-------------Q- -N------------Q- ---N----------Q- -N-------------Q --N------------Q ----N----------Q --------N------Q
Вы также можете посмотреть на решения для n = 5 как матрицы ; доски содержит #
, q
и n
символы, которые пустые клетки разных видов (см мой ответ ниже). Я считаю 2836 досок для n = 6 , как и в ответе Sleafar (я внес ошибку при уменьшении количества байтов, но теперь это исправлено).
Большое спасибо Sleafar за то, что он нашел не один, а две ошибки в моем коде.
Гол
Самый короткий код в байтах побеждает.
Мы измеряем размер первой программы, которая принимает n .
1 . Королевы и рыцари , Роджер К. Уи (будьте осторожны! Содержит решение)
-------------------------N--------Q-
, недопустимо, потому что можно добавить больше частей :)Q--------N---------------N--------Q-
.Ответы:
Groovy, 515 байтов
тестирование
Введите n в качестве аргумента командной строки:
Первая строка вывода всегда является решением в виде комментария (0 = пусто, 1 = королева, 2 = рыцарь), за которым следует код во второй строке:
Следующий скрипт может быть использован для автоматического тестирования ( снова введите n в качестве аргумента):
Поскольку я пытался сделать решение как можно меньшим, оно очень медленное (подробности см. Ниже). Я протестировал только n = 4 с этой версией, чтобы увидеть, работает ли квинификация.
Полученные результаты
n = 4: 40 решения (в преобразованном формате )
n = 5: 172 решения (в преобразованном формате )
n = 6: 2836 решений (в преобразованном формате) )
Алгоритм
Это немного неутешительный вариант решения, не относящийся к квине:
Quineification
Я использовал очень простой подход, чтобы сохранить небольшой размер кода.
Переменная X содержит индекс решения для печати далее. Y содержит измененную копию алгоритма, описанного выше, который используется для вычисления всех решений, а затем выбирает только одно из них, что является причиной его медлительности. Преимущество этого решения в том, что оно не требует большого количества дополнительного кода. Код, хранящийся в Y , выполняется с помощью Eval класса (истинный квин не требуется).
Модифицированный код печатает решение, на которое указывает X , увеличивает X и добавляет копию самого себя:
Я также попытался вывести все решения в виде кода для второго шага, но для n = 6 он выдавал слишком много кода, чтобы Groovy мог его обработать.
источник
Common Lisp, 737
самостоятельно ответ
пример
Вставьте вышеупомянутое в REPL, который возвращает объект функции:
Назовите его (звезда привязана к последнему возвращенному значению):
Это выводит следующее на стандартный вывод:
Кроме того, значение, возвращаемое этой функцией:
... который является литералом массива. Число 5 представляет королев, 6 - рыцарей, а все остальное обозначает пустую ячейку, за исключением того, что внутри хранится больше информации. Если мы скопируем и вставим возвращенную функцию в repl, мы получим новую функцию.
И мы можем назвать это без аргументов:
Этот вызов возвращает новое решение
#(5 0 0 0 0 0 0 2 0 0 0 6 0 0 2 0)
и источник другой функции (здесь не показано). Если исходная функция или последняя сгенерированная не находит решения, ничего не печатается и ничего не возвращается.Внутренние ценности
Раньше я генерировал слишком мало решений. Теперь я рассказываю, какая клетка безопасна для королевы и рыцаря, независимо. Например, вот вывод для n = 5 с pretty-printing:
Когда мы поместили королеву
Q
, позиции, которые находятся в шаге от рыцаря от этой королевы, все еще безопасны для королев и обозначеныq
. Аналогично, рыцари, которых достигают только королевы, безопасны для других рыцарей. Значения являются побитовыми и -ed для представления возможных ходов, а некоторые ячейки достижимы ни одним видом.Точнее, вот последовательность плат, приводящая к следующему решению (слева направо), где свободные ячейки постепенно ограничиваются различными значениями:
Нехвайнский подход
Ungolfed, прокомментированная версия
Дубликаты и ошибки
Мое самое первое решение дало дублирующие решения. Чтобы решить эту проблему, я ввел два счетчика для королев и рыцарей. Счетчик для ферзей (соответственно, рыцарей) отслеживает первую позицию на доске, где существует ферзь (соответственно, рыцарь): я добавляю ферзь (соответственно, рыцарь) только в положениях, которые следуют за этой минимальной позицией.
Этот метод не позволяет мне пересматривать решения, которые уже были найдены в предыдущих итерациях, потому что я выполняю итерацию с возрастающей позицией ферзя (или рыцаря).
Однако Слеафар заметил, что существуют решения, для которых могут быть места для королев и рыцарей, что противоречит правилам. Некоторое время мне приходилось возвращаться к обычному поиску и хранить все известные решения для предотвращения дубликатов, которые были слишком дорогостоящими (как с точки зрения байтов, так и использования памяти).
Вместо этого вот что я делаю сейчас: когда потенциальная доска решений найдена, я пытаюсь добавить ровно одну ферзь и одну рыцаря без учета счетчиков (то есть для всех ячеек на доске). Если это возможно, то текущая доска является дубликатом предыдущей, и я отвергаю решение.
тесты
Куайн-кация
У меня были разные идеи, чтобы делать последовательные работы. Самый простой из них, вероятно, - сначала сгенерировать все решения в виде списка строк и написать последовательные кавычки, которые появляются из этого списка при каждом поколении. Однако это не казалось короче, чем нынешний подход. В качестве альтернативы я попытался переписать рекурсивный код с помощью собственного стека и сбросить все переменные состояния каждый раз, когда нахожу решение; цель состоит в том, чтобы следующий шаг мог быть обработан как продолжение текущего шага. Может быть, это было бы лучше подходит для стекового языка. Текущая довольно проста и основана на переменных читателя Common Lisp, которые всегда интересно использовать.
источник