Überprüfen Sie ein Minesweeper-Board

33

Ihr Ziel ist es zu überprüfen, ob ein ausgefülltes Minesweeper- Board gültig ist. Dies bedeutet, dass jede Zahl eine korrekte Anzahl von Minen in benachbarten Zellen, einschließlich Diagonalen, darstellt. Das Board wickelt sich nicht um.

Wie üblich sollten Sie eine Funktion oder ein Programm angeben, und der kürzeste Code in Bytes gewinnt.

Sehen Sie sich auch frühere Herausforderungen an , um Minesweeper zu generieren , zu lösen und vollständig zu implementieren .

Eingang:

Eine einzelne Zeichenfolge wie folgt: 02X2 13X2 X211.

  • Die Reihen des Minensuchbrettes sind durch Leerzeichen getrennt. Das Obige repräsentiert also das 3x4-Board:

    02X2
    13X2
    X211

  • Jede Zelle ist ein Zeichen: Xfür eine Mine oder eine Nummer 0durch 8.

  • Alle Zeilen haben die gleiche Länge.

  • Es gibt mindestens 3 Zeilen und 3 Spalten.

  • Die Eingabe beginnt oder endet nicht mit einem Leerzeichen. Wenn Sie möchten, können Sie am Ende eine neue Zeile einfügen.

Ausgabe:

Eine konsistente Wahrheit auf korrekten Boards und ein konsistenter Falsey- Wert auf inkorrekten Boards. Konsistent bedeutet, dass alle Wahrheitsausgaben gleich und alle Falseyausgaben gleich sind.

Testfälle

Jede Zeile ist ein eigener Testfall.

True:

02X2 13X2 X211
XXXX XXXX XXXX XXXX
XX4X2 5X6X4 XX6XX 4XX54 2X4XX

False:

02X2 13X2 X212
XXXX XXXX X7XX XXXX
XX5X2 5X6X4 XX6XX 4XX54 2X5XX
xnor
quelle
Sie sollten wahrscheinlich angeben, dass die konsistente falsy Ausgabe von der konsistenten truthy Ausgabe verschieden sein muss ;-)
John Dvorak
@ JanDvorak Das sollte impliziert werden, dass sie Wahrheit und Falsch sind.
13.
Nicht wirklich. "truthy" und "falsy" sind nur zwei Bezeichnungen, die wir definieren dürfen. Ich kann keine Einschränkung erkennen, dass sie in der Sprache, die wir verwenden, tatsächlich wahr oder falsch sind. Das einzige Wort, bei dem sie möglicherweise unterschiedlich sein müssen, ist das "anzeigende" Verb. Ich bin nicht sicher, ob es als Spezifikation gilt (es ist jedoch immer noch als Standard-Regelungslücke verboten).
John Dvorak
4
@JanDvorak 'Wahrhaftigkeit' und 'Falschheit' sind eigentlich etwas gebräuchliche Begriffe, wenn ich mich nicht irre. Sie werden im Grunde genommen verwendet, um Dinge zu beschreiben (nicht notwendigerweise Narren), die beim Tippen auf Narren als wahr oder falsch bewertet werden. Zum Beispiel ist 0 im Allgemeinen falsch und 1 ist im Allgemeinen wahr.
KSab
1
@JanDvorak Nein, Truthy / Falsey muss richtig / falsch sein.
13.

Antworten:

11

Python 2, 132 129 128

def f(s):w=s.find(' ');E=dict(enumerate(s));return all(E[i]in' X'+`sum(E.get(i+d/3*~w+d%3+w,5)>'O'for d in range(9))`for i in E)

Ich habe enumeratein einem Golf verwendet ... und sogar rangeanderswo im selben Programm verwendet. Hier stimmt eindeutig etwas nicht.

Edit: Iteriere dict(enumerate(s))lieber über enumerate(s), enumeratemuss also nicht zweimal aufgerufen werden.

Feersum
quelle
Was für eine kluge Verwendung von ~! Und von Wörterbüchern, damit die Indexierung außerhalb der Grenzen funktioniert.
16.
@xnor Ihr Kommentar zum ~Betreiber hat mich ironischerweise dazu gebracht, dass ich ihn ohne Grund zweimal verwendet habe, wobei eine einmalige Verwendung offensichtlich das Gleiche bewirken würde. Ich fand den Wörterbuchteil lustig, danke.
Feersum
9

