Verificar un tablero de Buscaminas

33

Su objetivo es verificar si un tablero de Buscaminas completo es válido. Esto significa que cada número es un recuento correcto de minas en las celdas adyacentes, incluidas las diagonales. El tablero no se envuelve.

Como de costumbre , debe asignar una función o programa, y ​​gana el código más corto en bytes.

Vea también los desafíos pasados ​​para generar , resolver e implementar completamente Buscaminas.

Entrada:

Una sola cadena como esta: 02X2 13X2 X211.

  • Las filas del tablero del buscaminas se dan separadas por espacios. Entonces, lo anterior representa el tablero 3x4:

    02X2
    13X2
    X211

  • Cada celda es un carácter: Xpara una mina, o un número a 0través 8.

  • Todas las filas tienen la misma longitud.

  • Hay al menos 3 filas y 3 columnas.

  • La entrada no comienza o termina con un espacio, pero puede incluir una nueva línea al final si lo desea.

Salida:

Una Verdad consistente en tableros correctos, y un valor Falsey consistente en tableros incorrectos. Consistente significa que todas las salidas de Truthy son iguales y todas las salidas de Falsey son iguales.

Casos de prueba

Cada línea es un caso de prueba separado.

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
fuente
Probablemente debería especificar que la salida falsa consistente debe ser distinta de la salida veraz consistente ;-)
John Dvorak
@ JanDvorak Eso debería estar implícito en que ellos son Truthy y Falsey respectivamente.
xnor
Realmente no. "verdadero" y "falso" son solo dos etiquetas que nos dejas definir. No puedo ver ninguna restricción, en realidad son verdaderas o falsas, respectivamente, en el lenguaje que utilizamos. La única palabra que puede requerir que sean distintos es el verbo "indicador". No estoy seguro de que cuente como una especificación (aunque todavía está prohibido como una laguna estándar).
John Dvorak
44
@JanDvorak 'verdadero' y 'falso' son en realidad términos comunes si no me equivoco, básicamente se usa para describir cosas (no necesariamente bools) que se evalúan como verdaderas o falsas cuando se escriben en bools. Por ejemplo, 0 es generalmente falso y 1 es generalmente verdadero.
KSab
1
@ JanDvorak No, Truthy / Falsey tiene que coincidir correcto / incorrecto.
xnor

Respuestas:

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)

Solía enumerateen un campo de golf ... e incluso rangeen otro lugar del mismo programa. Claramente algo está mal aquí.

Editar: Iterar dict(enumerate(s))más que enumerate(s), por lo que enumerateno es necesario llamarlo dos veces.

Feersum
fuente
¡Qué uso tan inteligente ~! Y de diccionarios para hacer que la indexación fuera de límites funcione correctamente.
xnor
@xnor Su comentario sobre el ~operador, irónicamente, me hizo notar que lo estaba usando dos veces sin ningún motivo, donde usarlo solo una vez obviamente lograría lo mismo. Pensé que la parte del diccionario era divertida, gracias.
feersum
9

Pyth, 43

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

Probarlo aquí .

