GNU Prolog, 493 байт
z(_,[_,_]).
z(F,[A,B,C|T]):-call(F,A,B,C),z(F,[B,C|T]).
i([],[],[],[]).
i([H|A],[I|B],[J|C],[H-I-J|T]):-i(A,B,C,T).
c(A/_-B/_-C/_,D/_-_/T-E/_,F/_-G/_-H/_):-T#=A+B+C+D+E+F+G+H.
r(A,B,C):-i(A,B,C,L),z(c,L).
q(63,V):-var(V).
q(42,1/_).
q(X,0/Y):-Y#=X-48.
l([],[0/_]).
l([H|T],[E|U]):-q(H,E),l(T,U).
p([],[[0/_,0/_]],0).
p([],[[0/_|T]],N):-M#=N-1,p([],[T],M).
p([H|T],[[0/_|E]|U],N):-p(T,U,N),l(H,E).
m([H|A],B):-length(H,N),p([],[R],N),p([H|A],M,N),z(r,[R|M]),p(B,M,N).
s(A):-setof(B,m(A,B),[_]).
Додатковий предикат, який може бути корисним для тестування (не є частиною подання):
d([]).
d([H|T]):-format("~s~n",[H]),d(T).
Пролог, безумовно, є правильною мовою для вирішення цього завдання з практичної точки зору. Ця програма в основному просто визначає правила тральщика і дозволяє вирішити проблему обмеження GNU Prolog звідти.
z
і i
є корисними функціями ( z
виконує щось на зразок складної операції, але на наборах з трьох сусідніх елементів, а не 2; i
переносить 3 списки з n елементів у список n 3-кортежів). Ми внутрішньо зберігаємо осередок як , де x дорівнює 1 для шахти і 0 для немінного, а y - кількість сусідніх мін; висловлює це обмеження на дошці. стосується кожного ряду дошки; і тому перевіряє, чи є дійсною дошкою.x/y
c
r
c
z(r,M)
M
На жаль, формат введення, необхідний для прямого виконання цієї роботи, є нерозумним, тому мені також довелося включити аналізатор (який, ймовірно, приносить більше коду, ніж фактичний механізм правил, і більшу частину часу, витраченого на налагодження; двигун правил тральщика значно працював перший раз, але парсер був повний тонких). q
перетворює одну клітинку між символьним кодом і нашим форматом. перетворює один рядок дошки (залишаючи одну клітинку, яка, як відомо, не шахта, а з невідомою кількістю сусідніх мін, на кожному краю лінії як кордон);x/y
l
p
перетворює всю плату (включаючи нижню межу, але виключаючи верхню). Усі ці функції можна виконувати або вперед, або назад, таким чином можна як розібрати, так і сильно роздрукувати дошку. (Існує деякий роздратований хитання навколо третього аргументу до p
, який визначає ширину плати; це тому, що Prolog не має матричного типу, і якщо я не обмежую плату бути прямокутною, програма перейде в нескінченна петля, що намагається прогресивно розширювати межі навколо дошки.)
m
є основною функцією вирішення тральщиків. Він аналізує рядок введення, генеруючи дошку з правильною рамкою (за допомогою рекурсивного випадку p
конвертувати більшу частину дошки, а потім викликає базовий випадок безпосередньо для створення верхньої межі, яка має таку саму структуру, як нижня межа). Потім дзвонитьz(r,[R|M])
запустити двигун правил Minesweeper, який (з такою схемою виклику) стає генератором, що генерує лише дійсні дошки. На даний момент рада все ще виражається як набір обмежень, що потенційно незручно для нас; можливо, ми можемо мати єдиний набір обмежень, який міг би представляти більше однієї дошки. Крім того, ми ще ніде не вказали, що кожен квадрат містить максимум одну шахту. Таким чином, нам потрібно явно "згортати форму хвилі" кожного квадрата, вимагаючи, щоб він був конкретно (шахта) або міну, і найпростіший спосіб зробити це - запустити її через аналізатор назад (the var(V)
on the q(63,V)
корпус призначений для запобігання ?
запуску корпусу назад, і, таким чином, відведення дошки змушує його бути повністю відомим). Нарешті, ми повертаємо розібрану дошку зm
; m
таким чином стає генератором, який займає частково невідому плату і генерує всі відомі плати, що відповідають їй.
Цього насправді достатньо, щоб вирішити тральщик, але питання прямо вимагає перевірити, чи існує саме одне рішення, а не знайти всі рішення. Як такий, я написав додатковий предикат, s
який просто перетворює генератор m
в набір, а потім стверджує, що в наборі є рівно один елемент. Це означає, що s
поверне truthy ( yes
), якщо дійсно рівно одне рішення, або falsey ( no
), якщо їх більше, ніж одне чи менше.
d
не є частиною рішення та не включається до рахунку; це функція для друку списку рядків як би матрицею, що дає змогу оглянути дошки, згенеровані m
(за замовчуванням GNU Prolog друкує рядки як список ASCII-кодів, оскільки він обробляє обидва синоніми; цей формат досить важко читати). Це корисно під час тестування, або якщо ви хочете використовувати m
як практичний вирішувач міночистки (оскільки він використовує вирішувач обмежень, це дуже ефективно).
2?
не має рішень, а це означає, що він не може виходити з фактичної гри тральщика. Отже, це не вважається "дошкою тральщика" ... так?)