Pyth, 43

Jhxzd!f-@zT+" X"`sm/:+*JNztd+d2\Xm+T*kJU3Uz

Probieren Sie es hier aus .

Erläuterung:

  • Jhxzd: Dies ist die Position des ersten Leerzeichens in der Eingabe + 1. ( zin der Eingabe dist Leerzeichen.) Dies ist die Trennung in der Eingabe zwischen vertikal benachbarten Zellen auf der Platine.
  • !f: Dies ist das logische Nicht ( !) eines Filters ( f). Dies ist Truegenau dann der Fall, wenn der Ausdruck für jedes Element der Sequenz falsch ist.
  • -@zT: Nehmen Sie das Zeichen an der Position T(die Lambda-Variable) aus der Eingabe und entfernen Sie alle Erscheinungen von: (Dies ist wahr, wenn das Zeichen nicht entfernt wird, und falsch, wenn dies der Fall ist.
  • +" X": Entfernen Sie das Leerzeichen, X und
  • `: Repr von
  • sm: Summe der Karte zu
  • / \X: Anzahl der "X" in
  • :+*JNz: Der Abschnitt der Eingabe, dem JDummy-Zeichen vorangestellt sind
  • td+d2: Von d-1 bis d + 2.
  • m+T*kJU3: Für d in [T, T + J, T + 2 * J].
  • UzFür T in range(len(input)).
isaacg
quelle
7
Downvoters: Warum die Downvotes?
Isaacg
7

APL (NARS2000) (74)

{~0∊(G>9)∨G=(⍴G)↑{+/∊9<⍵∘⌷¨G∘.⊖(G←2-⍳3)∘.⌽⊂Z}¨⍳⍴Z←G↑⍨2+⍴G←¯1+⎕D⍳⊃⍵⊂⍨⍵≠' '}

Funktioniert auch in Dyalog APL, wenn auf ⎕MLgesetzt 3.

Erläuterung:

  • ⊃⍵⊂⍨⍵≠' ': Teilen Sie die Leerzeichen auf und bilden Sie aus den Listen eine Matrix.
  • G←¯1+⎕D⍳: Finden Sie den Index in ⎕Dfür jeden Wert, subtrahieren Sie 1 und speichern Sie diesen in G. ( ⎕DEnthält die Ziffern, alle nicht-Ziffern werden zu 10).
  • Z←G↑⍨2+⍴G: Fügen Sie am Rand der Matrix zwei Zeilen und Spalten mit Nullen hinzu, um den Umlauf zu bewältigen
  • {... }¨⍳⍴Z: ZFinden Sie für jede Position in die Anzahl der Bomben in der Nachbarschaft von Moore dieser Position:
    • G∘.⊖(G←2-⍳3)∘.⌽⊂Z: Nach Zlinks, rechts, oben, unten, links oben, rechts oben, links unten und rechts unten drehen .
    • ⍵∘⌷¨: Finden Sie für jedes dieser Elemente das Element in jeder dieser gedrehten Matrizen
    • +/∊9<: Zählen Sie, wie viele Elemente höher als 9 sind (dies ist die Anzahl der Bomben).
  • (⍴G)↑: entferne die hinzugefügten Nullzeilen wieder,
  • G=: Überprüfen Sie, ob jedes Element in der Ggleichen Anzahl von Bomben ist, die diese Position umgeben (dies sollte für alle Nicht-Bomben-Quadrate gelten).
  • (G>9)∨: und überprüfe, ob die Elemente Ghöher sind als 9(das sind die Bomben).
  • ~0∊: 1Gibt zurück, wenn die resultierende Matrix keine Nullen enthält (= alle Quadrate sind entweder Bomben oder die richtige Zahl), und 0wenn ja.
Marinus
quelle
Haben Sie Bytes oder Zeichen gezählt? Sie sollten Bytes zählen.
Tim S.
5
@TimS .: Es gibt viele 1-Byte-APL-Codierungen, hier eine .
Marinus
5

C #, 321 320 305

bool s(string B){var L=B.Split(' ').Select(s=>' '+s+' ').ToList();var b=new string(' ',L[0].Length);L.Insert(0,b);L.Add(b);Func<int,int,IEnumerable<int>>E=Enumerable.Range;return E(1,b.Length-2).All(x=>E(1,L.Count-2).All(y=>L[y][x]=='X'||L[y][x]-'0'==E(x-1,3).Sum(X=>E(y-1,3).Sum(Y=>L[Y][X]=='X'?1:0))));}