Explicación:

  • Jhxzd: Esta es la ubicación del primer espacio en la entrada + 1. ( zen la entrada, des espacio). Es la separación en la entrada entre celdas verticalmente adyacentes en el tablero.
  • !f: Este es el no lógico ( !) de un filtro ( f), que será Truesi y solo si la expresión es falsa para cada elemento de la secuencia.
  • -@zT: Tome el carácter en la ubicación T(la variable lambda) de la entrada y elimine cualquier aspecto de: (Esto será verdadero si el carácter no se elimina y falso si lo es.
  • +" X": Eliminar espacio, X y
  • `: Repr de
  • sm: suma del mapa a
  • / \X: recuento de "X" en
  • :+*JNz: El segmento de la entrada con el prefijo de Jcaracteres ficticios
  • td+d2: De d-1 a d + 2.
  • m+T*kJU3: Para d en [T, T + J, T + 2 * J].
  • UzPara T en range(len(input)).
isaacg
fuente
77
Votantes: ¿Por qué los votos negativos?
isaacg
7

APL (NARS2000) (74)

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

También funciona en Dyalog APL si ⎕MLestá configurado en 3.

Explicación:

  • ⊃⍵⊂⍨⍵≠' ': dividir en los espacios y utilizar las listas para formar una matriz.
  • G←¯1+⎕D⍳: encuentre el índice en ⎕Dcada valor, reste 1 y almacene esto en G. ( ⎕Dcontiene los dígitos, cualquier no dígito se convertirá en 10).
  • Z←G↑⍨2+⍴G: agregue dos líneas y columnas de ceros en el borde de la matriz, para tratar el envolvente
  • {... }¨⍳⍴Z: para cada posición en Z, encuentre la cantidad de bombas en el vecindario de Moore de esa posición:
    • G∘.⊖(G←2-⍳3)∘.⌽⊂Z: gire a la Zizquierda, derecha, arriba, abajo, izquierda-arriba, derecha-arriba, izquierda-abajo y derecha-abajo.
    • ⍵∘⌷¨: para cada uno de estos, encuentre el elemento en cada una de estas matrices rotadas
    • +/∊9<: cuenta cuántos elementos son superiores a 9 (esta es la cantidad de bombas).
  • (⍴G)↑: elimine las líneas agregadas de ceros nuevamente,
  • G=: comprueba si cada elemento en Ges igual a la cantidad de bombas que rodean esa posición (esto debería ser cierto para todos los cuadrados que no son bombas),
  • (G>9)∨: y compruebe si los elementos en Gson más altos que 9(estas son las bombas).
  • ~0∊: devuelve 1si la matriz resultante no contiene ceros (= todos los cuadrados son bombas o el número correcto), y 0si lo tiene.
marinus
fuente
¿Contaste bytes o caracteres? Deberías contar los bytes.
Tim S.
55
@TimS .: Hay un montón de codificaciones APL de 1 byte, aquí hay una .
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))));}

Primero intento jugar al golf, y sé que C # no es el lenguaje ideal.

Espero que se permita escribir un método de instancia, de lo contrario agregue otros 7 caracteres para static.

Espaciado:

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

Usar Linq ahorra algo de espacio en comparación con los bucles for, pero es más difícil de depurar.

Aprendí algunas cosas como convertir char => intrestando '0'.

Parecía más simple rellenar el tablero con espacios, por lo que iterar sobre él sería más fácil.

Carl Walsh
fuente
1
¿No puedes simplemente reemplazarlo -'0'por -48? Funciona para mí y guarda algunos bytes para varias 'X' y ''
Roman Gräf
5

Pitón 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)

Esto está fuertemente inspirado por la respuesta de feersum . El orden del día es excesivo: en lugar de buscar minas en los 9 vecinos de la celda, verifique cada celda para ver si es una mina vecina.

Verificamos si dos celdas son vecinas 2>r>-2<c<2, donde ry cson las diferencias de fila y columna de las celdas, equivalentes a {r,c}<{-1,0,1}. Estas coordenadas se calculan a partir de los índices de celda Iy icomo c=I%n-i%ny r=I/n-i/n. Es más eficiente indexar directamente en la cadena y extraer filas y columnas que convertirlo en un objeto 2D como una lista de listas. La verificación de la mina es B[i]>'W'equivalente aquí a B[i]=='X'.

El uso enumeratehabría salvado dos caracteres sobre lo feo, range(len(B))excepto que devuelve un objeto iterador que no admite dos bucles anidados a través de él.

xnor
fuente
Creo que un módulo negativo debería funcionar para n; entonces podrías usar ~B.find.
feersum
@feersum Desafortunadamente, eso arruina el /porque redondea los negativos también hacia abajo.
xnor
4

Pitón 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
fuente
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)))

Proporcione entrada a la función como una cadena:

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

Para una explicación, vea la versión anterior, a continuación. La nueva versión reemplaza los forbucles con everyllamadas y usa la variable e="every"para hacer en someArray[e](...)lugar de someArray.every(...).

Además, el contador kahora está indexado 1para que la k+=...expresión sea siempre verdadera, a fin de mantener el everyciclo en ejecución. Eliminamos ese extra 1restando el trueresultado (que coacciona numéricamente 1) devuelto por la everyoperación [-1,0,k=1][e](...).


Versión antigua:

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

Código con espacios y comentarios:

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

El everymétodo de matriz de JavaScript toma una devolución de llamada y aplica la devolución de llamada a cada elemento de la matriz. Si alguna devolución de llamada devuelve un valor falso, la everyllamada vuelve false.

Los booleanos en JS se convierten a 1 o 0 cuando forman parte de una adición. Para cada espacio circundante, "agregamos" el resultado booleano de comparar su valor Xy luego agregamos ese valor al contador ken la expresión k += (... == "X"). Por lo tanto, kcontiene un recuento del número de Xs circundantes , porque truecuenta como 1y falsecuenta como 0.

apsillers
fuente
¡En lugar de c=="X"intentarlo !c/1, lo que le ahorra una gran cantidad de un par de bytes! Si falla, inténtalo !!c/1. El razonamiento es eso 'X'/1 => NaN, y NaNes falso. Comprueba si c=='X', ¿por qué no intentas comprobar si no es así false?
Ismael Miguel
@IsmaelMiguel Eso evalúa lo mismo (!c)/1que, desafortunadamente, no ayuda; Necesito tener los paréntesis para !(c/1), que cuestan 2. Además, 0/1es falsey, por lo que la entrada no válida " 0X" tendría el resultado incorrecto true. Lo mejor que puedo hacer sin dejar de respetar los ceros es combinar las dos condiciones en una frase negada, como !(+c+1&&k-c), pero esa es la misma longitud que ya tengo.
apsillers
@IsmaelMiguel Gracias por hacerme pensar en eso, me he dado cuenta de que !(k-1-c)prueba ambas condiciones, porque si kcoincide c(menos el desplazamiento 1), entonces la negación se 0cumple, y si cno es un número, obtenemos NaNla negación es también true.
apsillers
¡Realmente tenías hambre! ¡Te comiste 10 bytes desde el código inicial! Realmente me gusta la solución que se te ocurrió. ¡+1 para tu solución!
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

Esto se puede jugar mucho al golf.

Da 1por un tablero válido y 0por un tablero no válido.

Casos de prueba

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

Entrada

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

Salida

1
1
1
0
0
0

Pruébalo en línea aquí

Optimizador
fuente
3

JavaScript (ES6) 98

Usando algunos para aplicar una función a cada carácter de la cadena.
La función vuelve

  • falso si está en blanco
  • NaN si 'X' (restar repetidamente valores de un carácter no numérico como 'X' da NaN)
  • Un valor numérico de 0 si hay el número correcto de 'X' adiacente, de lo contrario no 0.
    El control interno se realiza utilizando el mapa solo porque es más corto que para Cada

algunos devuelve verdadero en el primer valor verdadero (en este caso, distinto de cero), lo que significa una comprobación fallida. El resultado se niega para dar un verdadero / falso más reconocible.

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
)

Prueba en la consola 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)))

Salida

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
fuente
1

R, 156 caracteres

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

Con sangrías, espacios y saltos de línea, para legibilidad:

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

Ejemplos:

> 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
fuente