Verifique o quebra-cabeça rainhas


16

Se você não sabe o que é uma rainha no xadrez, isso não importa muito; é apenas um nome :)

Sua entrada será um quadrado de largura e altura arbitrárias contendo alguma quantidade de rainhas. A placa de entrada ficará assim (esta placa possui largura e altura de 8):

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

Existem 8 rainhas neste fórum. Se houvesse, digamos, 7, 1 ou 10 aqui, o quadro não seria válido.

Aqui usamos a .para um espaço vazio e umQ para uma rainha. Como alternativa, você pode usar qualquer caractere que não seja de espaço em branco que desejar.

Essa entrada pode ser verificada como válida e você deve imprimir (ou retornar) um valor verdadeiro (se não for válido, deve imprimir (ou retornar) um valor falso). É válido porque nenhuma dama está na mesma linha, coluna, diagonal ou anti-diagonal que outra .

Exemplos (não exiba itens entre colchetes):

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

Deixe-me enfatizar que uma entrada é válida apenas se nenhuma rainha estiver na mesma linha, coluna, diagonal ou anti-diagonal que outra .

Regras

  • Você nunca receberá uma entrada vazia
  • Se a entrada contiver menos rainhas que a raiz quadrada da área da placa, ela não será válida.
  • Observe que não há soluções válidas para uma placa 2x2 ou 3x3, mas existe uma solução para todos os outros tamanhos quadrados placas , em que a largura e a altura são um número natural.
  • A entrada pode estar em qualquer formato razoável, de acordo com as regras do PPCG
  • A entrada será sempre um quadrado
  • Usei 1 e 0 nos exemplos, mas você pode usar valores de verdade ou falsidade (como Why yes, sir, that is indeed the casee Why no, sir, that is not the case)

Como se trata de , o código mais curto vence!



1
Será que {(x, y, v)}com vem [., Q]ser um formato de entrada válido?
precisa saber é o seguinte

@DuctrTape Eu não acho que faz muito sentido.
Okx 9/03/17

2
@Okx Em outras palavras, eles estão perguntando sobre o recebimento de uma lista de coordenadas e valores como entrada. Por exemplo: (0, 0, Q), (0, 1, .), (1, 0, Q), (1, 1, .)seria o terceiro caso de teste.
Mego

Posso pegar uma string sem quebras de linha?
Titus

Respostas:


7

Caracóis , 14 bytes

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

Experimente online!

Nada como uma linguagem de correspondência de padrões 2D para um problema de decisão 2D. :)

Explicação

A &primeira linha é uma opção de modo de correspondência que requer que o padrão na segunda linha corresponda de todas as posições possíveis na entrada. Se for esse o caso, o programa será impresso 1, caso contrário, será impresso 0.

Quanto ao próprio padrão, observe que há um implícito )no 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.
)

Por que isso funciona é mais fácil de ver, começando pela cabeça negativa: garantindo que não haja Quma linha reta da outra Qque já encontramos, garantimos que não haja mais que N rainhas (caso contrário, haveria ser duas em uma linha e não seria possível encontrar essas rainhas sem encontrar outra). Então a primeira parte, certificando-se de que há uma rainha alcançável em uma direção ortogonal a partir de qualquer posição, garante que haja exatamente N rainhas. Se alguém estivesse faltando, haveria uma linha e uma coluna sem uma rainha. A partir da interseção destes, não seria possível encontrar uma rainha indo apenas em uma direção ortogonal.


6

Gelatina , 17 ou 15 bytes

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

Experimente online!

Usa para uma rainha e ¹para espaço em branco. (Isso é principalmente uma conseqüência da proibição de receber entrada como uma matriz, porque força a entrada a ser cadeias; converter cadeias em números inteiros é difícil no Jelly, com o método mais fácil sendo a avaliação, e acontece que, em vez de 1 e 0, usando "add 1" ( ) e "add 0" ( ¹) torna possível omitir várias instruções de soma e mapa, porque podemos contar as rainhas em uma lista avaliando-a.) Os valores truthy e falsey são os valores normais de Jelly 1e0 .

EDIT: A pergunta foi alterada desde que escrevi esta resposta para permitir a entrada de dados como uma matriz. Isso permite eliminar os principais Ỵµ, economizando 2 bytes. Provavelmente também permite alterar o formato de entrada para algo mais normal, usando Ssomar e não Vavaliar, mas não acho que isso economize bytes e eu meio que gosto desse formato descolado.

Explicação

Ỵµ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.

Portanto, a ideia básica é garantir que haja no máximo uma rainha em cada antidiagonal, diagonal e coluna; e exatamente uma rainha em cada linha. Essas condições estão juntas o suficiente para exigir que haja no máximo uma rainha em cada um dos quatro tipos de linha e um número de rainhas iguais ao comprimento lateral do tabuleiro.

