Resolver quebra-cabeças Hitori

21

Introdução

Escreva um solucionador para os quebra-cabeças Hitori usando menos bytes.

Desafio

Sua tarefa é escrever um solucionador para os quebra-cabeças lógicos Hitori (ひ と り, em japonês; o significado do nome do jogo é "Deixe-me em paz"). As regras são as seguintes:

  • Você é apresentado com uma grade de células n por n, cada célula contém um número inteiro entre 1 e n (inclusive).
  • Seu objetivo é garantir que nenhum número apareça mais de uma vez em cada linha e em cada coluna da grade, removendo números da grade especificada, sujeito à restrição indicada nas duas próximas regras,
  • Você não pode remover dois números de duas células adjacentes (horizontal ou verticalmente).
  • As células numeradas restantes devem estar todas conectadas umas às outras. Isso significa que quaisquer duas células numeradas restantes podem ser conectadas com uma curva composta apenas por segmentos que conectam números restantes adjacentes (horizontal ou verticalmente). (Obrigado a @ user202729 por apontar que isso está faltando)

Espero que as regras estejam claras agora. Se houver algo pouco claro sobre as regras, consulte a página da Wikipedia .

Casos de teste

As células das quais os números são removidos são representadas com 0s.

Input  ->  Output

4
2 2 2 4      0 2 0 4
1 4 2 3  ->  1 4 2 3
2 3 2 1      2 3 0 1
3 4 1 2      3 0 1 2

4
4 2 4 3      0 2 4 3
4 1 1 2  ->  4 1 0 2
3 1 2 1      3 0 2 1
4 3 1 3      0 3 1 0

5
1 5 3 1 2      1 5 3 0 2
5 4 1 3 4      5 0 1 3 4
3 4 3 1 5  ->  3 4 0 1 5
4 4 2 3 3      4 0 2 0 3
2 1 5 4 4      2 1 5 4 0

8
4 8 1 6 3 2 5 7      0 8 0 6 3 2 0 7
3 6 7 2 1 6 5 4      3 6 7 2 1 0 5 4
2 3 4 8 2 8 6 1      0 3 4 0 2 8 6 1
4 1 6 5 7 7 3 5  ->  4 1 0 5 7 0 3 0
7 2 3 1 8 5 1 2      7 0 3 0 8 5 1 2
3 5 6 7 3 1 8 4      0 5 6 7 0 1 8 0
6 4 2 3 5 4 7 8      6 0 2 3 5 4 7 8
8 7 1 4 2 3 5 6      8 7 1 4 0 3 0 6

9
8 6 5 6 8 1 2 2 9      8 0 5 6 0 1 2 0 9
5 6 2 4 1 7 9 8 3      5 6 2 4 1 7 9 8 3
5 8 2 5 9 9 8 2 6      0 8 0 5 0 9 0 2 0
9 5 6 6 4 3 8 4 1      9 5 6 0 4 3 8 0 1
1 1 6 3 9 9 5 6 2  ->  0 1 0 3 9 0 5 6 2
1 1 4 7 3 8 3 8 6      1 0 4 7 0 8 3 0 6
3 7 4 1 2 6 4 5 5      3 7 0 1 2 6 4 5 0
3 3 1 9 8 7 7 4 5      0 3 1 9 8 0 7 4 5
2 9 7 5 3 5 9 1 3      2 9 7 0 3 5 0 1 0 

Esses casos de teste são retirados de Concept Is Puzzles , PuzzleBooks , Concept Is Puzzles , Wikipedia e Youtube , respectivamente.

Especificações

  • Não precisa se preocupar com o tratamento de exceções.

  • Você pode assumir que a entrada é sempre um quebra-cabeça válido com uma solução exclusiva e pode tirar proveito disso ao escrever seu código.

  • Isso é , o menor número de bytes vence.

  • 4 <= n <= 9 (16 originalmente, alterado para 9 seguindo a sugestão de Stewie Griffin, também economiza alguns problemas de IO)

  • Você pode receber e fornecer saída através de qualquer formulário padrão e pode escolher o formato.

  • Algumas sugestões para o formato de saída são (mas você não está restrito a elas)

    • Saída da grade final
    • Saída da grade contendo todos os números removidos
    • Emita uma lista de coordenadas de uma das opções acima
  • Como de costume, as brechas padrão se aplicam aqui.


