GNU Prolog, 493 bytes
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),[_]).
Um predicado extra que pode ser útil para testes (não faz parte do envio):
d([]).
d([H|T]):-format("~s~n",[H]),d(T).
O Prolog é definitivamente o idioma certo para resolver esta tarefa do ponto de vista prático. Este programa praticamente estabelece as regras do Minesweeper e permite que o solucionador de restrições do GNU Prolog resolva o problema a partir daí.
z
e i
são funções utilitárias ( z
realiza uma espécie de operação semelhante a dobra, mas em conjuntos de três elementos adjacentes em vez de 2; i
transpõe 3 listas de n elementos para uma lista de n 3 tuplas). Armazenamos internamente uma célula como , onde x é 1 para uma mina e 0 para uma não mina e y é o número de minas adjacentes; expressa essa restrição no quadro. aplica - se a todas as linhas do tabuleiro; e assim verifica se é um quadro válido.x/y
c
r
c
z(r,M)
M
Infelizmente, o formato de entrada necessário para fazer esse trabalho diretamente não é razoável, então eu também precisei incluir um analisador (que provavelmente é responsável por mais código do que o mecanismo de regras real e a maior parte do tempo gasto na depuração; o mecanismo de regras do Minesweeper praticamente funcionou primeira vez, mas o analisador estava cheio de pensamentos). q
converte uma única célula entre um código de caractere e nosso formato. converte uma linha do tabuleiro (deixando uma célula que se sabe não ser uma mina, mas com um número desconhecido de minas vizinhas, em cada extremidade da linha como uma borda);x/y
l
p
converte o quadro inteiro (incluindo a borda inferior, mas excluindo a borda superior). Todas essas funções podem ser executadas para frente ou para trás, portanto, podem analisar e imprimir o quadro de maneira bonita. (Há algumas oscilações irritantes com o terceiro argumento para p
, que especifica a largura da placa; isso ocorre porque o Prolog não possui um tipo de matriz e, se eu não restringir a placa a ser retangular, o programa entrará em um loop infinito tentando bordas progressivamente mais amplas ao redor do quadro.)
m
é a principal função de resolução do Campo Minado. Ele analisa a sequência de entrada, gerando uma placa com uma borda correta (usando o caso recursivo de p
para converter a maior parte da placa e chamando o caso base diretamente para gerar a borda superior, que tem a mesma estrutura da borda inferior). Então chamaz(r,[R|M])
para executar o mecanismo de regras do Campo Minado, que (com esse padrão de chamada) se torna um gerador que gera apenas placas válidas. Nesse ponto, o conselho ainda é expresso como um conjunto de restrições, o que é potencialmente estranho para nós; talvez pudéssemos ter um único conjunto de restrições que poderiam representar mais de uma diretoria. Além disso, ainda não especificamos em nenhum lugar que cada quadrado contenha no máximo uma mina. Como tal, precisamos explicitamente "recolher a forma de onda" de cada quadrado, exigindo que seja especificamente uma mina (única) ou uma não mina, e a maneira mais fácil de fazer isso é executá-la no analisador de trás para a frente ( var(V)
no q(63,V)
A caixa foi projetada para impedir que a ?
caixa se mova para trás e, portanto, a separação da placa o força a ser totalmente conhecida). Finalmente, retornamos o quadro analisado dem
; m
torna-se assim um gerador que pega uma placa parcialmente desconhecida e gera todas as placas conhecidas consistentes com ela.
Isso é realmente suficiente para resolver o Campo Minado, mas a pergunta pede explicitamente para verificar se existe exatamente uma solução, em vez de encontrar todas as soluções. Como tal, escrevi um predicado extra s
que simplesmente converte o gerador m
em um conjunto e, em seguida, afirma que o conjunto possui exatamente um elemento. Isso significa que s
retornará yes
verdade ( ) se houver de fato exatamente uma solução ou falsey ( no
) se houver mais de uma ou menos de uma.
d
não faz parte da solução e não está incluído no bytecount; é uma função para imprimir uma lista de strings como se fosse uma matriz, o que possibilita inspecionar as placas geradas por m
(por padrão, o GNU Prolog imprime strings como uma lista de códigos ASCII, porque trata os dois como sinônimos; este formato é bastante difícil de ler). É útil durante o teste ou se você deseja usar m
como um solucionador prático do Campo Minado (porque usa um solucionador de restrições, é altamente eficiente).
2?
não tem soluções, o que significa que não pode vir de um jogo real do Campo Minado Por isso, não é considerado um "board Campo Minado" ... sim.?)