Aliás, Jelly provavelmente poderia fazer com um antidiagonais embutido, mas o AFAICT não parece ter um, então eu preciso me contentar em refletir o quadro e depois tirar as diagonais.

Outra observação interessante é que mudar =1Ṃpara E(todos iguais) fornece um verificador n- rainhas generalizado , que também aceita um quadro n × n em que cada linha, coluna, diagonal e antidiagonal não contém mais que k rainhas, e o quadro contém exatamente kn queens. Restringir k para igual a 1 realmente custa dois bytes.


As regras foram atualizadas, agora "A entrada pode estar em qualquer formato razoável, de acordo com as regras do PPCG", que deve abreviar :) EDIT - Vejo que você anotou.
Jonathan Allan

5

Oitava, 57 70 67 51 52 bytes

Economizou 1 byte usando em flipvez de rot90agradecer a @LuisMendo, mas encontrou um bug no gabinete 1x1

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

Recebe a entrada como uma matriz binária, com 1 representando uma rainha e 0 representando um espaço vazio.

Cria uma função anônima que concatena primeiro a matriz de entrada e sua transposição.

spdiagscria uma matriz com o mesmo número de linhas que o argumento, com as diagonais transformadas em colunas (preenchidas com zero, conforme necessário), para concatenar spdiagsa matriz de entrada para obter as diagonais e spdiagsa matriz invertida horizontalmente para obter as antidiagonais.

Agora pegue a soma de cada coluna da matriz concatenada e verifique se cada coluna é exatamente 1.

Amostra executada em ideone .


Eu acho que você pode usar em flipvez derot90
Luis Mendo

@LuisMendo Sim, isso também funcionará. Obrigado!
copo

Além disso, você não pode evitar all()?
Luis Mendo

@LuisMendo Ugh ... provavelmente ... mas vai ter que esperar até depois do jantar;)
beaker

4

MATL , 38 34 bytes

4 bytes de desconto graças a @beaker !

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

A entrada é uma matriz 2D de zeros e uns, usando ponto-e-vírgula como separadores de linha.

Isso gera um vetor de coluna uns como verdade e um vetor de coluna contendo pelo menos um zero como falso.

Experimente online!O código do rodapé é um iframo para demonstrar a veracidade ou falsidade.

Ou verifique todos os casos de teste .

Explicação

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

Você pode salvar 2 bytes agora que pode usar uma matriz binária como entrada.
copo

2

J , 37 bytes

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

Trem de funções anônimas que usa a matriz booleana como argumento.

Experimente online!

