Verificar el rompecabezas de las reinas

16

Si no sabes qué es una reina en el ajedrez, no importa mucho; es solo un nombre :)

Tu entrada será un cuadrado de ancho y alto arbitrario que contiene cierta cantidad de reinas. La placa de entrada se verá así (esta placa tiene un ancho y una altura de 8):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

Hay 8 reinas en este tablero. Si hubiera, digamos, 7, o 1, o 10 aquí, el tablero no sería válido.

Aquí usamos un .para un espacio vacío, y unQ para una reina. Alternativamente, puede usar cualquier carácter que no sea un espacio en blanco que desee en su lugar.

Esta entrada puede verificarse como válida, y debe imprimir (o devolver) un valor verdadero (si no es válido, debe imprimir (o devolver) un valor falso). Es válido porque ninguna reina está en la misma fila, columna, diagonal o anti-diagonal que otra. .

Ejemplos (no mostrar cosas entre paréntesis):

...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q..

1

...Q.
Q....
.Q...
....Q
..Q..

0

Q.
Q.

0

..Q
...
.Q.

0 (this is 0 because there are only 2 queens on a 3x3 board)


..Q.
Q...
...Q
.Q..

1

Q

1 (this is valid, because the board is only 1x1, so there's no queen that can take another)

Permítanme enfatizar que una entrada solo es válida, si ninguna reina está en la misma fila, columna, diagonal o anti-diagonal que otra .

Reglas

  • Nunca recibirá una entrada vacía
  • Si la entrada contiene menos reinas que la raíz cuadrada del área del tablero, no es válida.
  • Tenga en cuenta que no hay soluciones válidas para un tablero de 2x2 o 3x3, pero hay una solución para cualquier tablero cuadrado de otro tamaño , donde el ancho y la altura es un número natural.
  • La entrada puede estar en cualquier formato razonable, según las reglas de PPCG
  • La entrada siempre será un cuadrado
  • Usé 1 y 0 en los ejemplos, pero puede usar cualquier valor verdadero o falso (como Why yes, sir, that is indeed the casey Why no, sir, that is not the case)

Como se trata de , ¡el código más corto gana!

Okx
fuente
Continuemos esta discusión en el chat .
Okx
1
Would {(x, y, v)}con vde [., Q]ser un formato de entrada válida?
PidgeyUsedGust
@DuctrTape No creo que tenga mucho sentido.
Okx
2
@Okx En otras palabras, están preguntando acerca de recibir una lista de coordenadas y valores como entrada. Por ejemplo: (0, 0, Q), (0, 1, .), (1, 0, Q), (1, 1, .)sería el tercer caso de prueba.
Mego
¿Puedo tomar una cadena sin saltos de línea?
Titus

Respuestas:

7

Caracoles , 14 bytes

&
o.,\Q!(z.,\Q

Pruébalo en línea!

Nada como un lenguaje de coincidencia de patrones 2D para un problema de decisión 2D. :)

Explicación

La &opción en la primera línea es una opción de modo de coincidencia que requiere que el patrón en la segunda línea coincida desde todas las posiciones posibles en la entrada. Si ese es el caso, el programa imprime 1, de lo contrario imprime 0.

En cuanto al patrón en sí, tenga en cuenta que hay un implícito )al final.

o       ,, Move in any orthogonal direction (up, down, left or right).
.,\Q    ,, Make sure that there's a Q somewhere in that direction from the
        ,, starting position of the match.
!(      ,, After finding the Q, make sure that the following part _doesn't_ match:
  z     ,,   Move in any orthogonal or diagonal direction.
  .,\Q  ,,   Try to find another Q in a straight line.
)

Es más fácil ver por qué esto funciona al comenzar desde el lado negativo: al asegurarnos de que no haya Quna línea recta con respecto a la otra Qque ya hemos encontrado, nos aseguramos de que no haya más que N reinas (de lo contrario, habría ser dos en una fila, y no sería posible encontrar estas reinas sin encontrar otra). Luego, la primera parte, asegurándose de que haya una reina accesible en una dirección ortogonal desde cualquier posición, se asegura de que haya exactamente N reinas. Si faltaba uno, habría una fila y una columna sin una reina. A partir de la intersección de estos, no sería posible encontrar una reina yendo solo en una dirección ortogonal.

Martin Ender
fuente
6

Gelatina , 17 o 15 bytes

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ

Pruébalo en línea!

