Vencedor encontrado
Parece que temos um vencedor! A menos que alguém planeje contestar o atual solucionador de Sudoku mais rápido do mundo, o usuário 53x15 vence com o solucionador incrivelmente rápido do Tdoku. Para quem ainda trabalha em seus solucionadores, ainda compararei novos envios quando tiver tempo.
O desafio
O objetivo de um jogo de Sudoku é preencher o tabuleiro com os números de 1 a 9, um em cada célula, de modo que cada linha, coluna e caixa contenha apenas cada número uma vez. Um aspecto muito importante de um quebra-cabeça Sudoku é que deve haver apenas uma solução válida.
O objetivo deste desafio é simples, você deve resolver um conjunto de quebra-cabeças de Sudoku o mais rápido possível. No entanto, você não estará apenas resolvendo qualquer Sudoku antigo, mas também os mais difíceis enigmas de Sudoku existentes, o Sudokus de 17 pistas. Aqui está um exemplo:
Regras
Língua
Você é livre para usar qualquer idioma. Se eu não tiver um compilador instalado para o seu idioma, você poderá fornecer um conjunto de instruções da linha de comando necessárias para instalar um ambiente em que seu script possa ser executado no Linux .
Máquina de referência
O benchmark será executado em um Dell XPS 9560, Intel Core i7-7700HQ de 2,8 GHz (aumento de 3,8 GHz), 4 núcleos, 8 threads e 16 GB de RAM. GTX 1050 4GB. A máquina executa o Ubuntu 19.04. Aqui está a uname
saída, para qualquer pessoa interessada.
Linux 5.0.0-25-generic #26-Ubuntu SMP Thu Aug 1 12:04:58 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Entrada
A entrada será fornecida como um arquivo. Pode ser encontrado aqui . O arquivo contém 49151 quebra-cabeças de Sudoku. A primeira linha do arquivo é o número de quebra-cabeças, e cada linha a seguir tem 81 caracteres e representa um quebra-cabeça. As células desconhecidas são 0
e as células conhecidas são 1-9
.
Seu programa deve poder usar o nome do arquivo como argumento ou receber a entrada de arquivo do STDIN , para facilitar a verificação manual da sua solução. Por favor, inclua uma instrução sobre como o seu programa recebe informações.
Tempo / pontuação
A partir das discussões nos comentários e de algumas reflexões, os critérios de pontuação foram alterados para serem o tempo de todo o programa. Seu programa deve produzir o arquivo de saída com o hash correto, mesmo durante a pontuação oficial. Isso não interfere em nenhuma solução existente e não altera as classificações como estão agora. Quaisquer pensamentos sobre o sistema de pontuação são bem-vindos.
Se duas soluções tiverem pontuações semelhantes para execuções individuais, executarei vários benchmarks e o tempo médio será a pontuação final. Se a pontuação média diferir em menos de 2%, considerarei um empate.
Se a sua solução demorar mais de uma hora para ser executada, ela não será classificada oficialmente. Nesses casos, você é responsável por relatar a máquina em que foi executada e sua pontuação. Para um solucionador otimizado, isso não deve ser um problema.
EDIT : Fui informado de que, embora difícil, o problema em questão não é o mais difícil que existe. Se houver tempo disponível, tentarei comparar as soluções apresentadas aqui com o conjunto de quebra-cabeças mais difícil e adicionar a pontuação a cada envio. No entanto, isso não será uma pontuação oficial e é apenas por diversão.
Verificação
Sua solução será verificada por uma soma de verificação MD5 / SHA256. Seu script deve ser capaz de gerar um arquivo contendo todos os quebra-cabeças e suas soluções. No entanto, o arquivo também será inspecionado manualmente, portanto, não tente obter uma colisão de hash. Seu arquivo de saída deve corresponder:
MD5: 41704fd7d8fd0723a45ffbb2dbbfa488
SHA256:0bc8dda364db7b99f389b42383e37b411d9fa022204d124cb3c8959eba252f05
O arquivo estará no formato:
<num_puzzles>
<unsolved_puzzle#1>,<solved_puzzle#1>
<unsolved_puzzle#2>,<solved_puzzle#2>
...
<unsolved_puzzle#n>,<solved_puzzle#n>
com uma única nova linha à direita.
O que não é permitido
Você não tem permissão para codificar soluções . Seu algoritmo deve ser aplicável a qualquer conjunto de quebra-cabeças do Sudoku, Sudokus fáceis e difíceis. No entanto, tudo bem se sua solução for lenta para quebra-cabeças mais fáceis.
Você não tem permissão para ter um programa não determinístico . Você tem permissão para usar um gerador de números aleatórios, mas a semente do gerador deve ser corrigida. Essa regra é garantir que as medições sejam mais precisas e tenham menos variação. (Obrigado a Peter Taylor pela dica)
Você não tem permissão para usar recursos externos ou solicitações da Web durante o tempo de execução do seu programa. Tudo deve ser independente. Isso não se aplica às bibliotecas e pacotes instalados, que são permitidos.
Outras informações
Se você quiser outro conjunto de testes para verificar sua solução, aqui estão 10000 Sudokus mais fáceis . Aqui estão as soluções deles .
MD5: 3cb465ef6077c4fcab5bd6ae3bc50d62
SHA256:0bc8dda364db7b99f389b42383e37b411d9fa022204d124cb3c8959eba252f05
Se você tiver alguma dúvida, não hesite em perguntar e tentarei esclarecer qualquer mal-entendido.
Respostas:
C ++ - pontuação oficial de 0.201s
O uso do Tdoku ( código ; design ; benchmarks ) fornece os seguintes resultados:
O Tdoku foi otimizado para instâncias difíceis do Sudoku. Mas observe, ao contrário da declaração do problema, que 17 quebra-cabeças estão longe de ser o Sudoku mais difícil. Na verdade, eles estão entre os mais fáceis, com a maioria não exigindo retorno. Veja alguns dos outros conjuntos de dados de referência no projeto Tdoku para obter quebra-cabeças realmente difíceis.
Observe também que, embora o Tdoku seja o solucionador mais rápido que eu conheço em quebra-cabeças difíceis, não é o mais rápido em 17 quebra-cabeças. Para eles, acho que o mais rápido é esse projeto de ferrugem , um derivado do JCZSolve, que foi otimizado para 17 quebra-cabeças durante o desenvolvimento. Dependendo da plataforma, pode ser 5-25% mais rápido que o Tdoku para esses quebra-cabeças.
fonte
Pontuação oficial de Node.js ,
8.231s6.735sPega o nome do arquivo como argumento. O arquivo de entrada já pode conter as soluções no formato descrito no desafio; nesse caso, o programa as comparará com suas próprias soluções.
Os resultados são salvos em 'sudoku.log' .
Código
Saída de exemplo
Testado em um Intel Core i7 7500U @ 2.70 GHz.
fonte
Python 3 (com dlx ) 4min 46.870s pontuação oficial
(i7-3610QM de núcleo único aqui)
Obviamente imbatível com uma linguagem compilada como C, e usando threading, mas é um começo ...
sudoku
é um módulo que eu coloquei no github (copiado no rodapé deste post) que é usadodlx
sob o capô.Uso
sudoku.py
algum lugar do seu caminho (no link do git hub ou copie-o abaixo)testSolver.py
em algum lugar do seu caminhoCanalize a saída conforme necessário na especificação de desafio para um arquivo, se necessário:
sudoku.py (sim, existem outros recursos aqui além de resolver)
fonte
Python 3 + Z3 - 10min 45.657s pontuação oficial
cerca de mil no meu laptop.
Instalar dependência
Corre
Não tenho certeza de como melhorar seu desempenho, pois ele resolveu magicamente ...
fonte
Pontuação oficial C -
2.228s1.690sbaseado em @ Arnauld
compile e execute:
fonte
C - 12min 28.374s pontuação oficial
funciona por cerca de
30m15m no meu i5-7200U e produz o hash md5 corretocompile (de preferência com o clang v6) e execute:
fonte
memcpy
lá e alguma recursão acontecendo. Vou tentar verificar isso hoje.Java - pontuação oficial da 4.056s
A idéia principal disso é nunca alocar memória quando não for necessária. A única exceção são as primitivas, que devem ser otimizadas pelo compilador de qualquer maneira. Todo o resto é armazenado como máscaras e matrizes de operações realizadas em cada etapa, que podem ser desfeitas quando a etapa de recursão for concluída.
Cerca de metade de todos os sudokus são resolvidos completamente sem voltar atrás, mas se eu aumentar esse número, o tempo geral parece ser mais lento. Estou planejando reescrever isso em C ++ e otimizar ainda mais, mas esse solucionador está se tornando um gigante.
Eu queria implementar o máximo possível de cache, o que levou a alguns problemas. Por exemplo, se houver duas células na mesma linha que só podem ter o número 6, chegamos a um caso impossível e devemos retornar ao retorno. Mas como calculei todas as opções em uma varredura e depois coloquei números nas células com apenas uma possibilidade, não verifiquei duas vezes se havia colocado um número na mesma linha pouco antes. Isso levou a soluções impossíveis.
Com tudo o que está contido nas matrizes definidas na parte superior, o uso de memória do solucionador real é de cerca de 216kB. A parte principal do uso da memória vem da matriz que contém todos os quebra-cabeças e dos manipuladores de E / S em Java.
Edição : Eu tenho uma versão que está traduzida para C ++ agora, mas não é muito mais rápido. O tempo oficial é de cerca de 3,5 segundos, o que não é uma grande melhoria. Penso que o principal problema da minha implementação é manter minhas máscaras como matrizes, em vez de máscaras de bits. Vou tentar analisar a solução de Arnauld para ver o que pode ser feito para melhorá-la.
fonte
C ++ com Minisat (2.2.1-5) - pontuação oficial 11.735s
Isso não é tão rápido quanto um algoritmo especializado, mas é uma abordagem diferente, um ponto de referência interessante e fácil de entender.
$ clang ++ -o resolve -lminisat solver_minisat.cc
fonte