Versuchen Sie zuerst, etwas Golf zu spielen, und ich weiß, dass C # nicht die ideale Sprache ist.

Ich hoffe, dass das Schreiben einer Instanzmethode erlaubt ist, ansonsten fügen Sie weitere 7 Zeichen für hinzu static.

Abgetrennt aus:

bool s(string B) {
    var L = B.Split(' ').Select(s => ' ' + s + ' ').ToList();
    var b = new string(' ', L[0].Length);
    L.Insert(0, b);
    L.Add(b);
    Func<int, int, IEnumerable<int>> E = Enumerable.Range;
    return E(1, b.Length - 2).All(x =>
        E(1, L.Count - 2).All(y =>
            L[y][x] == 'X' ||
            L[y][x] - '0' == E(x - 1, 3).Sum(X =>
                E(y - 1, 3).Sum(Y =>
                  L[Y][X] == 'X' ? 1 : 0))));
}

Durch die Verwendung von Linq wird im Vergleich zu for-Schleifen etwas Platz gespart, das Debuggen ist jedoch schwieriger.

Ich habe ein paar Dinge gelernt, wie das Konvertieren char => intdurch Subtrahieren '0'.

Es schien einfacher, das Board mit Leerzeichen auszustatten, damit es einfacher wäre, darüber zu iterieren.

Carl Walsh
quelle
1
Kannst du nicht einfach ersetzen -'0'durch -48. Funktioniert für mich und speichert ein paar Bytes für verschiedene 'X' und ''
Roman Gräf
5

Python 2, 121

def f(B):n=B.find(' ')+1;R=range(len(B));print all(B[I]in' X'+`sum(2>I%n-i%n>-2<I/n-i/n<2<B[i]>'W'for i in R)`for I in R)

Dies ist stark von Feersums Antwort inspiriert . Die Tagesordnung ist übertrieben: Anstatt in den 9 Nachbarn der Zelle nach Minen zu suchen, überprüfen Sie jede einzelne Zelle, um festzustellen, ob es sich um eine benachbarte Mine handelt.

Wir prüfen, ob zwei Zellen Nachbarn sind 2>r>-2<c<2, wobei rund wo cdie Zeilen- und Spaltendifferenzen von Zellen äquivalent sind {r,c}<{-1,0,1}. Diese Koordinaten werden aus den Zellindizes Iund ials c=I%n-i%nund berechnet r=I/n-i/n. Es ist effizienter, die Zeichenfolge direkt zu indizieren und Zeilen und Spalten zu extrahieren, als sie in ein 2D-Objekt wie eine Liste von Listen zu konvertieren. Der Minencheck ist B[i]>'W'hier gleichbedeutend mit B[i]=='X'.

Die Verwendung von enumeratehätte zwei Zeichen über dem Hässlichen gespeichert, mit der range(len(B))Ausnahme, dass ein Iteratorobjekt zurückgegeben wird, das keine zwei verschachtelten Schleifen unterstützt.

xnor
quelle
Ich denke, ein negativer Modul sollte für n funktionieren; dann könntest du verwenden ~B.find.
Feersum
@feersum Leider bringt das das durcheinander, /weil es auch Negative nach unten rundet.
xnor
4

Python 2, 140

s=input();w=s.index(' ')+1
print all(c in'X 'or(int(c)==sum(s[max(0,a-1):max(0,a+2)].count('X')for a in[i-w,i,i+w]))for i,c in enumerate(s))
KSab
quelle
4

JavaScript (ES6), 135 133 125 122

f=s=>s.split(" ")[e="every"]((l,i,a)=>[...l][e]((c,j)=>!(-[-1,0,k=1][e]((y,m,q)=>q[e](x=>k+=(a[i+y]||0)[j+x]=="X"))-c+k)))

Geben Sie die Funktion als Zeichenfolge ein:

f("XX4X2 5X6X4 XX6XX 4XX54 2X4XX");

Eine Erklärung finden Sie in der alten Version weiter unten. Die neue Version ersetzt die forSchleifen mit everyAnrufen und verwendet die Variable e="every"zu tun , someArray[e](...)statt someArray.every(...).