( +/a soma &do ,percurso =é igual #à contagem de linhas)

* e (lit. vezes)

1um =é igual [:ao >./máximo de

+/as somas na /.diagonal ,e (lit. catenadas para)

+/as somas na /.diagonal &do |.reverso ,e

+/as somas ,e

+/as somas &da |:transposição


2

SnakeEx , 67 bytes

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

Usos _ no lugar de .na entrada. Retorna 1 ou mais correspondências para truthy, 0 correspondências para falsey. Você pode encontrar um intérprete online no link no cabeçalho.

Explicação

SnakeEx é um idioma do desafio de Correspondência de Padrão 2-D . Ele define "cobras" que se movem ao redor do material correspondente à grade. Cobras podem gerar outras cobras, tornando a linguagem bastante poderosa.

Vamos olhar para este programa de baixo para cima.

n:_+$

Isso define uma cobra nque corresponde a 1 ou mais sublinhados e depois à borda da grade. Observe que isso pode estar em qualquer uma das oito direções cardeais - a direção é determinada quando a cobra é gerada.

q:_*Q_*$

Semelhante ao nacima, isso define qcomo uma cobra que corresponde a qualquer número de sublinhados, um único Q, qualquer número de sublinhados e a borda da grade. Em outras palavras, uma linha / coluna / diagonal que tem apenas uma rainha nela.

e:.$

e é uma cobra que corresponde a um caractere e a borda da grade.

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

A cobra principal m usa esses blocos de construção para verificar o tabuleiro inteiro. Conceitualmente, ele percorre as bordas externas da grade, gerando outras cobras para verificar se todas as colunas e linhas têm exatamente uma rainha e todas as diagonais têm no máximo uma rainha. Se alguma das cobras reproduzidas não corresponder, a correspondência inteira falhará. Vamos dividir.

  • ( )%{4}executa o que está dentro dos parênteses 4 vezes, uma vez para cada lado. (A seguir, é útil imaginar um lado em particular - digamos, a borda superior da grade, começando no canto superior esquerdo e movendo-se para a direita.)
  • {q<>}cria uma qcobra na mesma direção em que a cobra principal está se movendo. Isso verifica se a borda atual atende à regra "exatamente uma dama". Observe que as cobras reproduzidas não movem o ponteiro da partida da serpente principal, portanto ainda estamos no início da borda.
  • ( )* corresponde a 0 ou mais do que está entre parênteses.
  • {q<R>}cria uma qcobra virada para a direita na direção da cobra principal. (Por exemplo, se a cobra principal estiver se movendo para a direita ao longo da borda superior, ela se moverá para baixo.) Isso verifica cada coluna / linha.
  • [ ] corresponde a uma das opções dentro dos colchetes:
    • {q<RF>}cria uma qcobra virada 45 graus para a direita (isto é, para a direita Re para a frente F) na direção da cobra principal. A qcobra combina se a diagonal contiver exatamente uma rainha.
    • {n<RF>}gera uma ncobra em seu lugar. A ncobra combina se a diagonal não contiver rainhas.
  • . corresponde a qualquer caractere, movendo o ponteiro da correspondência para frente.
  • Depois de verificar o maior número possível de horizontais e diagonais, verificamos que estamos no limite ao gerar {e<>}.
  • Finalmente, <R>vira a serpente principal para a direita, pronta para corresponder à próxima aresta.

Coisa estranha

  • Não há nada no programa para garantir que a correspondência comece em um canto externo. De fato, os casos de teste verdadeiros produzem várias correspondências, algumas das quais começam por dentro em algum lugar. Apesar disso, nenhum dos casos falsey que eu tentei gerou nenhum falso positivo.
  • Se estou lendo as especificações de idioma corretamente, eu deveria ter sido capaz de usar X(ramificar em todas as direções diagonais) no lugar de RF. Infelizmente, o intérprete on-line disse que foi um erro de sintaxe. Eu também tentei *(ramifique em todas as direções), mas isso impediu o intérprete.
  • Teoricamente, algo como _*Q?_*$deveria funcionar para combinar "no máximo uma rainha" nas diagonais, mas isso também pendia do intérprete. Meu palpite é que a possibilidade de correspondências vazias causa problemas.

2

Ruby, 120 bytes

Função Lambda baseada na especificação original que exigia entrada como uma sequência.

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

converte os Q's em números complexos e os subtrai um do outro. Se a diferença entre as coordenadas de duas rainhas for horizontal, vertical ou diagonal, elevá-la para a quarta potência resultará em um número real e o arranjo será inválido.

Ungolfed in program program

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

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

Experimente online!

-32 bytes graças ao @beaker notando uma alteração nas especificações de entrada; Mudei a linguagem de Python 3 para 2, permitindo que eu usasseinput a entrada como uma matriz de seqüências de caracteres ou uma matriz de matrizes de caracteres.

-45 bytes graças a @Leaky Nun


Os requisitos de entrada foram relaxados, se isso ajudar você.
copo

@beaker Ok, obrigado. Aceitarei a entrada como uma matriz de seqüências de caracteres. Obrigado por apontar isso!
HyperNeutrino


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

Ungolfed:

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

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}

Isso é horrível de ler, então eu tenho uma versão um pouco menos golfe abaixo

->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 é o mesmo código, mas com algumas linhas novas para separar o que está acontecendo.

O próprio código é uma função lambda anônima que recebe uma matriz de strings ( x) no formato ["..Q", "Q..", ".Q."].

A primeira linha está mapeando cada sequência para o índice do caractere Q nessa sequência. Se não houver um caractere Q, ele será substituído por -2 1 . Esta nova série de índices é atribuído à variável y.

A próxima linha fecha esse conjunto de índices com um deslocamento (rotacionado). Isso resulta em uma matriz de pares de índices consecutivos.

A próxima linha é particularmente complicada. Ele percorre cada um dos pares de índices e subtrai o menor do maior. Se for 1 (e não estamos no último par 2) ), existem duas rainhas que estão na mesma diagonal e um valor de -2 é inserido; caso contrário, o índice original da rainha na sequência é inserido .

A última linha resume todos os índices de cada um e verifica se é o número do triângulo para n-1, onde n é a largura (ou altura) do quadrado.

1: -1 teria sido o meu objetivo, mas é 1 além de 0, por isso mexeria com a verificação das diagonais. A negatividade é importante para fazer a soma final errada. Pensei em um número alto (com um dígito) como 9, mas não tenho certeza se isso não resultará em uma verificação incorreta.
2: O tabuleiro não quebra, enquanto a rotatefunção de array do ruby , e se o último par é diferente de um, não importa - isso não é uma diagonal.


0

PHP, 137 143 bytes

inspirado na solução 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;

recebe entrada do primeiro argumento da linha de comando; corra com -r. Requer quebras de linha de byte único.
Na verdade, você pode usar qualquer caractere, exceto 0para a quebra de linha.
imprime true ( 1) ou false (string vazia).

demolir

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

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

Uma função anônima que recebe uma lista de seqüências de caracteres 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]))])
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.