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),[_]).
Ein zusätzliches Prädikat, das zum Testen nützlich sein kann (nicht Teil der Einreichung):
d([]).
d([H|T]):-format("~s~n",[H]),d(T).
Prolog ist definitiv die richtige Sprache, um diese Aufgabe aus praktischer Sicht zu lösen. Dieses Programm gibt so ziemlich nur die Regeln von Minesweeper an und lässt GNU Prologs Constraint Solver das Problem von dort aus lösen.
z
und i
sind Utility-Funktionen ( z
führt eine Art Fold-ähnliche Operation aus, jedoch mit Mengen von drei benachbarten Elementen anstelle von 2; i
transponiert 3 Listen von n Elementen in eine Liste von n 3-Tupeln). Wir speichern eine Zelle intern als , wobei x 1 für eine Mine und 0 für eine Nichtmine ist und y die Anzahl benachbarter Minen ist; drückt diese Einschränkung an der Tafel aus. gilt für jede Reihe der Tafel; und prüft so , ob es sich um eine gültige Karte handelt.x/y
c
r
c
z(r,M)
M
Leider ist das Eingabeformat, das erforderlich ist, um diese Funktion direkt auszuführen, nicht zumutbar. Daher musste ich auch einen Parser einbinden (der wahrscheinlich mehr Code als die eigentliche Regelengine enthält und die meiste Zeit mit dem Debuggen verbracht hat). Die Minesweeper-Regelengine hat ziemlich gut funktioniert Das erste Mal, aber der Parser war voll von Thinkos. q
konvertiert eine einzelne Zelle zwischen einem Zeichencode und unserem Format. konvertiert eine Zeile des Spielbretts (wobei eine Zelle, von der bekannt ist, dass sie keine Mine ist, jedoch eine unbekannte Anzahl benachbarter Minen aufweist, an jedem Rand der Zeile als Grenze verbleibt);x/y
l
p
Konvertiert das gesamte Board (einschließlich des unteren Rahmens, jedoch ohne das obere). Alle diese Funktionen können entweder vorwärts oder rückwärts ausgeführt werden, wodurch das Board sowohl analysiert als auch schön gedruckt werden kann. (Es gibt einige nervige Bewegungen mit dem dritten Argument von p
, das die Breite der Karte angibt. Dies liegt daran, dass Prolog keinen Matrixtyp hat. Wenn ich die Karte nicht auf rechteckig einschränke, wird das Programm ausgeführt eine Endlosschleife, in der immer breitere Ränder um das Brett gezogen werden.)
m
ist die Hauptauflösungsfunktion von Minesweeper. Es analysiert die Eingabezeichenfolge und generiert eine Platine mit einem korrekten Rand (indem das p
meiste der Platine in den rekursiven Fall konvertiert wird und dann der Basisfall direkt aufgerufen wird, um die obere Grenze zu generieren, die dieselbe Struktur wie die untere Grenze hat). Dann ruft esz(r,[R|M])
um die Minesweeper Rules Engine auszuführen, die (mit diesem Aufrufmuster) zu einem Generator wird, der nur gültige Boards generiert. Zu diesem Zeitpunkt wird das Board immer noch als eine Reihe von Einschränkungen ausgedrückt, was für uns möglicherweise umständlich ist. wir könnten vielleicht eine einzige Reihe von Einschränkungen haben, die mehr als ein Board repräsentieren könnten. Außerdem haben wir noch nirgendwo angegeben, dass jedes Quadrat höchstens eine Mine enthält. Als solches müssen wir die Wellenform jedes Quadrats explizit "kollabieren", wobei es spezifisch entweder eine (einzelne) Mine oder eine Nichtmine sein muss, und der einfachste Weg, dies zu tun, besteht darin, es rückwärts durch den Parser zu laufen (die var(V)
auf der q(63,V)
case soll verhindern, dass das ?
Gehäuse nach hinten läuft, und dass das Board durch das Deparsing vollständig erkannt wird). Zum Schluss geben wir das geparste Board abm
; m
Somit wird ein Generator, der eine teilweise unbekannte Karte nimmt und alle bekannten Karten in Übereinstimmung mit ihr erzeugt.
Das ist wirklich genug, um Minesweeper zu lösen, aber die Frage lautet ausdrücklich, ob es genau eine Lösung gibt, anstatt alle Lösungen zu finden. Als solches habe ich ein zusätzliches Prädikat geschrieben s
, das den Generator einfach m
in eine Menge umwandelt und dann behauptet, dass die Menge genau ein Element enthält. Dies bedeutet, dass s
truthy ( yes
) zurückgegeben wird, wenn es tatsächlich genau eine Lösung gibt, oder falsey ( no
), wenn es mehr als eine oder weniger als eine gibt.
d
ist nicht Teil der Lösung und nicht im bytecount enthalten; Es ist eine Funktion zum Drucken einer Liste von Zeichenfolgen, als wäre es eine Matrix, die es ermöglicht, die von m
(standardmäßig druckt GNU Prolog Zeichenfolgen als Liste von ASCII-Codes, da beide synonym behandelt werden; dieses Format) generierten Karten zu überprüfen ist ziemlich schwer zu lesen). Dies ist nützlich beim Testen oder wenn Sie m
einen praktischen Minesweeper-Solver verwenden möchten (da ein Constraint-Solver verwendet wird, ist dieser sehr effizient).
2?
keine Lösungen, was bedeutet, dass es nicht aus einem tatsächlichen Spiel von Minesweeper stammen kann. Daher wird es nicht als "Minesweeper-Brett" angesehen ... ja?)