Außerdem ist der Zähler kjetzt auf indexiert, 1sodass der k+=...Ausdruck immer wahr ist, um die everySchleife am Laufen zu halten . Wir eliminieren dieses Extra 1durch Subtrahieren des trueErgebnisses (das numerisch erzwungen wird 1), das von der everyOperation zurückgegeben wird [-1,0,k=1][e](...).


Alte Version:

f=s=>s.split(" ").every((l,i,a)=>[...l].every((c,j)=>{q=[-1,k=0,1];for(y of q)for(x of q)k+=(a[i+y]||0)[j+x]=="X";return c=="X"||k==c}))

Code mit Leerzeichen und Kommentaren:

f=s=>s.split(" ")                 // split on spaces
      .every((l,i,a)=>             // for every line
                                   //     l: line string, i: line number, a: whole array
          [...l].every((c,j)=>{    // for every character
                                   //     c: character, j: index in string
              q=[-1,k=0,1];        // define counter k=0 and q=[-1,0,1]
              for(y of q)          // use q to loop adjacent spaces
                  for(x of q)

                      k+=              // add the following boolean to k:

                          (a[i+y]      //   from line number i+y...
                                 ||0)  //   (or a dummy zero, to prevent lookups on undefined)
                          [j+x]        //   ...get index j+x from the above value...
                                =="X"; //   ...and compare it to "X"

              return !(k-c)     // after the loop, this character passed if
                                // the char equals the number of counted X's (so k-c is 0)
                                // or it is an X itself (so `k-c` is NaN)
          })
      )

Die JavaScript- everyArray-Methode nimmt einen Rückruf entgegen und wendet den Rückruf auf jedes Element des Arrays an. Wenn ein Rückruf einen falschen Wert zurückgibt, wird der everyAnruf zurückgegeben false.

Boolesche Werte in JS werden als Teil einer Addition auf 1 oder 0 gesetzt. Für jeden umgebenden Raum "addieren" wir das boolesche Ergebnis des Vergleichs seines Werts mit Xund addieren diesen Wert dann zum Zähler kim Ausdruck k += (... == "X"). Daher kenthält eine Zählung der Anzahl der umgebenden Xs, da truezählt als 1und falsezählt als 0.

Apsillers
quelle
Anstatt zu c=="X"versuchen !c/1, das spart Ihnen eine Menge von ein paar Bytes! Wenn es fehlschlägt, versuchen Sie es !!c/1. Die Argumentation ist die 'X'/1 => NaN, und NaNist falsch. Sie prüfen, ob c=='X'und warum nicht, ob dies nicht der falseFall ist.
Ismael Miguel
@IsmaelMiguel Das bewertet genauso (!c)/1, was leider nicht hilft; Ich brauche die Klammern für !(c/1), die 2 kosten. Auch 0/1ist falsch, so dass die ungültige Eingabe " 0X" das falsche Ergebnis hätte true. Das Beste, was ich tun kann, während ich immer noch Nullen respektiere, ist, die beiden Bedingungen zu einer negierten Phrase zu kombinieren !(+c+1&&k-c), aber das ist die gleiche Länge wie das, was ich bereits habe.
Apsillers
@IsmaelMiguel Vielen Dank, dass Sie mich zum Nachdenken gebracht haben. Ich habe festgestellt, dass !(k-1-c)beide Bedingungen getestet werden, denn wenn kÜbereinstimmungen c(abzüglich des 1-Offsets) vorliegen, ergibt die Negation die 0Wahrheit, und wenn ces sich nicht um eine Zahl handelt, erhalten wir NaNund die Negation ist auch true.
Apsillers
Du warst wirklich hungrig! Sie haben seit dem ersten Code 10 Bytes gegessen! Die Lösung, die Sie gefunden haben, gefällt mir sehr gut. +1 für Ihre Lösung!
Ismael Miguel
3

CJam, 70 65 63 Bytes

1l_S#):L)S*+:Q{Ii33/2%[0~1LL)L(L~)L~_))]W):Wf+Qf='X/,(scI==&}fI

Dies kann viel Golf gespielt werden.

Gibt 1für eine gültige Karte und 0für eine ungültige Karte.

Testfälle

{-1:W;
1l_S#):L)S*+:Q{Ii33/2%[0~1LL)L(L~)L~_))]W):Wf+Qf='X/,(scI==&}fI
}6*]N*

