É hora de embarcar em uma perigosa busca para derrotar a Inteligência Britânica. O objetivo deste desafio é escrever o código mais curto que resolverá um Nonograma.
O que é um nonograma?
As regras são simples. Você tem uma grade de quadrados, que deve ser preenchida em preto ou deixada em branco. Ao lado de cada linha da grade, estão listados os comprimentos das séries de quadrados pretos nessa linha. Acima de cada coluna, estão listados os comprimentos das execuções de quadrados pretos nessa coluna. Seu objetivo é encontrar todos os quadrados pretos. Nesse tipo de quebra-cabeça, os números são uma forma de tomografia discreta que mede quantas linhas ininterruptas de quadrados preenchidos existem em qualquer linha ou coluna. Por exemplo, uma pista de "4 8 3" significaria que há conjuntos de quatro, oito e três quadrados preenchidos, nessa ordem, com pelo menos um quadrado em branco entre grupos sucessivos. [ 1 ] [ 2 ]
Portanto, a solução para o Nonogram acima seria:
Detalhes da implementação
Você pode representar o Nonograma da maneira que desejar e tomá-lo como entrada da maneira que julgar adequada ao seu idioma. O mesmo vale para a saída. O objetivo desse desafio é literalmente fazer o trabalho; se você puder resolver o nonograma com qualquer saída que seu programa der, isso é válido. Uma ressalva é que você não pode usar um solucionador on-line :)
Esse problema é desafiador por algoritmos (np-complete), pois não existe uma solução completamente eficiente e, como tal, você não será penalizado por não conseguir resolver os maiores, embora sua resposta seja altamente recompensada se for capaz de lidar com casos grandes (ver bônus). Como referência, minha solução funciona em aproximadamente 25x25 em 5 a 10 segundos. Para permitir flexibilidade entre idiomas diferentes, as soluções que levam menos de 5 minutos para um nonograma de 25x25 são boas o suficiente.
Você pode assumir um quebra-cabeça em um nonograma quadrado NxN.
Você pode usar este criador de quebra-cabeças sem programa on - line para testar suas soluções.
Pontuação
Você é livre para usar qualquer idioma que desejar e, como se trata de código de golfe, as entradas serão classificadas na ordem: accuracy -> length of code -> speed.
No entanto, não desanime com idiomas de código de golfe, respostas em todos os idiomas que mostram tentativas de golfe de uma maneira interessante será votado!
Bônus
Na verdade, eu aprendi sobre os Nonogramas a partir de um cartão de Natal criptográfico lançado pela Inteligência Britânica aqui . A primeira parte foi basicamente um Nonogram enorme de 25x25. Se sua solução for capaz de resolver isso, você receberá elogios :)
Para facilitar sua vida em termos de entrada de dados, forneci como eu representava os dados desse quebra-cabeça específico para seu uso gratuito. As primeiras 25 linhas são as pistas da linha, seguidas por uma linha separadora '-', seguidas por 25 linhas das pistas col, seguidas por uma linha separadora '#' e, em seguida, uma representação da grade com as pistas quadradas preenchidas.
7 3 1 1 7
1 1 2 2 1 1
1 3 1 3 1 1 3 1
1 3 1 1 6 1 3 1
1 3 1 5 2 1 3 1
1 1 2 1 1
7 1 1 1 1 1 7
3 3
1 2 3 1 1 3 1 1 2
1 1 3 2 1 1
4 1 4 2 1 2
1 1 1 1 1 4 1 3
2 1 1 1 2 5
3 2 2 6 3 1
1 9 1 1 2 1
2 1 2 2 3 1
3 1 1 1 1 5 1
1 2 2 5
7 1 2 1 1 1 3
1 1 2 1 2 2 1
1 3 1 4 5 1
1 3 1 3 10 2
1 3 1 1 6 6
1 1 2 1 1 2
7 2 1 2 5
-
7 2 1 1 7
1 1 2 2 1 1
1 3 1 3 1 3 1 3 1
1 3 1 1 5 1 3 1
1 3 1 1 4 1 3 1
1 1 1 2 1 1
7 1 1 1 1 1 7
1 1 3
2 1 2 1 8 2 1
2 2 1 2 1 1 1 2
1 7 3 2 1
1 2 3 1 1 1 1 1
4 1 1 2 6
3 3 1 1 1 3 1
1 2 5 2 2
2 2 1 1 1 1 1 2 1
1 3 3 2 1 8 1
6 2 1
7 1 4 1 1 3
1 1 1 1 4
1 3 1 3 7 1
1 3 1 1 1 2 1 1 4
1 3 1 4 3 3
1 1 2 2 2 6 1
7 1 3 2 1 1
#
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
E aqui está uma versão ligeiramente diferente para sua conveniência; uma tupla separada por vírgula (linha, col), em que cada elemento é uma lista de listas.
([[7, 3, 1, 1, 7],
[1, 1, 2, 2, 1, 1],
[1, 3, 1, 3, 1, 1, 3, 1],
[1, 3, 1, 1, 6, 1, 3, 1],
[1, 3, 1, 5, 2, 1, 3, 1],
[1, 1, 2, 1, 1],
[7, 1, 1, 1, 1, 1, 7],
[3, 3],
[1, 2, 3, 1, 1, 3, 1, 1, 2],
[1, 1, 3, 2, 1, 1],
[4, 1, 4, 2, 1, 2],
[1, 1, 1, 1, 1, 4, 1, 3],
[2, 1, 1, 1, 2, 5],
[3, 2, 2, 6, 3, 1],
[1, 9, 1, 1, 2, 1],
[2, 1, 2, 2, 3, 1],
[3, 1, 1, 1, 1, 5, 1],
[1, 2, 2, 5],
[7, 1, 2, 1, 1, 1, 3],
[1, 1, 2, 1, 2, 2, 1],
[1, 3, 1, 4, 5, 1],
[1, 3, 1, 3, 10, 2],
[1, 3, 1, 1, 6, 6],
[1, 1, 2, 1, 1, 2],
[7, 2, 1, 2, 5]],
[[7, 2, 1, 1, 7],
[1, 1, 2, 2, 1, 1],
[1, 3, 1, 3, 1, 3, 1, 3, 1],
[1, 3, 1, 1, 5, 1, 3, 1],
[1, 3, 1, 1, 4, 1, 3, 1],
[1, 1, 1, 2, 1, 1],
[7, 1, 1, 1, 1, 1, 7],
[1, 1, 3],
[2, 1, 2, 1, 8, 2, 1],
[2, 2, 1, 2, 1, 1, 1, 2],
[1, 7, 3, 2, 1],
[1, 2, 3, 1, 1, 1, 1, 1],
[4, 1, 1, 2, 6],
[3, 3, 1, 1, 1, 3, 1],
[1, 2, 5, 2, 2],
[2, 2, 1, 1, 1, 1, 1, 2, 1],
[1, 3, 3, 2, 1, 8, 1],
[6, 2, 1],
[7, 1, 4, 1, 1, 3],
[1, 1, 1, 1, 4],
[1, 3, 1, 3, 7, 1],
[1, 3, 1, 1, 1, 2, 1, 1, 4],
[1, 3, 1, 4, 3, 3],
[1, 1, 2, 2, 2, 6, 1],
[7, 1, 3, 2, 1, 1]])
fonte
s=[].fill([].fill(0,0,25),0,25);s[3][3]=s[3][4]=s3[3][12]=s3[3][13]=s3[3][21]=s[8][6]=s[8][7]=s[8][10]=s[8][14]=s[8][15]=s[8][18]=s[16][6]=s[16][11]=s[16][16]=s[16][20]=s[21][3]=s[21][4]=s[21][9]=s[21][10]=s[21][15]=s[21][20]=s[21][21]=1;
Respostas:
Braquilog ,
7069 bytesIsso leva uma lista de duas listas (primeiro os indicadores de linhas, depois os da coluna). Cada indicador é ele próprio uma lista (para sessões como
[3,1]
em uma linha).Esta versão leva cerca de 3 minutos para resolver o exemplo 5 por 5 do desafio.
Versão muito mais eficiente, 91 bytes
Experimente online!
Essa não é uma força bruta completa: a única diferença é que ela impõe restrições aos valores das células, de modo que o número de 1s em cada linha e coluna corresponda aos números dados como indicadores na entrada. A única parte da força bruta é encontrar a grade com as restrições para as quais os "blocos" de 1s correspondem ao que é dado como indicação.
Este leva cerca de 0,05 segundos no exemplo 5 por 5 do desafio. Isso ainda é muito lento para o caso de bônus, pois não tenho idéia de como expressar os blocos de unidades separados por um ou mais zeros em termos de restrições.
Explicação
Vou explicar abaixo a versão de 93 bytes. A única diferença entre os dois é a chamada para o predicado 3, que não existe na versão de 70 bytes, e a numeração dos predicados (já que há um a menos).
Predicado principal:
Predicado 1: força as linhas a terem um comprimento específico e que cada célula seja 0 ou 1.
Predicado 2: restrinja uma variável a ser 0 ou 1
Predicado 3: A soma de 1s em uma lista deve ser igual à soma dos indicadores (por exemplo, se o indicador for [3: 1], a lista deve ter a soma 4)
Predicado 4: verifique se os blocos de 1s correspondem ao indicador
Predicado 5: verdadeiro para blocos de 1s, falso caso contrário
fonte
Haskell,
242 230 201 199 177 163 160 160 149131 bytesFinalmente, com menos de 200 bytes, credite para @Bergi. Muito obrigado a @nimi por ajudar quase a reduzir o tamanho pela metade.
Uau. Quase com metade do tamanho agora, em parte por minha causa, mas principalmente por causa do @nimi.
A função mágica é
(#)
. Encontra todas as soluções de um dado nonograma.Isso é capaz de resolver todos os casos, mas pode ser super lento, já que é uma questão de complexidade
O(2^(len a * len b))
. Um benchmark rápido revelou 86 GB alocados para um nonograma 5x5.Curiosidade: funciona para todos os nonogramas, não apenas os quadrados.
Como funciona:
a#b
: Dadas as listas de listas de números inteiros que representam o número de quadrados, gere todas as grades (map(chunk$length b).mapM id$a>>b>>[[0,1]]
) e filtre os resultados para manter apenas os válidos.g
: Dado um nonogram potencial, soma as execuções de 1s horizontalmente.fonte
m(chunk$l b)
ereplicate(l$a>>b)
import Data.Lists
é suficiente, porque reexporta ambosData.List
eData.List.Split
.Pitão,
917271 bytesUm programa que recebe a entrada de uma lista do formulário em
[size, [horizontal clues], [vertical clues]]
que cada pista é uma lista de números inteiros (pistas vazias são a lista vazia,[]
), e imprime a cada solução, nova linha separada, sob a forma de uma grade de binário, onde1
é protegido e0
é não sombreado .Esta é uma força bruta, por isso é aproximadamente
O(2^n^2)
. Começa a demorar muito tempo para quebra-cabeças maiores, mas resolve qualquer tamanho arbitrário, desde que haja tempo suficiente.Experimente online
Como funciona
O programa gera todos os layouts possíveis, utilizando o produto cartesiano repetido
[0, 1]
com um comprimento igual asize^2
. Isso é dividido em pedaços, fornecendo uma lista para cada linha horizontal. Cada linha é codificada no comprimento da execução, filtrada pela presença1
e achatada, deixando a pista para essa linha. Isso é verificado contra a entrada. O processo acima é repetido para a transposição dos pedaços, verificando as linhas verticais. Se houver uma ocorrência, cada parte é concatenada e as partes concatenadas são unidas em novas linhas e impressas implicitamente, com uma nova linha à direita.Obrigado a @ Pietu1998 por algumas dicas
fonte
=ZhZ
é igual a=hZ
, eFN
é igual aV
.Javascript (ES6),
401386333 bytesEsta é uma tentativa inicial. Não é muito eficiente, mas estava curioso para testar uma solução usando expressões regulares na representação binária das linhas e colunas.
Por exemplo, ele traduzirá a pista
[3,1]
na seguinte expressão regular:No momento, esta versão não está levando em consideração pistas quadradas. Provavelmente vou adicionar isso mais tarde.
Código
Saída
A solução é exibida em formato binário. Tal como:
Teste
Este é um teste simples na grade de exemplo.
fonte
Haskell, 109 bytes
Isenção de responsabilidade: isso é derivado da resposta da @ ThreeFx . Ajudei-o a jogar sua resposta, mas ele parece ter perdido o interesse de incluir minhas últimas melhorias substanciais, então as coloco como nova resposta.
Exemplo de uso:
[[2],[3],[3],[3,1],[1]] # [[2],[3],[4],[2],[2]]
->[[" ## "," ### ","### ","### #"," #"]]
.Força bruta. Tente todas as combinações de
e
#
, divida os pedaços de int#
, conte os comprimentos e compare com a entrada.fonte
PHP,
751833 (720)753724726710691680682 bytesEu estava ansioso para construir um incremento de sequência especializado e experimentar meu gerador cartesiano mais uma vez;
mas abandonou o cartesiano em favor do retrocesso para resolver o quebra-cabeça grande mais rapidamente.
$r
para dicas de linha, dicas$c
de coluna e$s
dicas quadradas.invalid argument supplied for foreach
se não encontrar solução.\n
e remova as outras duas quebras de linha.descrição
1) das dicas de linha
geram possíveis linhas que satisfazem as dicas quadradas
e lembram suas contagens para cada índice de linha.
2) retroceder nas combinações de linhas:
se a combinação atender às dicas da coluna, procure uma combinação mais profunda ou retorne com êxito,
mais tente a próxima possibilidade para esta linha
3) solução de impressão
O último golfe teve um impacto severo no desempenho;
mas removi as atribuições de criação de perfil para os benchmarks finais.
Substitua
$n=$n*($f=($p[$y][$i[$y]]>>$x&1)==$v)+$k=$f?:($v=!$v)||$n==$h[$z++];
por
if(($p[$y][$i[$y]]>>$x&1)-$v){$k=($v=!$v)||$n==$h[$z++];$n=1;}else$n++;
para desfazer a última etapa do golfe.
exemplos
Para o pequeno exemplo (
17 a 21 emtorno de12876,75,3 ms), usepara o quebra-cabeça de natal:
5037,845,5 emtorno de 36 segundoscoloque os dados da pergunta em um arquivo
christmas.nonogram
e use este código para importar:demolir
fonte
$d
tem que estar na ordem correta paraforeach