Usos para una reina y ¹para espacios en blanco. (Esto es principalmente una consecuencia de la prohibición de tomar la entrada como una matriz, porque obliga a la entrada a ser cadenas; convertir las cadenas en enteros es difícil en Jelly, ya que el método más fácil es la evaluación, y resulta que en lugar de 1 y 0, usando "add 1" ( ) y "add 0" ( ¹) hacen posible omitir varias instrucciones de suma y mapa, porque podemos contar las reinas en una lista al evaluarla.) Los valores de verdad y falsey son normales 1y Jelly0 .

EDITAR: La pregunta ha cambiado desde que escribí esta respuesta para permitir tomar la entrada como una matriz. Esto permite descartar el líder Ỵµ, ahorrando 2 bytes. Probablemente también permita cambiar el formato de entrada a algo más normal, usar Spara sumar en lugar de Vevaluar, pero no creo que eso guarde bytes y me gusta este formato original.

Explicación

ỴµUŒD;ŒD;ZVṀ;V=1Ṃ
Ỵ                    Split on newlines.
 µ                   Set this value as the default for missing arguments.
     ;  ;            Concatenate the following three values:
  UŒD                - the antidiagonals;
      ŒD             - the diagonals;
         Z           - and the columns.
          V          Evaluate (i.e. count the queens on) all of those.
           Ṁ         Take the largest value among the results.
            ;V       Append the evaluation (i.e. queen count) of {each row}.
              =1     Compare each value to 1.
                Ṃ    Take the minimum (i.e. most falsey) result.

Entonces, la idea básica es asegurarnos de que haya como máximo una reina en cada antidiagonal, diagonal y columna; y exactamente una reina en cada fila. Estas condiciones son lo suficientemente juntas como para requerir que haya como máximo una reina en cada uno de los cuatro tipos de línea, y un número de reinas igual a la longitud del lado del tablero.

Por cierto, a Jelly probablemente le vendría bien un antidiagoniales incorporado, pero AFAICT no parece tener uno, así que tengo que conformarme con reflejar el tablero y luego tomar las diagonales.

Otra nota interesante es que cambiar =1Ṃa E(todos iguales) da un corrector general de n -queens, que también aceptará un tablero n × n donde cada fila, columna, diagonal y antidiagonal no contiene más que k reinas, y el tablero contiene exactamente Kn reinas. Restringir k para que sea igual a 1 en realidad cuesta dos bytes.


fuente
Las reglas se actualizaron, ahora "La entrada puede estar en cualquier formato razonable, según las reglas PPCG", eso debería acortarla :) EDITAR - Veo que lo notó.
Jonathan Allan
5

Octava, 57 70 67 51 52 bytes

Se guardó 1 byte usando en fliplugar de rot90gracias a @LuisMendo, pero encontré un error en el caso 1x1

