Ваша задача - написать программу (или две отдельные программы) на любом языке, который:
- Может взять заполненную доску судоку в качестве входных данных (в любом логическом формате) и сжать ее в строку символов
- Может взять сжатую строку в качестве ввода и распаковать ее, чтобы получить точно такую же заполненную доску судоку (вывод в любом логическом формате из 9 строк)
Примечание: используйте правила судоку в ваших интересах; это идея этого вызова.
Судоку правил в Википедии
правила
- Только сжатые символы ASCII (32 - 126) допускаются в сжатом выводе (например, нет многобайтовых символов ).
- Вы можете предположить, что вход является действительной доской Судоку 3х3 (нормальные правила, без изменений).
- Я не буду устанавливать временные ограничения, но не буду создавать алгоритм перебора. Или, отправители должны иметь возможность проверить свои материалы перед публикацией (Спасибо Ян Дворжак).
Если у вас есть какие-либо вопросы или проблемы, вы можете попросить разъяснения или внести предложения в комментариях.
Условия выигрыша
Оценка = сумма количества символов из всех десяти тестовых случаев
Самый низкий балл побеждает.
Тестовые случаи
Вы можете использовать их, чтобы проверить, насколько хорошо работает ваша программа.
9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1
7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2
1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2
8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5
6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8
1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8
5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4
2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9
8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6
Благодарим http://www.opensky.ca/~jdhildeb/software/sudokugen/ за некоторые из этих
Если вы обнаружите какие-либо проблемы с тестовыми примерами, пожалуйста, сообщите мне.
code-challenge
compression
sudoku
kukac67
источник
источник
fudge
подпрограмму в моем втором ответе, который набирает 12 баллов). Более справедливый тест будет состоять в том, чтобы потребовать (а) работы тестовых решений, (б) набрать 1000 случайно сгенерированных сеток Судоку и поделить ответ на 100. Я считаю, что лучшее, что можно сделать со случайными данными, - около 110 на основе 10 x log-base-95 (6670903752021072936960)Ответы:
Хаскелл, 107 очков
Результаты теста:
Код не очень красивый, но он работает. Основа алгоритма состоит в том, что, хотя перечисление всех решений занимает слишком много времени, перечисление всех решений в одном блоке происходит довольно быстро - на самом деле это быстрее, чем последующее преобразование в base95. Все это работает в течение нескольких секунд в переводчике на моей бюджетной машине. Скомпилированная программа завершится немедленно.
Поднятие тяжестей выполняется
solution2ix
функцией, которая для каждого блока 3x3 генерирует все возможные перестановки с учетом ограничений слева и сверху, пока не найдет одну в закодированном решении, запоминая только индекс упомянутой перестановки. Затем он объединяет индексы, используя некоторые предварительно вычисленные веса и схему Хорнера.В другом направлении
ix2solution
функция сначала разбивает индекс на девять значений. Затем для каждого блока он индексирует список возможных перестановок с соответствующим значением, а затем извлекает ограничения для следующих блоков.assignments
простая, но уродливая развернутая рекурсия с использованием монады списка. Он генерирует список перестановок с учетом набора ограничений.Реальная сила исходит от жестких границ длины списка перестановок:
9!
. Это значение никогда не используется, кроме как для поиска верхней границы для выходной длины.6*5*4*6!
в семь раз хуже, чем фактическое число, найденное при перечислении:12096
Результатом всех этих ограничений является
71025136897117189570560
~ =95^11.5544
, что означает, что ни один код не должен быть длиннее 12 символов, и почти половина из них должна быть 11 символов или меньше. Я решил не делать различий между более короткой строкой и той же строкой, дополненной пробелами. Пространства где-либо еще являются значительными.Теоретическое ограничение эффективности кодирования для кодов без префиксов - логарифм base-95
6670903752021072936960
-11.035
означает, что даже оптимальный алгоритм не может избежать создания выходных данных длины 12, хотя он будет производить их только в 3,5% всех случаев. Разрешение длины быть значительным (или, что то же самое, добавление конечных пробелов) действительно добавляет несколько кодов (1% от общего количества), но этого недостаточно, чтобы устранить необходимость в кодах длины-12.источник
Питон, 130 баллов
Алгоритм работает, кодируя каждую позицию на доске, по одному, в большое целое число. Для каждой позиции рассчитываются возможные значения с учетом всех закодированных назначений. Поэтому, если [1,3,7,9] являются возможными значениями для данной позиции, для кодирования выбора требуется 2 бита.
Приятной особенностью этой схемы является то, что если позиция имеет только один оставшийся выбор, ей не нужно места для кодирования.
Получив большое целое число, мы записываем его в базу 95.
Возможно, порядок кодирования лучше, чем в лексикографическом, но я об этом особо не задумывался.
Кодер:
декодер:
Запустите это так:
источник
Perl - оценка
115113103113Выход:
Выход:Ни одна из этих строк не имеет завершающего пробела. Обратите внимание, что первая строка пуста.
Этот алгоритм работает следующим образом. Сжать:
Начните с пустой текущей строки, представляющей сетку судоку
Попробуйте добавить по очереди каждую цифру 1 ... 9 к этой строке и определить, какая из них является жизнеспособной.
Получить следующую цифру из сетки ответов (и добавить ее к текущей)
Если только один является жизнеспособным, нет ничего, чтобы закодировать
Если существует более одного жизнеспособного, подсчитайте количество жизнеспособных опций, отсортируйте их и закодируйте эту цифру в качестве индекса в отсортированный массив. Запишите в массиве цифру и число в качестве 2-кортежа.
Когда все сделано, закодируйте каждый из 2-х кортежей (в обратном порядке) в число на основе переменной, сохраненное как bigint.
Экспресс бигинт в базе 95.
Расшифровать:
Начните с пустой текущей строки, представляющей сетку судоку
Расшифровать номер base95 в бигинт
Попробуйте добавить по очереди каждую цифру 1 ... 9 к этой строке и определить, какая из них является жизнеспособной.
Если только один является жизнеспособным, нет ничего, чтобы закодировать; добавить этот выбор в сетку
Если существует более одного жизнеспособного, подсчитайте количество жизнеспособных опций, отсортируйте их и закодируйте эту цифру в качестве индекса в отсортированный массив.
Декодируйте переменную base bigint, используя количество жизнеспособных опций в качестве базы и модуль в качестве индекса в массиве, и выводите эту цифру в качестве значения ячейки.
Для определения количества жизнеспособных опций используется Games :: Sudoku :: Solver. Это в основном для ясности, так как на этом сайте есть 3 линейных решателя судоку.
На все 10 ушло 8 секунд на моем ноутбуке.
fudge
Операция сортирует массив по- разному , чтобы достичь минимального значения для тестов. Как задокументировано, это выдумка. Выдумка снижает оценку со 115 до 103. Это сделано вручную, чтобы гарантировать, что код bigint для первого теста равен 0. Наихудший результат для любого судоку - 12, что дает оценку 120. Поэтому я не думаю, что это считается как жесткий код; скорее это оптимизирует для тестовых данных. Чтобы увидеть его работу без этого измененияsort fudge
вsort
обоих местах.Код следует:
источник
CJam, 309 байтов
Это просто быстрое базовое решение. Извините, я сделал это на языке игры в гольф, но на самом деле это был самый простой способ сделать это. Я добавлю объяснение фактического кода завтра, но я обрисовал в общих чертах алгоритм ниже.
кодировщик
дешифратор
Проверьте это здесь.
Вход кодера (на STDIN) и выход декодера (на STDOUT) имеют форму вложенного массива CJam. Например
10 тестовых выходов:
Алгоритм очень прост:
источник
Python 2.7, всего 107 символов
TL; DR перебор всех 3х3 квадратов с ограничениями сверху + слева
контрольные примеры:
вспомогательная функция для печати судоку
генерирует все возможные квадраты с учетом ограничений сверху и слева
см код комментария для более подробной информации
извлекает все квадраты из доски судоку как кортежи
см код комментария для более подробной информации
преобразует квадраты обратно в судоку
в основном обратная функция выше
заданных квадратов осталось, вернуть ограничения
см код комментария для более подробной информации
заданные квадраты выше, возвратные ограничения
см код комментария для более подробной информации
делает строку
это жестко закодированный список зависимостей для каждого квадрата
см код комментария для более подробной информации
это жестко запрограммированный список максимального количества возможных вариантов для каждого квадрата
см код комментария для более подробной информации
они объединяют вышеуказанные функции и преобразуют доску в список целых чисел
и обратно на доску
хорошо, это все функции
для каждой доски сделайте строку и распечатайте ее
Теперь выведите общую длину всех строк.
и unringringify, чтобы доказать, что это не одностороннее сжатие
выход:
источник
Mathematica, оценка:
1309Обновить:
После того, как этот ответ был опубликован, он вдохновил новую лазейку ближе: «Оптимизация для данных тестовых случаев» . Однако я оставлю этот ответ как есть, как пример лазейки. Не стесняйтесь понижать голос. Мне не будет больно.
Это кодирует ячейку за раз в растровом порядке, и для каждой ячейки соответствующим образом исключается ее значение для последующих ячеек с использованием основных правил судоку. Так, например, когда ячейка кодируется и имеет только четыре возможности, к большому целому числу добавляется базовая цифра 4. Он также кодирует тестовые примеры непосредственно в виде небольших целых чисел, по-прежнему правильно сжимая и распаковывая все допустимые платы Судоку со средней сжатой длиной ~ 12,5 символов, что на 1,5 больше, чем оптимальное значение 11,035, с относительно простым кодом и не требующим решателя Судоку.
Закодированные тестовые случаи:
Это не приводит к идеальному кодированию (в среднем ~ 11), так как основные правила не исключают некоторые варианты, для которых фактически нет решения. Производительность может быть улучшена (т. Е. Большое целое число всегда будет меньше, чем число возможных плат Судоку), проверив, не существует ли решения для некоторых из текущих вариантов с использованием решателя Судоку, и исключив их.
источник
J, 254 балла
компрессия декомпрессияСтандартные операции ввода-вывода немного неуклюжи в J, поскольку
jconsole
на самом деле это REPL, поэтому я позволил себе записать сжатый вывод в файл.Находит индекс анаграммы каждой строки, обрабатывает полученные девять чисел как число base (9!), А затем, наконец, преобразует в base-95, добавляет 32 и преобразует в ASCII, как в решении Мартина Бюттнера. Индекс анаграммы перестановки 1..n - это просто индекс перестановки в лексически отсортированном списке всех таких перестановок, например,
5 4 3 2 1
имеет индекс анаграммы 5! - 1 = 119 .Все операции имеют простые инверсии, поэтому декомпрессия проста.
В качестве бонуса примеры представлены в очень дружественном для J формате, поэтому ввод / вывод для распакованного судоку точно такой же, как в примерах (хотя для ввода в кодировщик требуется завершающий перевод строки).
Сжатые строки для тестовых случаев:
источник
Python 3, 120 баллов
Эта программа перечисляет все возможные 3x3-блоки и запоминает, какой из них действительно присутствовал в оригинальном судоку, а затем объединяет все эти числа в представление base-95. Хотя это очень близко к жесткому кодированию, оно сжимает и распаковывает примеры примерно на 5 секунд каждый на моей машине.
Основными функциями являются
compress(sudoku)
иdecompress(text)
.Выходы:
источник
Python 2,5, 116 баллов
Код:
Полученные результаты:
Очень медленно. Потребовалось 517 секунд, чтобы запустить и проверить на моей машине.
encconfig берет доску судоку и цифру от 1 до 9, перечисляет координаты xy, где появляется эта цифра, и выводит число в диапазоне (6 ** 6), которое представляет эти координаты. («цифровая конфигурация»)
decconfig - это обратная функция. Требуется число в диапазоне (6 ** 6), цифра и доска судоку (по умолчанию пусто). Она выводит плату судоку с наложенной на нее цифрой. Если одна из позиций в конфигурации цифр уже занята на введенной доске судоку, цифра в этой позиции заменяется новой цифрой.
Совместимость принимает плату судоку и конфигурацию цифр (определяется с помощью conf и dig), накладывает конфигурацию цифр на плату судоку и проверяет наличие конфликтов. Затем он возвращает True или False в зависимости от результата.
закодировать это функция сжатия. Он берет доску судоку и выводит число, представляющее ее. Он делает это, сначала копируя позиции единиц на пустую доску и составляя список всех конфигураций числа 2, которые совместимы с конфигурацией 1 (которые не занимают места, уже занятые 1 - х). Затем он находит порядок фактической 2-конфигурации платы в списке и сохраняет ее, затем копирует эту конфигурацию на новую плату, которая теперь содержит только 1 и 2. Затем он перечисляет все конфигурации числа 3, которые совместимы с позициями 1 и 2, и так далее.
декодирование - обратная функция.
Python 2.5.
источник
C #, 150 байт
Сжатый выход:
Как это работает:
Он генерирует все возможные перестановки 123456789 и запоминает их. Затем он сравнивает перестановки со строками в судоку. Когда совпадающая перестановка для заданной строки найдена, она запоминает индекс этой перестановки. После каждой строки будут удалены все перестановки, где есть хотя бы один символ в той же позиции, что и текущая строка. Это гарантирует, что каждое число уникально в своем столбце. Затем он удаляет все перестановки, которые больше не работают по критериям коробки. Поскольку последний ряд тривиален, он генерирует 8 чисел. Я проверил, каково будет максимальное значение каждого из этих чисел, и сгенерировал маску подсчета цифр для каждой их позиции. {6, 5, 3, 5, 3, 1, 2, 1, 1}. Первый, очевидно, самый длинный с 362880 перестановками. Используя цифровую маску, я создаю BigInteger с ведущей 1, чтобы сделать его длиной 28 цифр. В результате получается всего 11 байтов. Затем эти байты преобразуются в base64. Чтобы сохранить один символ, я убираю знак = в конце.
Работы по реконструкции аналогичны.
Он восстанавливает BigInteger из строки base64, а затем снова превращает его в строку и снова разделяет, используя упомянутую маску подсчета цифр. Эти строки анализируются обратно в индексы.
Затем алгоритм делает почти то же самое, вместо поиска строки в перестановках, он просто использует индекс, чтобы получить строку, остальное работает так же.
Возможно, было бы немного лучше по-настоящему использовать 94 возможных символа вместо только 64, но мне не хватает мозгов, чтобы сделать это.
Источник : Скопируйте и вставьте, чтобы он работал с 10 примерами. .dotNet-Fiddle говорит мне, что это превышает ограничение памяти, поэтому вам нужно запустить его на своем компьютере, чтобы текст.
источник
Perl - 290 символов = 290 баллов
Эта программа не использует жесткого кодирования и надежно сжимает сетку ровно в 29 символов (теоретически можно было бы найти несколько меньших).
Вот как это работает:
Сначала преобразуйте массив 9 x 9 в 60 чисел. Это можно сделать, так как последний столбец, последний ряд и последний квадрат каждой ячейки 3 × 3 могут быть отброшены.
Затем преобразуйте с помощью bigint в одно целое число, используя 9 ^ 60 элементов.
Затем конвертируйте бигинт в базу 95.
Компрессор и декомпрессор:
источник
PHP, 214
Это решение сначала очищает правый столбец и нижний ряд, а также нижний правый угол каждого блока 3х3. Затем он пытается очистить ячейку. Если существует простое решение, ячейка остается пустой.
Затем сетка судоку форматируется в строку слева направо и сверху вниз, исключая правый столбец, нижний ряд и нижний правый угол. Ведущие нули подсчитываются (пусть это будет
z
) и удаляются. Замыкающие нули также удаляются.Строка форматируется как целое число 10, 11 или 12 (пусть это будет основание
b
) сA
представлением двух нулей, иB
трех.Это преобразуется в целое число base-95 и добавляется перед цифрой base-95, представляющей
z << 2 | (b - 10)
.Позвоните,
php sudoku-compress.php enc
чтобы закодировать, иphp sudoku-compress.php dec
декодирования. Кодировщик принимает формат, указанный в вопросе, с обязательным завершающим переводом строки.Тестовые выходы:
источник
Java, 330 баллов
Прежде чем меня высмеют за столь высокий балл, позвольте мне уточнить, что я пытался решить эту проблему другим способом, зная, что это, вероятно, будет не столь оптимальным, как некоторые из лучших ответов здесь. Мне было более или менее любопытно, если бы я мог подобраться ближе, что, к моему удивлению, я не осознавал, насколько хуже это окажется. Вот краткое изложение того, что мой подход был здесь:
Разработайте алгоритм решения головоломки Судоку.
Разработайте алгоритм шифрования, который еще можно решить. Он делает это несколько случайным образом, удаляя подсказки, которые можно легко определить заранее. Я мог получить примерно 22 подсказки, прежде чем это заняло слишком много времени.
После скремблирования головоломка может быть представлена триплетом однозначных целых чисел для каждой подсказки, в моем случае 22 тройки из 3. Я подумал, что если бы я мог объединить их в одно 66-значное число, тогда base95 закодировал бы это, тогда у меня есть кое-что, что может быть легко расшифрованным.
Закодированная строка оказалась длиннее, чем я ожидал, обычно около 33 символов. В этот момент я попробовал альтернативный способ, чем использование Java BigInteger, где я создал большое число из 81-битной маски, представляющей 81 ячейку сетки, где 1 означает, что для этой ячейки существует подсказка. Затем я скомбинировал эту битовую маску с 4-битными представлениями каждого значения ячейки в последовательном порядке, округлил до байтов и обнаружил, что я получил примерно одинаковую длину кодированной строки после кодирования base95.
Так что, в основном, я публикую свой код на тот случай, если кто-нибудь заинтересуется другим подходом, который не сработает так хорошо.
Класс Пазз
Мой тестовый кейс
Тестовый вывод
источник
С ++ 241, оценка: 82 * 10 = 820
Добавляет '!' в начало закодированной строки, чтобы определить, какую операцию выполнить.
Игра в гольф 241 символ
Ungolfed 312 символов
источник