Eingang

02X2 13X2 X211
XXXX XXXX XXXX XXXX
XX4X2 5X6X4 XX6XX 4XX54 2X4XX
02X2 13X2 X212
XXXX XXXX X7XX XXXX
XX5X2 5X6X4 XX6XX 4XX54 2X5XX

Ausgabe

1
1
1
0
0
0

Probieren Sie es hier online aus

Optimierer
quelle
3

JavaScript (ES6) 98

Verwenden Sie some , um eine Funktion auf jedes Zeichen der Zeichenfolge anzuwenden.
Die Funktion kehrt zurück

  • false, wenn leer
  • NaN wenn 'X' (wiederholtes Subtrahieren von Werten von einem nicht numerischen Zeichen wie 'X' ergibt NaN)
  • Ein numerischer Wert von 0, wenn die richtige Anzahl von aufeinanderfolgenden 'X' vorhanden ist, andernfalls nicht 0.
    Die innere Prüfung erfolgt mit map, nur weil sie kürzer als forEach ist

Einige geben beim ersten Wahrheitswert (in diesem Fall ungleich Null) true zurück, was bedeutet, dass die Prüfung fehlgeschlagen ist. Das Ergebnis wird negiert, um ein besser erkennbares Wahr / Falsch zu erhalten.

F=v=>![...v].some(
  (x,p)=>x!=' '&&[1,-1,l=v.search(' '),-l,++l,-l,++l,-l].map(q=>x-=v[p+q]=='X')|x
)

Test In FireFox / Firebug - Konsole

;["02X2 13X2 X212","XXXX XXXX X7XX XXXX","XX5X2 5X6X4 XX6XX 4XX54 2X5XX"
,"02X2 13X2 X211","XXXX XXXX XXXX XXXX","XX4X2 5X6X4 XX6XX 4XX54 2X4XX","111 1X1 111"]
.forEach(t => console.log(t, F(t)))

Ausgabe

02X2 13X2 X212 false
XXXX XXXX X7XX XXXX false
XX5X2 5X6X4 XX6XX 4XX54 2X5XX false
02X2 13X2 X211 true
XXXX XXXX XXXX XXXX true
XX4X2 5X6X4 XX6XX 4XX54 2X4XX true
111 1X1 111 true
edc65
quelle
1

R 156 Zeichen

a=b=do.call(rbind,strsplit(scan(,""),""));for(i in 1:nrow(a))for(j in 1:ncol(a))b[i,j]=sum(a[abs(i-row(a))<2&abs(j-col(a))<2]=="X");v=a!="X";all(b[v]==a[v])

Mit Einrückungen, Leerzeichen und Zeilenumbrüchen zur besseren Lesbarkeit:

a = b = do.call(rbind,strsplit(scan(,""),"")) #Reads stdin and turn into a matrix
for(i in 1:nrow(a)) #Ugly, ugly loop
    for(j in 1:ncol(a))
        b[i,j] = sum(a[abs(i-row(a))<2 & abs(j-col(a))<2]=="X")
v = a!="X"
all(b[v]==a[v])

Beispiele:

> a=b=do.call(rbind,strsplit(scan(,""),""));for(i in 1:nrow(a))for(j in 1:ncol(a))b[i,j]=sum(a[abs(i-row(a))<2&abs(j-col(a))<2]=="X");v=a!="X";all(b[v]==a[v])
1: XX4X2 5X6X4 XX6XX 4XX54 2X4XX
6: 
Read 5 items
[1] TRUE
> a=b=do.call(rbind,strsplit(scan(,""),""));for(i in 1:nrow(a))for(j in 1:ncol(a))b[i,j]=sum(a[abs(i-row(a))<2&abs(j-col(a))<2]=="X");v=a!="X";all(b[v]==a[v])
1: XXXX XXXX XXXX XXXX
5: 
Read 4 items
[1] TRUE
> a=b=do.call(rbind,strsplit(scan(,""),""));for(i in 1:nrow(a))for(j in 1:ncol(a))b[i,j]=sum(a[abs(i-row(a))<2&abs(j-col(a))<2]=="X");v=a!="X";all(b[v]==a[v])
1: XX5X2 5X6X4 XX6XX 4XX54 2X5XX
6: 
Read 5 items
[1] FALSE
Plannapus
quelle