Vérifier un tableau de démineur

33

Votre objectif est de vérifier si un tableau Minesweeper terminé est valide. Cela signifie que chaque nombre représente un nombre correct de mines dans les cellules adjacentes, y compris les diagonales. Le conseil ne s'enroule pas.

Comme d'habitude , vous devez donner une fonction ou un programme, et le code le plus court en octets est gagnant.

Voir également les défis passés pour générer , résoudre et mettre en œuvre intégralement Minesweeper.

Contribution:

Une seule chaîne comme ceci: 02X2 13X2 X211.

  • Les rangées du tableau du dragueur de mines sont séparées par des espaces. Donc, ce qui précède représente le tableau 3x4:

    02X2
    13X2
    X211

  • Chaque cellule est un personnage: Xpour une mine ou un numéro 0par 8.

  • Toutes les lignes ont la même longueur.

  • Il y a au moins 3 lignes et 3 colonnes.

  • L'entrée ne commence ni ne se termine par un espace, mais vous pouvez inclure une nouvelle ligne à la fin si vous le souhaitez.

Sortie:

Une vérité cohérente sur les bons tableaux et une valeur cohérente de Falsey sur les mauvais. Consistant signifie que toutes les sorties Truthy sont identiques et que toutes les sorties Falsey sont identiques.

Cas de test

Chaque ligne est un cas de test distinct.

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
la source
Vous devriez probablement spécifier que la sortie de fausseté cohérente doit être distincte de la sortie de vérité cohérente ;-)
John Dvorak
@ JanDvorak Cela devrait être sous-entendu par le fait qu'ils soient respectivement Truthy et Falsey.
xnor
Pas vraiment. "Truthy" et "Falsy" ne sont que deux étiquettes que vous nous laissez définir. Je ne vois aucune restriction à ce qu'ils soient réellement véridiques ou faux dans le langage que nous utilisons. Le seul mot qui peut nécessiter leur distinction est le verbe "indiquer". Je ne suis pas sûr que cela compte comme une spécification (cependant, c'est toujours interdit comme une échappatoire standard).
John Dvorak
4
@JanDvorak «vérité» et «fausseté» sont en fait des termes assez communs, si je ne me trompe pas, ils sont essentiellement utilisés pour décrire des choses (pas nécessairement des bools) qui sont considérées comme vraies ou fausses lorsqu'elles sont dactylographiées. Par exemple, 0 correspond généralement à la fausseté et 1 à la vérité.
KSab
1
@JanDvorak Nope, Truthy / Falsey doit correspondre correct / incorrect.
xnor

Réponses:

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)

Je l'ai utilisé enumeratedans un golf ... et même utilisé rangeailleurs dans le même programme. Il est clair que quelque chose ne va pas ici.

Edit: Itérer sur dict(enumerate(s))plutôt que enumerate(s), donc enumeraten'a pas besoin d'être appelé deux fois.

feersum
la source
Quelle utilisation intelligente de ~! Et des dictionnaires pour faire du bon travail d’indexation hors des limites.
xnor
@xnor Votre commentaire à propos de l' ~opérateur m'a fait ironiquement remarquer que je l'utilisais deux fois sans aucune raison, alors que l'utiliser une seule fois accomplirait évidemment la même chose. Je pensais que la partie dictionnaire était drôle, merci.
Feersum
9

Pyth, 43

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

Essayez ici .