Relacionado (inspirado neste desafio): Verifique se todos os elementos de uma matriz estão conectados

Meu último desafio: extensão do jogo dos setes

Weijun Zhou
fonte
2
Sugiro que você exija tempo de execução determinístico ou que o maior caso de teste possa ser resolvido em não mais de 1 minuto (ou talvez mais / menos). Além disso, você diz 4 <= n <= 16, mas o maior caso de teste é para n=9. Sugiro que você publique um n=16caso de teste ou diga 4 <= n <= 9. Bom desafio pela maneira :)
Stewie Griffin
1
@StewieGriffin, que tal ter apenas um desafio de algoritmo mais rápido separado?
Jonathan Allan
@StewieGriffin Tentou adicionar um 16x16, mas ainda não estava pronto. Alterado para 9 agora.
Weijun Zhou 29/01
@JonathanAllan Como desejar.
Weijun Zhou 30/01
Re "Eu decido fazer uma alteração para ver se seria melhor": Definitivamente seria pior. Além disso, você não deve alterar um desafio já publicado.
precisa saber é o seguinte

Respostas:

3

Haskell , 374 bytes

import Data.Array;import Data.List;r=range;p=partition
c(e,f)=p(\(b,p)->any(==1)[(b-d)^2+(p-q)^2|(d,q)<-e])f
n#g=[s|(o,(e:f))<-[p((==0).(g!))$indices g],
 null.fst$c(o,o),null.snd$until(null.fst)c([e],f),
 s<-case[((l,c),d)|((l,c),h)<-assocs g,h>0,
 d<-[filter((==h).(g!))$r((l,c+1),(l,n))++r((l+1,c),(n,c))],d/=[]]
 of[]->[g];((c,d):_)->n#(g//[(c,0)])++n#(g//[(c,0)|c<-d])]

Experimente online!

Roman Czyborra
fonte
Obrigado. Muito impressionante. Pessoalmente, sou iniciante, mas também um grande fã de Haskell.
Weijun Zhou 03/02
tio.run/…
H.PWiz 7/02
1
O número acima era de muitos caracteres. Deixe um comentário ao lado. É apenas remover alguns espaços em branco
H.PWiz
2

APL (Dyalog Unicode) , SBCS de 133 bytes

{q←{⊢/4 2⍴⍵}⌺3 3g←⍵=⊂∪,⍵⋄⍵×~1⊃{((⌈/q b)⌈b<{2<≢∪0,,(⍵×⊢⌈⌈/∘q)⍣≡⍵×(⍴⍵)⍴1+⍳≢,⍵}¨~b∘⌈¨⊂⍤2∘.≡⍨⍳⍴b)(+/↑w<g×⌈.⌈⍨w×g)⌈w b←⍵}⍣≡×\(⌈/=∘⌽⍨q⍵)0}

Experimente online!

Minha implementação da regra nº 4 (as células devem formar um único componente conectado) é um desperdício, mas ainda assim é aprovada em todos os testes em cerca de 10 segundos no TIO.


O algoritmo geral: armazene duas matrizes booleanas be wpara células que certamente serão preto e branco, respectivamente. Inicialize bcomo zero. Inicialize wcomo 1 apenas para as células que possuem vizinhos correspondentes opostos.

Repita até be wse acalme:

  • adicione às bcélulas que estão na mesma linha (horizontal ou vertical) e com o mesmo valor que uma célula emw

  • adicionar aos wvizinhos imediatos de todas as células emb

  • adicionar a wtodos os pontos de corte - células cuja remoção dividiria o gráfico de células não pretas em vários componentes conectados

Por fim, o resultado not(b)multiplicado pela matriz original.