@(A)all(sum([A A' (d=@spdiags)(A) d(flip(A))],1)==1)

Toma la entrada como una matriz binaria con 1 que representa una Reina y 0 que representa un espacio vacío.

Crea una función anónima que primero concatena la matriz de entrada y su transposición.

spdiagscrea una matriz con el mismo número de filas que el argumento, con las diagonales convertidas en columnas (rellenadas con ceros según sea necesario), de modo que concatene spdiagsla matriz de entrada para obtener las diagonales yspdiags de la matriz volteada horizontalmente para obtener las antidiagonales.

Ahora tome la suma de cada columna de la matriz concatenada y asegúrese de que cada columna sea exactamente 1.

Ejecución de muestra en ideone .

cubilete
fuente
Creo que puedes usar en fliplugar derot90
Luis Mendo
@LuisMendo Sí, eso también funcionará. ¡Gracias!
vaso de precipitados el
Además, ¿no puedes evitarlo all()?
Luis Mendo
@LuisMendo Ugh ... probablemente ... pero tendrá que esperar hasta después de la cena;)
vaso
4

MATL , 38 34 bytes

¡4 bytes de descuento gracias a @beaker !

sG!sGt&n_w&:&XdsGP5M&Xdsv2<GnGzU=*

La entrada es una matriz 2D de ceros y unos, usando punto y coma como separadores de fila.

Esto genera un vector de columna de unos como verdadero, y un vector de columna que contiene al menos un cero como falso.

Pruébalo en línea! El código de pie de página es una iframa para demostrar veracidad o falsedad.

O verificar todos los casos de prueba .

Explicación

s      % Input binary matrix implicitly. Sum of columns. Gives a row vector
G!     % Paste input again. Transpose
s      % Sum of columns (rows in the original matrix). Gives a row vector
G      % Paste input again
t&n    % Duplicate. Push number of rows and number of columns (will be equal)
_w     % Negate, flip
&:     % Binary range. Gives [-n -n+1 ... n] for input of size n×n
&Xd    % Get diagonals -n through n. This gives all diagonals as colums
s      % Sum of each column (diagonals of original matrix). Gives a row vector
GP     % Paste input again. Flip vertically
5M     % Push [-n -n+1 ... n] again
&Xd    % Get diagonals -n through n (anti-diagonals of original matrix)
s      % Sum of each column. Gives a row vector
v      % Concatenate everything into a column vector
2<     % True for elements that are less than 2
Gn     % Paste input again. Number of elements
Gz     % Paste input again. Number of nonzeros (i.e. of queens)
U      % Square
=      % True if equal
*      % Mutiply, element-wise
Luis Mendo
fuente
Puede guardar 2 bytes ahora que puede tomar una matriz binaria como entrada.
vaso de precipitados el
2

J , 37 bytes

(+/&,=#)*1=[:>./+//.,+//.&|.,+/,+/&|:

Tren de funciones anónimo que toma la matriz booleana como argumento.

Pruébalo en línea!

( +/la suma &del ,enmarañamiento =es igual #al recuento de filas)

* y (lit. veces)

1uno =es igual [:al >./máximo de

+/las sumas en /.diagonal ,y (lit. cateadas a)

+/ las sumas /. diagonal &del |.reverso ,y

+/las sumas a través ,y

+/las sumas &de |:la transposición

Adán
fuente
2

SnakeEx , 67 bytes

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}
e:.$
q:_*Q_*$
n:_+$

Usos _ en lugar de .en la entrada. Devuelve 1 o más coincidencias para la verdad, 0 coincidencias para falsey. Puede encontrar un intérprete en línea en el enlace en el encabezado.

Explicación

SnakeEx es un lenguaje del desafío de coincidencia de patrones 2D . Define "serpientes" que se mueven alrededor de la cuadrícula haciendo coincidir cosas. Las serpientes pueden generar otras serpientes, lo que hace que el lenguaje sea bastante poderoso.

Miremos este programa de abajo hacia arriba.

n:_+$

Esto define una serpiente nque coincide con 1 o más guiones bajos y luego el borde de la cuadrícula. Tenga en cuenta que esto puede estar en cualquiera de las 8 direcciones cardinales: la dirección se determina cuando se genera la serpiente.

q:_*Q_*$

Similar a lo nanterior, esto se define qcomo una serpiente que coincide con cualquier número de guiones bajos, un solo Q, cualquier número de guiones bajos y el borde de la cuadrícula. En otras palabras, una fila / columna / diagonal que solo tiene una reina.

e:.$

e es una serpiente que coincide con un personaje y el borde de la cuadrícula.

m:({q<>}({q<R>}[{q<RF>}{n<RF>}].)*{e<>}<R>)%{4}

La serpiente principal m usa estos bloques de construcción para verificar todo el tablero. Conceptualmente, se ejecuta alrededor de los bordes exteriores de la cuadrícula, engendrando otras serpientes para verificar que todas las columnas y filas tengan exactamente una reina, y todas las diagonales tengan como máximo una reina. Si alguna de las serpientes engendradas no coincide, la coincidencia completa falla. Vamos a desglosarlo.

  • ( )%{4}ejecuta lo que está dentro del paréntesis 4 veces, una para cada lado. (En lo que sigue, es útil imaginar un lado en particular, por ejemplo, el borde superior de la cuadrícula, comenzando desde la esquina superior izquierda y moviéndose hacia la derecha).
  • {q<>}genera una qserpiente en la misma dirección en que se mueve la serpiente principal. Esto verifica que el borde actual cumple con la regla de "exactamente una reina". Tenga en cuenta que las serpientes engendradas no mueven el puntero de la serpiente principal, por lo que todavía estamos al principio del borde.
  • ( )* coincide con 0 o más de lo que está dentro de los paréntesis.
  • {q<R>}genera una qserpiente girada hacia la derecha desde la dirección de la serpiente principal. (Por ejemplo, si la serpiente principal se mueve hacia la derecha a lo largo del borde superior, esta serpiente se mueve hacia abajo). Esto verifica cada columna / fila.
  • [ ] coincide con cualquiera de las opciones dentro de los corchetes:
    • {q<RF>}genera una qserpiente girada 45 grados hacia la derecha (es decir, hacia adelante Ry hacia Fatrás) desde la dirección de la serpiente principal. La qserpiente coincide si la diagonal contiene exactamente una reina.
    • {n<RF>}genera una nserpiente en su lugar. La nserpiente coincide si la diagonal no contiene reinas.
  • . coincide con cualquier personaje, moviendo el puntero de coincidencia hacia adelante.
  • Después de verificar tantas horizontales y diagonales como sea posible, verificamos que estamos en el borde generando {e<>} .
  • Finalmente, <R>gira la serpiente principal hacia la derecha, lista para que coincida con el siguiente borde.

Cosas raras

  • No hay nada en el programa para garantizar que la coincidencia comience en una esquina exterior. De hecho, los casos de prueba verdaderos producen varias coincidencias, algunas de las cuales comienzan en algún lugar del interior. A pesar de esto, ninguno de los casos de falsey que he probado ha generado falsos positivos.
  • Si estoy leyendo la especificación de idioma correctamente, debería haber podido usar X(ramificar en todas las direcciones diagonales) en lugar de RF. Desafortunadamente, el intérprete en línea dijo que era un error de sintaxis. También intenté* (bifurcar en todas las direcciones), pero eso colgó al intérprete.
  • Teóricamente, algo así _*Q?_*$debería funcionar para hacer coincidir "como máximo una reina" en las diagonales, pero eso también colgó al intérprete. Supongo que la posibilidad de coincidencias vacías causa problemas.
DLosc
fuente
2

Ruby, 120 bytes

Función Lambda basada en la especificación original que requería entrada como una cadena.

->s{t=k=0
a=[]
s.bytes{|i|i>65&&(a.map{|j|t&&=((k-j)**4).imag!=0};a<<k)
k=i<11?k.real+1:k+?i.to_c}
t&&~a.size**2>s.size}

convierte las Q en números complejos y las resta unas de otras. Si la diferencia entre las coordenadas de cualquiera de las dos reinas es horizontal, vertical o diagonal, elevarla a la cuarta potencia arrojará un número real y la disposición no es válida.

Sin golf en el programa de prueba

f=->s{                                 #Take input as string argument.
  t=k=0                                #k=coordinate of character. t=0 (truthy in ruby.)
  a=[]                                 #Empty array for storing coordinates.
  s.bytes{                             #Iterate through all characters as bytes.
    |i|i>65&&(                         #If alphabetical, compare the current value of k to the contents of a
      a.map{|j|t&&=((k-j)**4).imag!=0} #If k-j is horizontal, vertical or diagonal, (k-j)**4 will be real and t will be false
      a<<k)                            #Add the new value of k to the end of a.
    k=i<11?k.real+1:k+?i.to_c          #If not a newline, increment the imaginary part of k. If a newline, set imaginary to 0 and increment real
  }                                    #s.size should be a*a + a newlines. ~a.size = -1-a.size, so ~a.size**2 = (a.size+1)**2
t&&~a.size**2>s.size}                  #compare a.size with s.size and AND the result with t. Return value. 


p f["...Q....
......Q.
..Q.....
.......Q
.Q......
....Q...
Q.......
.....Q.."]

p f["...Q.
Q....
.Q...
....Q
..Q.."]

p f["Q.
Q."]

p f["..Q
...
.Q."]

p f["..Q.
Q...
...Q
.Q.."]

p f["Q"]
Level River St
fuente
2

Python 3 , 232 200 155 bytes

d=1
f=input()
Q=[]
for i in f:d=[0,d][i.count('Q')==1];Q+=[(len(Q),i.index('Q'))]
print[0,d][sum(k[1]==i[1]or sum(k)==sum(i)for k in Q for i in Q)==len(Q)]

Pruébalo en línea!

-32 bytes gracias a @beaker notando un cambio en las especificaciones de entrada; He cambiado el idioma de Python 3 a 2, lo que me permite usarinput entrada como una matriz de cadenas o una matriz de matrices de caracteres.

-45 bytes gracias a @Leaky Nun

Hiperneutrino
fuente
Los requisitos de entrada se han relajado, si eso te ayuda.
vaso de precipitados el
@beaker Ok, gracias. Tomaré la entrada como una matriz de cadenas en su lugar. ¡Gracias por señalar eso!
HyperNeutrino
157 bytes
Leaky Nun
1

JavaScript (ES6), 115 bytes

a=>!a.some((b,i)=>b.some((q,j)=>q&&h[i]|v[j]|d[i+j]|e[i-j]|!(h[i]=v[j]=d[i+j]=e[i-j]=1))|!h[i],h=[],v=[],d=[],e=[])

Sin golf:

function queens(arr) {
    horiz = [];
    vert = [];
    diag = [];
    anti = [];
    for (i = 0; i < arr.length; i++) {
        for (j = 0; j < arr.length; j++) {
            if (arr[i][j]) { // if there is a queen...
                if (horiz[i]) return false; // not already on the same row
                if (vert[j]) return false; // or column
                if (diag[i + j]) return false; // or diagonal
                if (anti[i - j]) return false; // or antidiagonal
                horiz[i] = vert[j] = diag[i + j] = anti[i - j] = true; // mark it
            }
        }
        if (!horiz[i]) return false; // fail if no queen in this row
    }
    return true;
}
Neil
fuente
0

Ruby, 155 bytes

->x{(y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2}).zip(y.rotate).map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}.inject(:+)*2==(s=x.size)*~-s}

Esto es horrible de leer, así que tengo una versión un poco menos golfizada a continuación.

->x{
    (y=x.map{|r|(i=r.index ?Q)==r.rindex(?Q)?i:p or-2})
    .zip(y.rotate)
    .map.with_index{|n,i|n.max-n.min==1&&i<y.size-1?-2:n[0]}
    .inject(:+)*2==(s=x.size)*~-s
}

Este es el mismo código, pero con algunas líneas nuevas para separar lo que está sucediendo.

El código tself es una función lambda anónima que toma una matriz de cadenas ( x) en el formato["..Q", "Q..", ".Q."] .

La primera línea está asignando cada cadena al índice del carácter Q en esa cadena. Si no hay un carácter Q, se reemplaza por -2 1 . Este nuevo conjunto de índices se asigna a la variable y.

La siguiente línea comprime esta matriz de índices con un desplazamiento de sí mismo (girado). Esto da como resultado una serie de pares de índices consecutivos.

La siguiente línea es particularmente complicada. Atraviesa cada uno de los pares de índices y resta lo más pequeño de lo más grande. Si esto es 1 (y no estamos en el último par 2 ), entonces hay dos reinas que están en la misma diagonal y se inserta un valor de -2, de lo contrario se inserta el índice original de la reina en la cadena .

La última línea resume todos los índices para cada uno y verifica si es el número de triángulo para n-1, donde n es el ancho (o alto) del cuadrado.

1: -1 habría sido mi opción, pero es 1 aparte de 0, por lo que se metería con la comprobación de diagonales. Lo negativo de esto es importante hacer que la suma final sea incorrecta. Pensé en un número alto (con un solo dígito) como 9, pero no puedo estar seguro de que eso no resulte en una verificación incorrecta.
2: El tablero no se ajusta, mientras que la rotatefunción de matriz de Ruby sí, y si el último par es diferente en uno, no importa, eso no es una diagonal.

IMP1
fuente
0

PHP, 137 143 bytes

inspirado en la solución de Neil

for($n=1+strlen($s=$argv[1])**.5|0;($c=$s[$p])&&!(Q==$c&&$v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++);$p++);echo$n-1==count($a)&&!$c;

toma la entrada del primer argumento de la línea de comando; correr con -r. Requiere saltos de línea de un solo byte.
En realidad, puedes usar cualquier personaje excepto 0para el salto de línea.
imprime verdadero ( 1) o falso (cadena vacía).

Descompostura

for($n=1+strlen($s=$argv[1])**.5|0; // copy input to $s, $n=size+1 (for the linebreak)
    ($c=$s[$p])&&!(                 // loop through characters
        Q==$c&&                         // if queen: test and increment lines
            $v[$x=$p%$n]++|$h[$x=$p/$n]++|$d[$y-$x]++|$a[$y+$x]++
    );                                  // break if a line had been marked before
    $p++);
echo$n-1==count($a)             // print result: true for $n-1(=size) marks
    &&!$c;                      // and loop has finished
Titus
fuente
0

Python 3 , 185 176 175 172 171 bytes

lambda x,c=lambda x:x.count("Q")==1:all([*map(c,x+[[l[i]for l in x]for i in range(len(x[0]))])])*~any(map(lambda s:"Q%sQ"%(s*".")in"".join(x),[len(x[0]),len(x[0])-2]))==-1

Una función anónima que toma una lista de cadenas como entrada.

Python 2 , 175 bytes

lambda x:all([a.count("Q")==1for a in x]+[[l[i]for l in x].count("Q")==1for i in range(len(x[0]))]+[all(map(lambda s:"Q%sQ"%(s*".")not in"".join(x),[len(x[0]),len(x[0])-2]))])
Trelzevir
fuente