GNU Prolog, 493 byte
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),[_]).
Un predicato aggiuntivo che può essere utile per i test (non parte dell'invio):
d([]).
d([H|T]):-format("~s~n",[H]),d(T).
Prolog è sicuramente la lingua giusta per risolvere questo compito dal punto di vista pratico. Questo programma praticamente indica solo le regole di Minesweeper e consente al risolutore di vincoli di GNU Prolog di risolvere il problema da lì.
z
e i
sono funzioni di utilità ( z
esegue una sorta di operazione simile a una piega ma su insiemi di tre elementi adiacenti anziché 2; i
traspone 3 elenchi di n elementi in un elenco di n 3 tuple). Memorizziamo internamente una cella come , dove x è 1 per una miniera e 0 per una nonmina, e y è il numero di mine adiacenti; esprime questo vincolo alla lavagna. si applica ad ogni riga del tabellone; e quindi controlla sex/y
c
r
c
z(r,M)
M
è una scheda valida.
Sfortunatamente, il formato di input richiesto per far funzionare direttamente questo lavoro è irragionevole, quindi ho anche dovuto includere un parser (che probabilmente rappresenta più codice rispetto al motore delle regole reale e la maggior parte del tempo impiegato per il debug; il motore delle regole di Minesweeper ha funzionato praticamente prima volta, ma il parser era pieno di thinkos). q
converte una singola cella tra un codice carattere e il nostro formato. converte una linea del tabellone (lasciando una cella nota per non essere una miniera, ma con un numero sconosciuto di mine vicine, su ciascun bordo della linea come bordo);x/y
l
p
converte l'intero tabellone (incluso il bordo inferiore, ma escluso quello in alto). Tutte queste funzioni possono essere eseguite sia in avanti che all'indietro, quindi possono sia analizzare che stampare graziosamente la scheda. (C'è qualche fastidioso sussulto con il terzo argomento ap
, che specifica la larghezza della scheda; questo perché Prolog non ha un tipo di matrice, e se non vincolo la tavola ad essere rettangolare, il programma andrà in un ciclo infinito provando progressivamente bordi più ampi attorno alla tavola.)
m
è la principale funzione di risoluzione dei dragamine. Analizza la stringa di input, generando una scheda con un bordo corretto (tramite l'uso del caso ricorsivo p
per convertire la maggior parte della scheda, quindi chiamando direttamente il caso base per generare il bordo superiore, che ha la stessa struttura del bordo inferiore). Quindi chiamaz(r,[R|M])
per eseguire il motore delle regole di Minesweeper, che (con questo modello di chiamata) diventa un generatore che genera solo schede valide. A questo punto, il consiglio è ancora espresso come un insieme di vincoli, che è potenzialmente imbarazzante per noi; potremmo forse avere un unico insieme di vincoli che potrebbero rappresentare più di una scheda. Inoltre, non abbiamo ancora specificato da nessuna parte che ogni quadrato contiene al massimo una miniera. Come tale, abbiamo bisogno di "collassare esplicitamente la forma d'onda" di ogni quadrato, richiedendo che sia specificamente una (singola) miniera o un nonmine, e il modo più semplice per farlo è far scorrere il parser all'indietro ( var(V)
il case di scorrere all'indietro e quindi il deparing della scheda lo costringe ad essere completamente noto). Infine, restituiamo la scheda analizzata daq(63,V)
la custodia è progettata per impedire il?
m
; m
diventa così un generatore che prende una scheda parzialmente sconosciuta e genera tutte le schede conosciute coerenti con essa.
Questo è davvero abbastanza per risolvere Minesweeper, ma la domanda chiede esplicitamente di verificare se esiste esattamente una soluzione, piuttosto che trovare tutte le soluzioni. Come tale, ho scritto un predicato extra s
che converte semplicemente il generatore m
in un set, e quindi afferma che il set ha esattamente un elemento. Ciò significa che s
restituirà verità ( yes
) se esiste davvero esattamente una soluzione, o falso ( no
) se c'è più di una o meno di una.
d
non fa parte della soluzione e non è incluso nel bytecount; è una funzione per stampare un elenco di stringhe come se fosse una matrice, il che rende possibile ispezionare le schede generate da m
(per impostazione predefinita, GNU Prolog stampa le stringhe come un elenco di codici ASCII, poiché tratta i due in modo sinonimo; questo formato è abbastanza difficile da leggere). È utile durante i test o se si desidera utilizzare m
come pratico risolutore di dragamine (poiché utilizza un risolutore di vincoli, è altamente efficiente).
2?
non ha soluzioni, il che significa che non può provenire da un vero gioco di Minesweeper. Quindi non è considerato una "scheda Minesweeper" ... sì?)