ngn
fonte
Muito obrigado pelo seu interesse e explicação. Acho que o que você descreveu também é um algoritmo típico usado para resolver o quebra-cabeça manualmente.
Weijun Zhou 08/02
1
Para ser sincero, nunca tentei resolver o Hitori manualmente. Eu peguei esses truques da Wikipedia e não tenho provas de que o algoritmo sempre convergiria até a solução (única).
NGN
2

Geléia , 62 bytes

Usa o link monádico isConnected de user202729 de outra pergunta.


FJṁa@µ«Ḋoµ€ZUµ4¡ÐLFQL<3
ḟ0ĠḊ€
¬T€œ&2\;Ç€FȦ
ZÇȯÇ_1Ŀ
2ḶṗLṗLa⁸ÇÞḢ

Um programa completo que imprime uma representação de uma lista de listas.
Funciona com força bruta e é estupidamente ineficiente.

Experimente online! - 3 por 3, uma vez que é muito ineficiente para executar até um tamanho 4 dentro do limite de TIO de 60 segundos!

Quão?

FJṁa@µ«Ḋoµ€ZUµ4¡ÐLFQL<3 - Link 1 isConnected? List of lists
...                     - 1 if connected 0 if not -- see linked answer in the header

ḟ0ĠḊ€ - Link 2, helperFor-AnyRepeatedValues: list
ḟ0    - filter out zeros
  Ġ   - group indices by value (i.e. [[indices of min],...,[indices of max]]
   Ḋ€ - dequeue €ach -- leaving a list of empty lists iff no repeated values
      -                 any remaining values are non-zero (1-based indexing in Jelly)

¬T€œ&2\;Ç€FȦ - Link 3, columnwiseAnyAdjacentZerosOrRowwiseAnyRepeatedValues: list of lists
¬            - logical not (convert all zeros to ones and all others to zeros)
 T€          - for €ach row get a list of truthy indexes (i.e. indexes of original zeros)
     2\      - pairwise reduction (i.e. for neighbouring rows) with:
   œ&        -   intersection (empty if no columnwise adjacent original zeros
             -                 any remaining values are non-zero due to 1-based indexing)
        Ç€   - call last link (1) as a monad for €ach row
       ;     - concatenate
          F  - flatten into a single list (empty iff no columnwise adjacent original zeros
             -                                   AND no rowwise repeated values)
           Ȧ - any and all (0 if empty [or contains any zero -- never] else 1)

ZÇȯÇ_1Ŀ - Link 4, validity check? list of lists
Z       - transpose
 Ç      - call last link (2) as a monad rowwiseAnyAdjacentZerosOrColumnwiseAnyRepeatedValues?
   Ç    - call last link (2) as a monad columnwiseAnyAdjacentZerosOrRowwiseAnyRepeatedValues?
  ȯ     - logical OR
     1Ŀ - call link 1 as a monad (isConnected?)
    _   - subtract
        - this yields -1 for valid, while it yields 0 or 1 if not.

2ḶṗLṗLa⁸ÇÞḢ - Main link: list of lists
2Ḷ          - lowered range of 2 -> [0,1]
   L        - length (number of rows in the input)
  ṗ         - Cartesian power (all lists of zeros and ones of length L)
     L      - length (number of rows in the input again)
    ṗ       - Cartesian power (all grids of zeros and ones of same shape as the input)
       ⁸    - the input
      a     - logical AND -- effectively uses each of the formed grids as a mask
         Þ  - sort by:
        Ç   -   last link (3) as a monad
          Ḣ - head
            - implicit print
Jonathan Allan
fonte
Bom como um começo. Obrigado. Eu vou dar uma olhada.
Weijun Zhou
Você esqueceu a quarta regra. (conectado)
user202729
(boa sorte com a implementação de BFS / DFS / DSU no Jelly)
user202729
Ah ... excluirá quando estiver no computador. Obrigado.
Jonathan Allan
sim, eu não acho que isso é possível, digamos, <60 bytes de Jelly, para não dizer <100 ...
Erik o Outgolfer