Explication:

  • Jhxzd: Ceci est l'emplacement du premier espace dans l'entrée + 1. ( zdans l'entrée, dc'est l'espace.) C'est la séparation dans l'entrée entre les cellules verticalement adjacentes du tableau.
  • !f: Ceci est la logique not ( !) d'un filter ( f), qui sera Truesi et seulement si l'expression est falsy pour chaque élément de la séquence.
  • -@zT: Prenez le caractère à l'emplacement T(la variable lambda) de l'entrée et supprimez toutes les apparences de: (Ce sera la vérité si le personnage n'est pas supprimé et faux si c'est le cas.
  • +" X": Supprimer de l'espace, X et
  • `: Repr de
  • sm: somme de la carte à
  • / \X: nombre de "X" dans
  • :+*JNz: La tranche de l'entrée préfixée par Jdes caractères factices
  • td+d2: De j-1 à j + 2.
  • m+T*kJU3: Pour d dans [T, T + J, T + 2 * J].
  • UzPour T in range(len(input)).
isaacg
la source
7
Downvoters: Pourquoi les votes négatifs?
isaacg
7

APL (NARS2000) (74)

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

Fonctionne également dans Dyalog APL si ⎕MLest réglé sur 3.

Explication:

  • ⊃⍵⊂⍨⍵≠' ': divisez les espaces et utilisez les listes pour former une matrice.
  • G←¯1+⎕D⍳: recherchez l’index ⎕Dpour chaque valeur, soustrayez 1 et stockez-le dans G. ( ⎕Dcontient les chiffres, tout non-chiffre deviendra 10).
  • Z←G↑⍨2+⍴G: ajoute deux lignes et colonnes de zéros au bord de la matrice, pour traiter le wraparound
  • {... }¨⍳⍴Z: pour chaque position dans Z, trouvez le nombre de bombes dans le quartier Moore de cette position:
    • G∘.⊖(G←2-⍳3)∘.⌽⊂Z: faire pivoter à Zgauche, à droite, en haut, en bas, à gauche en haut, à droite en haut, à gauche en bas et à droite en bas.
    • ⍵∘⌷¨: pour chacune d'elles, trouver l'élément dans chacune de ces matrices tournées
    • +/∊9<: compte combien d'éléments sont supérieurs à 9 (c'est le nombre de bombes).
  • (⍴G)↑: supprimer à nouveau les lignes de zéros ajoutées,
  • G=: vérifier si chaque élément Gest égal au nombre de bombes entourant cette position (cela devrait être vrai pour tous les carrés non-bombes),
  • (G>9)∨: et vérifiez si les éléments dans Gsont plus élevés que 9(ce sont les bombes).
  • ~0∊: retourne 1si la matrice résultante ne contient pas de zéros (= tous les carrés sont soit des bombes soit le nombre correct), et 0si c'est le cas.
marinus
la source
Avez-vous compté des octets ou des caractères? Vous devriez compter les octets.
Tim S.
5
@TimS .: Il y a des tonnes de codages APL sur 1 octet, en voici un .
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))));}

Première tentative de golf n'importe quoi, et je sais que C # n'est pas la langue idéale.

J'espère que l'écriture d'une méthode d'instance est autorisée, sinon ajoutez 7 autres caractères pour static.

Espacées:

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))));
}

L'utilisation de Linq permet d'économiser de l'espace par rapport aux boucles for, mais il est plus difficile de déboguer.

J'ai appris quelques choses comme convertir char => inten soustrayant '0'.

Il semblait plus simple de remplir le tableau avec des espaces afin de le parcourir plus facilement.

Carl Walsh
la source
1
Ne pouvez-vous pas simplement remplacer -'0'par -48. Fonctionne pour moi et enregistre quelques octets pour divers 'X' et ''
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)

Ceci est fortement inspiré par la réponse de Feersum . L'ordre du jour est exagéré: plutôt que de rechercher des mines chez les 9 voisins de la cellule, vérifiez chaque cellule pour voir s'il s'agit d'une mine voisine.

Nous vérifions si deux cellules sont voisines avec 2>r>-2<c<2, où ret csont les différences de cellules en ligne et en colonne, équivalentes à {r,c}<{-1,0,1}. Ces coordonnées sont calculées à partir des index de cellules Iet ide c=I%n-i%net r=I/n-i/n. Il est plus efficace d'indexer directement dans la chaîne et d'extraire des lignes et des colonnes que de le convertir en objet 2D, tel qu'une liste de listes. Le contrôle de la mine est B[i]>'W', équivalent ici à B[i]=='X'.

Utiliser enumerateaurait sauvé deux caractères sur le vilain range(len(B))sauf qu'il retourne un objet itérateur qui ne supporte pas deux boucles imbriquées.

Xnor
la source
Je pense qu'un module négatif devrait fonctionner pour n; alors vous pourriez utiliser ~B.find.
Feersum
@feersum Malheureusement, cela gâche le fichier /parce qu'il arrondit les négatifs également.
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
la source
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)))

Fournissez une entrée à la fonction sous forme de chaîne:

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

Pour une explication, voir l'ancienne version ci-dessous. La nouvelle version remplace les forboucles par des everyappels et utilise la variable e="every"à faire à la someArray[e](...)place de someArray.every(...).

De plus, le compteur kest maintenant indexé à 1afin que l' k+=...expression soit toujours véridique, afin de maintenir la everyboucle en cours d'exécution. Nous éliminons cet extra 1en soustrayant le truerésultat (qui coïncide numériquement 1) retourné par l' everyopération [-1,0,k=1][e](...).


Ancienne 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 avec espaces et commentaires:

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)
          })
      )

La everyméthode de tableau JavaScript prend un rappel et applique le rappel à chaque élément du tableau. Si un rappel renvoie une valeur falsey, l' everyappel est renvoyé false.

Les booléens dans JS sont forcés à 1 ou 0 lorsqu'ils font partie d'un ajout. Pour chaque espace environnant, nous "ajoutons" le résultat booléen de la comparaison de sa valeur à X, puis ajoutons cette valeur au compteur kdans l'expression k += (... == "X"). Par conséquent, kcontient le nombre de Xs environnants , car truecompte comme 1et falsecompte comme 0.

apsillers
la source
Au lieu d' c=="X"essayer !c/1, vous économiserez une énorme quantité d'octets! Si cela échoue, essayez !!c/1. Le raisonnement est que 'X'/1 => NaN, et NaNest falsie. Vous vérifiez si c=='X', pourquoi ne pas essayer de vérifier si ce n'est pas false?
Ismael Miguel
@IsmaelMiguel Qui évalue la même chose que (!c)/1, ce qui n'aide pas, malheureusement; J'aurais besoin d'avoir les parenthèses pour !(c/1), qui coûtent 2. En outre, 0/1c'est falsey, donc l'entrée " 0X" invalide aurait un résultat incorrect true. Le mieux que je puisse faire, tout en respectant les zéros, est de combiner les deux conditions en une phrase annulée, par exemple !(+c+1&&k-c), mais c'est la même longueur que ce que j'ai déjà.
apsillers
@IsmaelMiguel Merci de m'avoir fait penser à cela - j'ai réalisé que les !(k-1-c)deux conditions sont testées , car si les kcorrespondances c(moins l'offset 1), la négation est 0vraie, et si ce cn'est pas un nombre, nous obtenons NaNla négation est aussi true.
apsillers
Tu avais vraiment faim! Vous avez mangé 10 octets depuis le code initial! J'aime beaucoup la solution que vous avez proposée. +1 pour votre solution!
Ismael Miguel
3

CJam, 70 65 63 octets

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

Cela peut être beaucoup joué au golf.

Donne 1pour un conseil valide et 0pour un conseil non valide.

Cas de test

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

Contribution

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

Sortie

1
1
1
0
0
0

Essayez-le en ligne ici

Optimiseur
la source
3

JavaScript (ES6) 98

Certains utilisent pour appliquer une fonction à chaque caractère de la chaîne.
La fonction retourne

  • faux si vide
  • NaN si 'X' (en soustrayant de manière répétée les valeurs d'un caractère non numérique tel que 'X' donne NaN)
  • Une valeur numérique égale à 0 si le nombre correct de «X» est correct, sinon différent de 0.
    La vérification interne est effectuée à l'aide de la carte, car elle est plus courte que pourChaque

certains retournent vrai à la première valeur de vérité (dans le cas présent, différente de zéro), ce qui signifie un contrôle raté. Le résultat est annulé pour donner un vrai / faux plus reconnaissable.

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
)

Tester dans la console FireFox / FireBug

;["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)))

Sortie

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
la source
1

R, 156 caractères

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])

Avec des retraits, des espaces et des sauts de ligne, pour plus de lisibilité:

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])

Exemples:

> 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
planificateur
la source