Сапер - популярная игра-головоломка, в которой вы должны выяснить, какие плитки являются «минами», не нажимая на эти плитки. Вместо этого вы нажимаете на соседние плитки, чтобы показать количество смежных мин. Недостатком игры является то, что возможно оказаться в сценарии, где есть несколько действительных ответов, и вы можете только догадываться. Например, возьмите следующую доску:
1110
2*31
3*??
2*4?
112?
В этом формате число представляет количество соседних мин, an *
представляет известную шахту, и "?" представляет потенциальную шахту. К сожалению, в этой конкретной загадке есть четыре различных и правильных возможных решения:
1110 1110 1110 1110
2*31 2*31 2*31 2*31
3*4* 3*5* 3**2 3**1
2*42 2*4* 2*4* 2*42
112* 1121 1121 112*
Это означает, что доска неразрешима . Вот пример решаемой платы:
1121
1??*
12?*
0122
Эта доска разрешима, потому что есть только одно возможное правильное решение:
1121
1*4*
12**
0122
Ваша задача - написать программу или функцию, которая использует действующую платформу тральщика и определяет, разрешима она или нет. Под «действительной доской тральщика» я подразумеваю, что входные данные всегда будут прямоугольными, имеют хотя бы одно решение и не будут содержать недопустимых символов.
Ваш ввод может быть массивом символов, массивом строк, строкой, содержащей новые строки и т. Д. Выходные данные должны быть истинным значением, если оно разрешимо, и ложным значением, если это не так. Я не очень беспокоюсь о производительности, но ваше решение теоретически должно работать для любого размера ввода.
Как обычно, применяются стандартные лазейки и выигрывает самое короткое решение в байтах!
Примеры:
Следующие примеры все разрешимы:
1121
1??*
12?*
0122
1110
1???
1110
0000
1110
3???
??20
*310
****
****
****
****
0000
0000
0000
0000
1100
*100
2321
??*2
13*2
1221
1*10
1110
1121
2*??
2*31
2220
1*10
Следующие примеры неразрешимы:
1110
2*31
3*??
2*4?
112?
01??11*211
12??2323*1
1*33*2*210
12?2122321
13?3101**1
1***101221
1***
3*52
2*31
12??
02??
01??
00000111
000012*1
00001*21
22101110
**100111
?31123*1
?311**31
**113*20
источник
2?
не имеет решений, что означает, что он не может быть получен из реальной игры Сапер. Следовательно, он не считается «доской Сапер» ... да?)Ответы:
GNU Prolog, 493 байта
Дополнительный предикат, который может быть полезен для тестирования (не является частью представления):
Пролог, безусловно, является подходящим языком для решения этой задачи с практической точки зрения. Эта программа в значительной степени просто устанавливает правила Minesweeper и позволяет решателю ограничений GNU Prolog решить проблему оттуда.
z
иi
являются служебными функциями (z
выполняет своего рода операцию, подобную складке, но на наборах из трех смежных элементов, а не 2;i
переносит 3 списка из n элементов в список из n 3-х кортежей). Мы внутренне сохраняем ячейку как , где x равно 1 для мин и 0 для немина, а y - количество смежных мин; выражает это ограничение на доске. применяется к каждому ряду доски; и поэтому проверяет, является ли доска действительной.x/y
c
r
c
z(r,M)
M
К сожалению, формат ввода, необходимый для непосредственной работы, нецелесообразен, поэтому мне также пришлось включить синтаксический анализатор (который, вероятно, учитывает больше кода, чем фактический механизм правил, и большую часть времени проводил отладку; механизм правил Minesweeper в значительной степени работал первый раз, но парсер был полон мыслителей).
q
преобразует одну ячейку между кодом символа и нашим форматом. преобразует одну строку доски (оставляя одну ячейку, которая, как известно, не является миной, но с неизвестным количеством соседних мин, на каждом краю линии как граница);x/y
l
p
преобразует всю доску (включая нижнюю границу, но исключая верхнюю). Все эти функции могут быть запущены как вперед, так и назад, что позволяет как анализировать, так и печатать доску. (Есть несколько раздражающих шатаний с третьим аргументомp
, который задает ширину доски; это потому, что у Пролога нет матричного типа, и если я не ограничу доску прямоугольной, программа перейдет в бесконечный цикл, пытающийся постепенно расширить границы вокруг доски.)m
является главной функцией решения Сапер. Он анализирует входную строку, генерируя доску с правильной границей (используя рекурсивный регистрp
для преобразования большей части доски, затем вызывая базовый случай напрямую для генерации верхней границы, которая имеет ту же структуру, что и нижняя граница). Тогда это вызываетz(r,[R|M])
запустить механизм правил Minesweeper, который (с этим шаблоном вызовов) становится генератором, генерирующим только допустимые доски. На этом этапе правление все еще выражается в виде набора ограничений, что потенциально неудобно для нас; возможно, у нас может быть один набор ограничений, который может представлять более одной доски. Кроме того, мы еще нигде не указали, что каждый квадрат содержит не более одной шахты. Таким образом, нам необходимо явно «свернуть форму волны» каждого квадрата, требуя, чтобы он был конкретно либо (одиночным), либо минным, и самый простой способ сделать это - запустить его через анализатор в обратном направлении (var(V)
наq(63,V)
Корпус предназначен для предотвращения?
обратного хода корпуса, и, таким образом, отклонение доски заставляет ее быть полностью известной). Наконец, мы возвращаем разобранную доску изm
;m
таким образом, становится генератором, который принимает частично неизвестную доску и генерирует все известные платы в соответствии с ней.Этого действительно достаточно, чтобы решить Сапер, но вопрос явно просит проверить, есть ли точно одно решение, а не найти все решения. Поэтому я написал дополнительный предикат,
s
который просто преобразует генераторm
в набор, а затем утверждает, что набор содержит ровно один элемент. Это означает, чтоs
вернет truey (yes
), если действительно есть только одно решение, или falsey (no
), если существует более одного или меньше одного.d
не является частью решения и не входит в число байтов; это функция для печати списка строк, как если бы это была матрица, которая позволяет проверять платы, сгенерированныеm
(по умолчанию, GNU Prolog печатает строки в виде списка кодов ASCII, потому что он обрабатывает две эти функции как синонимы; этот формат довольно трудно читать). Это полезно во время тестирования или если вы хотите использоватьm
в качестве практического решателя Minesweeper (потому что он использует решатель ограничений, он очень эффективен).источник
Haskell,
193169168 байтПример использования:
g "1121 1??* 12?* 0122"
->True
.Как это работает: составьте список всех возможных плат с
?
заменой либо на,*
либо!
(!
значит, пропустите позже). Это делается с помощьюmapM c
, но прежде чем мы добавим и добавим несколько пробелов к входной строке, чтобы наша индексация не выходила за пределы диапазона. Для каждой такой проверки платы , если это правильная плата, обернув по всем элементам (индексаj
) , и если это число (d>'/'
) также на своих соседей (индексn
,m
), подсчитать*
и сравнить с числом. Наконец, проверьте длину списка действительных досок.источник
Mathematica,
214192190180176174168165 байтовСодержит U + F4A1 (для частного использования). Эта безымянная функция находит все возможные комбинации для
"?"
(т.е. заменяет все"?"
s на"*"
или0
) и проверяет, существует ли только одно допустимое решение.объяснение
Установите
b
в"*"
.Установите
q
в строку"?"
. Проверьте, есть ли"?"
на входе.Если
True
...Замените первое вхождение
q
(="?"
) наb
(="*"
) или0
(т.е. два выхода) и примените всю функцию снова.Если
False
...Дополните вход одним слоем
0
.Разделите входные данные на матрицы 3 x 3 со смещением 1. Для каждого раздела примените функцию, так что если среднее значение равно
b
(="*"
), выходным значением являетсяb
(="*"
), а если средним значением не являетсяb
(="*"
), output - это числоb
(="*"
) на входе. Этот шаг повторно оценивает все числовые ячейки.Из всех результатов найдите те, которые соответствуют входным
Проверьте, имеет ли вход длину 1.
источник
Perl, 215 байт
213 байтов кода +
-p0
флаги (2 байта).Идея кода состоит в том, чтобы проверить каждую возможность и посмотреть, есть ли одна-единственная, которая приводит к полностью заполненной доске, которая является действительной.
Более читабельный код выглядит так:
О регулярном выражении в середине:
Обратите внимание, что
[^V]
просто означает «любой символ, включая \ n».Идея такова: 3 символа на линии, затем 3 на следующей (с
$i
серединой), затем 3 на следующей. эти 3 группы из 3 чисел выровнены,[^V]{$c}
и интересующий нас номер находится посередине.И затем
"$1$2$3"=~y%*%%
подсчитывает количество*
(бомб) среди этих 9 символов: если оно отличается от$i
, мы добавляем пустую строку для сопоставления (""
=> мгновенное сопоставление, регулярное выражение возвращает истину), в противном случае мы принудительно завершаем неудачу, пытаясь сопоставитьR
( который не может быть в строке).Если регулярное выражение соответствует, то плата не действует, поэтому мы устанавливаем
$r
на0
с$r&=!/.../
.И именно поэтому мы добавляем некоторые
A
повсюду вокруг каждой строки: так что нам не нужно беспокоиться о случаях краев чисел, которые находятся рядом с краями доски: они будут иметь вA
качестве соседей, которые не являются минами (конечно, примерно любой символ может работать, Я выбралA
).Вы можете запустить программу из командной строки следующим образом:
Сложность не может быть худшей: это
O(m*9^n)
гдеn
число?
на доске иm
количество ячеек на доске (без учета сложности регулярного выражения в середине, что, вероятно, довольно плохо). На моей машине это работает довольно быстро до 4?
, и начинает работать медленнее 5, занимает несколько минут для 6, и я не пытался увеличить число.источник
JavaScript (ES6), 221
229Если все входные данные, как ожидается, будет действительно - то есть, по крайней мере , 1 решение - тогда я могу сохранить байт меняетсяs==1
сs<2
Меньше гольфа
Тест
источник
JavaScript (Node.js) , 167 байт
Попробуйте онлайн!
Несмотря на то, что оператор говорит: «вход всегда будет прямоугольным, есть хотя бы одно решение», ложный образец 3 не совпадает, поэтому мне все еще требуется 1 решение, а не <2 решения
источник