Votre travail consiste à écrire un programme (ou deux programmes distincts) dans n’importe quelle langue:
- Peut prendre une carte de Sudoku terminée en entrée (dans n'importe quel format logique) et la compresser en une chaîne de caractères
- Peut prendre la chaîne compressée en entrée et la décompresser pour obtenir exactement la même carte de Sudoku terminée (sortie dans n'importe quel format logique de 9 lignes)
Remarque: utilisez les règles du Sudoku à votre avantage. c'est l'idée derrière ce défi.
Sudoku règne sur Wikipedia
Règles
- Seuls les caractères ASCII imprimables (32 - 126) sont autorisés dans la sortie compressée (par exemple, aucun caractère multi-octets ).
- Vous pouvez supposer que la saisie est une carte 3x3 Sudoku valide (règles normales, pas de variations).
- Je ne vais pas imposer de limite de temps, mais ne créez pas d'algorithme de force brute. Ou bien, les auteurs des soumissions devraient pouvoir tester leurs soumissions avant de poster (Merci, Jan Dvorak).
Si vous avez des questions ou des préoccupations, vous pouvez demander des éclaircissements ou faire des suggestions dans les commentaires.
Conditions gagnantes
Score = somme du nombre de caractères des dix cas de test
Le score le plus bas gagne.
Cas de test
Vous pouvez les utiliser pour tester le fonctionnement de votre programme.
9 7 3 5 8 1 4 2 6
5 2 6 4 7 3 1 9 8
1 8 4 2 9 6 7 5 3
2 4 7 8 6 5 3 1 9
3 9 8 1 2 4 6 7 5
6 5 1 7 3 9 8 4 2
8 1 9 3 4 2 5 6 7
7 6 5 9 1 8 2 3 4
4 3 2 6 5 7 9 8 1
7 2 4 8 6 5 1 9 3
1 6 9 2 4 3 8 7 5
3 8 5 1 9 7 2 4 6
8 9 6 7 2 4 3 5 1
2 7 3 9 5 1 6 8 4
4 5 1 3 8 6 9 2 7
5 4 2 6 3 9 7 1 8
6 1 8 5 7 2 4 3 9
9 3 7 4 1 8 5 6 2
1 5 7 6 8 2 3 4 9
4 3 2 5 1 9 6 8 7
6 9 8 3 4 7 2 5 1
8 2 5 4 7 6 1 9 3
7 1 3 9 2 8 4 6 5
9 6 4 1 3 5 7 2 8
5 4 1 2 9 3 8 7 6
2 8 9 7 6 1 5 3 4
3 7 6 8 5 4 9 1 2
8 3 5 4 1 6 9 2 7
2 9 6 8 5 7 4 3 1
4 1 7 2 9 3 6 5 8
5 6 9 1 3 4 7 8 2
1 2 3 6 7 8 5 4 9
7 4 8 5 2 9 1 6 3
6 5 2 7 8 1 3 9 4
9 8 1 3 4 5 2 7 6
3 7 4 9 6 2 8 1 5
6 2 8 4 5 1 7 9 3
5 9 4 7 3 2 6 8 1
7 1 3 6 8 9 5 4 2
2 4 7 3 1 5 8 6 9
9 6 1 8 2 7 3 5 4
3 8 5 9 6 4 2 1 7
1 5 6 2 4 3 9 7 8
4 3 9 5 7 8 1 2 6
8 7 2 1 9 6 4 3 5
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 1 4 3 6 5 8 9 7
3 6 5 8 9 7 2 1 4
8 9 7 2 1 4 3 6 5
5 3 1 6 4 8 9 7 2
6 4 8 9 7 2 5 3 1
9 7 2 5 3 1 6 4 8
1 4 5 7 9 2 8 3 6
3 7 6 5 8 4 1 9 2
2 9 8 3 6 1 7 5 4
7 3 1 9 2 8 6 4 5
8 5 9 6 4 7 3 2 1
4 6 2 1 3 5 9 8 7
6 2 4 8 7 3 5 1 9
5 8 7 4 1 9 2 6 3
9 1 3 2 5 6 4 7 8
5 2 7 4 1 6 9 3 8
8 6 4 3 2 9 1 5 7
1 3 9 5 7 8 6 4 2
2 9 1 8 5 4 3 7 6
3 4 8 6 9 7 5 2 1
6 7 5 1 3 2 4 8 9
7 1 2 9 4 5 8 6 3
4 8 3 2 6 1 7 9 5
9 5 6 7 8 3 2 1 4
2 4 6 7 1 3 9 8 5
1 8 5 4 9 6 7 3 2
9 3 7 8 2 5 1 4 6
6 7 8 5 4 2 3 9 1
4 9 3 1 6 8 2 5 7
5 1 2 3 7 9 4 6 8
8 2 4 9 5 7 6 1 3
7 5 9 6 3 1 8 2 4
3 6 1 2 8 4 5 7 9
8 6 1 2 9 4 5 7 3
4 7 5 3 1 8 6 9 2
3 9 2 5 6 7 8 1 4
2 3 6 4 5 9 7 8 1
1 5 4 7 8 3 2 6 9
9 8 7 6 2 1 3 4 5
5 2 9 1 7 6 4 3 8
6 4 8 9 3 2 1 5 7
7 1 3 8 4 5 9 2 6
Nous remercions http://www.opensky.ca/~jdhildeb/software/sudokugen/ pour certaines de ces
Si vous rencontrez des problèmes avec les cas de test, merci de me le signaler.
code-challenge
compression
sudoku
kukac67
la source
la source
fudge
sous - programme de ma deuxième réponse qui gagne 12 points). Un test plus équitable consisterait à exiger que (a) les solutions de test fonctionnent, (b) marquer 1 000 grilles de Sudoku générées de manière aléatoire et diviser la réponse par 100. Je pense que le mieux que l'on puisse faire avec des données aléatoires est d'environ 110, sur 10 x log-base-95 (6670903752021072936960)Réponses:
Haskell, 107 points
Les résultats du cas de test:
Le code n'est pas joli, mais ça marche. L'algorithme repose sur le fait que, même si l'énumération de toutes les solutions prendrait trop de temps, l'énumération de toutes les solutions d'un bloc est assez rapide. En fait, elle est plus rapide que la conversion ultérieure en base95. Tout se passe en quelques secondes dans l'interprète de ma machine bas de gamme. Un programme compilé se terminerait immédiatement.
Le soulèvement lourd est effectué par la
solution2ix
fonction qui, pour chaque bloc 3x3, génère toutes les permutations possibles, sous réserve de contraintes de gauche et d’en haut, jusqu’à ce qu’elle trouve celle dans la solution codée, en ne mémorisant que l’indice de cette permutation. Ensuite, il combine les index en utilisant des pondérations précalculées et le schéma de Horner.Dans l'autre sens, la
ix2solution
fonction décompose d'abord l'index en neuf valeurs. Ensuite, pour chaque bloc, il indexe la liste des permutations possibles avec sa valeur respective, puis extrait les contraintes pour les blocs suivants.assignments
est une récursion déroulée simple mais laide utilisant la liste monad. Il génère la liste des permutations en fonction d'un ensemble de contraintes.Le vrai pouvoir vient des limites serrées sur les longueurs de liste de permutation:
9!
. Cette valeur n'est jamais utilisée, sauf pour trouver une limite supérieure pour la longueur en sortie.6*5*4*6!
est sept fois pire que le nombre réel trouvé par énumération:12096
Le produit de toutes ces limites est
71025136897117189570560
~ =95^11.5544
, ce qui signifie qu'aucun code ne dépasse 12 caractères et que presque la moitié d'entre eux doivent comporter 11 caractères ou moins. J'ai décidé de ne pas distinguer entre une chaîne plus courte et la même chaîne remplie à droite d'espaces. Les espaces partout ailleurs sont importants.La limite théorique de l'efficacité du codage pour les codes sans préfixe - logarithme en base 95
6670903752021072936960
- est11.035
que même un algorithme optimal ne peut éviter de produire des sorties de longueur 12, bien qu'il ne les produise que dans 3,5% des cas. Si la longueur doit être significative (ou l'équivalent, l'ajout d'espaces de fin) ajoute quelques codes (1% de la quantité totale), mais pas suffisamment pour éliminer le besoin de codes de longueur 12.la source
Python, 130 points
L'algorithme fonctionne en codant chaque position du tableau, une à la fois, en un grand entier. Pour chaque position, il calcule les valeurs possibles en fonction de toutes les assignations encodées jusqu'à présent. Donc, si [1,3,7,9] sont les valeurs possibles pour une position donnée, il faut 2 bits pour coder le choix.
La bonne chose à propos de ce schéma est que si une position n'a plus qu'un seul choix, l'encodage ne nécessite pas d'espace.
Une fois que nous avons le grand entier, nous l'écrivons en base 95.
Les ordres d’encodage sont probablement meilleurs que le lexicographique, mais je n’y ai pas beaucoup réfléchi.
Codeur:
Décodeur:
Exécutez-le comme ceci:
la source
perl - score
115113103113Sortie:
Sortie:Aucune de ces lignes n'a un espace de fin. Notez que la première ligne est vide.
Cet algorithme fonctionne comme suit. Pour compresser:
Commencez avec une chaîne 'courante' vide représentant la grille de Sudoku
Pensez à ajouter tour à tour chacun des chiffres 1 à 9 à cette chaîne et déterminez lequel est viable.
Obtenir le prochain chiffre de la grille de réponses (et l'ajouter au courant)
Si un seul est viable, il n'y a rien à coder
Si plusieurs sont viables, comptez le nombre d'options viables, triez-les et codez ce chiffre comme index dans le tableau trié. Enregistrez le chiffre et le nombre viables sous la forme d'un tuple dans un tableau.
Lorsque tout est terminé, codez chacun des 2-nuplets (dans l'ordre inverse) dans un nombre basé sur une variable et stocké sous forme de bigint.
Exprimer le bigint en base 95.
Pour décoder:
Commencez avec une chaîne 'courante' vide représentant la grille de Sudoku
Décoder le nombre base95 en bigint
Pensez à ajouter tour à tour chacun des chiffres 1 à 9 à cette chaîne et déterminez lequel est viable.
Si un seul est viable, il n'y a rien à coder; ajouter ce choix à la grille
Si plusieurs sont viables, comptez le nombre d'options viables, triez-les et codez ce chiffre comme index dans le tableau trié.
Décodez le bigint à base variable en utilisant le nombre d'options viables comme base et le module en tant qu'index dans le tableau, puis indiquez ce chiffre sous forme de valeur de cellule.
Afin de déterminer le nombre d’options viables, on utilise Games :: Sudoku :: Solver. C'est principalement pour la clarté qu'il y a des solveurs de Sudoku à 3 lignes sur ce site.
Pour faire tous les 10 a pris 8 secondes sur mon ordinateur portable.
L'
fudge
opération trie le tableau différemment pour atteindre la valeur minimale pour les cas de test. Comme documenté, ceci est un fudge. Le fudge réduit le score de 115 à 103. Il est fabriqué à la main pour que le code bigint du premier test soit égal à 0. Le score le plus défavorable pour tous les sudoku est 12, ce qui donne un score de 120. Je ne pense donc pas que cela compte comme codage en dur; il optimise plutôt pour les données de test. Pour le voir fonctionner sans cela, changez-lesort fudge
dans lessort
deux endroits.Le code suit:
la source
CJam, 309 octets
Ceci est juste une solution de base rapide. Je suis désolé de l'avoir fait dans une langue de golf, mais c'était en fait le moyen le plus simple de le faire. J'ajouterai une explication du code réel demain, mais j'ai décrit l'algorithme ci-dessous.
Codeur
Décodeur
Testez-le ici.
L'entrée du codeur (sur STDIN) et la sortie du décodeur (sur STDOUT) se présentent sous la forme d'un tableau CJam imbriqué. Par exemple
Les 10 sorties de test sont:
L'algorithme est très simple:
la source
Python 2.7, total de 107 caractères
TL; DR force brute de 3x3 carrés avec contraintes haut + gauche
cas de test:
fonction d'assistance pour imprimer le sudoku
génère tous les carrés possibles étant donné les contraintes ci-dessus et à gauche
voir le commentaire de code pour plus de détails
extrait tous les carrés du plateau de sudoku sous forme de tuples
voir le commentaire de code pour plus de détails
reconvertit les places en planche de sudoku
fondamentalement un inverse de la fonction ci-dessus
carrés donnés, contraintes de retour
voir le commentaire de code pour plus de détails
carrés donnés ci-dessus, contraintes de retour
voir le commentaire de code pour plus de détails
fait une ficelle
c'est une liste codée en dur des dépendances pour chaque carré
voir le commentaire de code pour plus de détails
c'est une liste codée en dur du nombre maximum d'options possibles pour chaque carré
voir le commentaire de code pour plus de détails
ceux-ci combinent les fonctions ci-dessus et convertissent un tableau en une liste d'entiers
et retour à un conseil
ok c'est toutes les fonctions
pour chaque planche, fabriquez une ficelle et imprimez-la
affiche maintenant la longueur totale de toutes les chaînes
et un-stringify, pour prouver que ce n'est pas une compression à sens unique
sortie:
la source
Mathematica, score:
1309Mise à jour:
Une fois cette réponse publiée, elle a inspiré une nouvelle faille: "Optimiser pour les cas de test donnés" . Je laisserai cependant cette réponse telle quelle, comme exemple de cette échappatoire. Ne hésitez pas à downvote. Je ne serai pas blessé.
Ceci code une cellule à la fois dans l'ordre du raster et élimine sa valeur de manière appropriée pour les cellules suivantes en utilisant les règles de base de Sudoku. Ainsi, par exemple, lorsqu'une cellule est codée et ne dispose que de quatre possibilités, un chiffre de base 4 est ajouté au grand entier. Il code également les scénarios de test directement sous forme de petits nombres entiers, toujours en compressant et en décompressant correctement toutes les cartes de Sudoku valides avec une longueur comprimée moyenne d’environ 12,5 caractères, soit 1,5 de plus que le 11.035 optimal, avec un code relativement simple et aucun solveur de Sudoku requis.
Cas de test codés:
Cela n'aboutit pas à un codage parfait (~ 11 en moyenne), car les règles de base n'excluent pas certains choix pour lesquels il n'y a pas de solution. La performance pourrait être rendue parfaite (le grand nombre entier serait toujours inférieur au nombre de cartes de Sudoku possibles) en vérifiant s'il n'y avait pas de solution à certains des choix actuels en utilisant un solveur de Sudoku, et en les éliminant également.
la source
J, 254 points
Compression DécompressionLes E / S standard sont un peu maladroites en J car il
jconsole
s’agit en fait d’une REPL, alors j’ai pris la liberté d’écrire la sortie compressée dans un fichier.Trouve l'index d'anagramme de chaque ligne, traite les neuf nombres résultants comme un nombre base- (9!), Puis convertit finalement en base 95, ajoute 32 et convertit en ASCII, comme dans la solution de Martin Büttner. L'index d'anagramme d'une permutation de 1..n est simplement l'indice de la permutation dans la liste triée lexicalement de toutes ces permutations, par exemple l'
5 4 3 2 1
index d'anagramme 5! - 1 = 119 .Toutes les opérations ont des inverses faciles, la décompression est donc simple.
En prime, les exemples sont dans un format très convivial en J, de sorte que les entrées / sorties pour les sudokus décompressés sont exactement telles que données dans les exemples (bien que l'entrée dans le codeur nécessite un retour à la ligne final).
Chaînes compressées pour les cas de test:
la source
Python 3, 120 points
Ce programme répertorie tous les blocs 3x3 possibles et mémorise celui qui était réellement présent dans le Sudoku original, puis regroupe tous ces nombres dans une représentation en base 95. Bien que cela soit très proche du codage en dur, il compresse et décompresse les exemples en environ 5 secondes chacun sur ma machine.
Les fonctions principales sont
compress(sudoku)
etdecompress(text)
.Les sorties:
la source
Python 2.5, 116 points
Code:
Résultats:
Très lent. A pris 517 secondes pour s'exécuter et vérifier sur ma machine.
encconfig prend un tableau de sudoku et un chiffre de 1 à 9, répertorie les coordonnées xy où ce chiffre apparaît et génère un nombre dans la plage (6 ** 6) qui représente ces coordonnées. (la "configuration de chiffres")
decconfig est la fonction inverse. Il faut un nombre compris entre 6 et 6, un chiffre et une carte de sudoku (vide par défaut). Il sort la carte de sudoku superposée avec la configuration des chiffres. Si l'une des positions de la configuration de chiffres est déjà prise dans la carte de sudoku entrée, le chiffre dans cette position est écrasé par le nouveau chiffre.
compatible prend une carte de sudoku et une configuration de chiffres (définie par conf et dig), superpose la configuration de chiffres sur la carte de sudoku et vérifie les conflits. Il renvoie ensuite True ou False en fonction du résultat.
Encode est la fonction de compression. Il faut un tableau de sudoku et un nombre le représentant. Pour ce faire, il copie d’abord les positions des 1 sur un tableau vide et dresse la liste de toutes les configurations du nombre 2 compatibles avec la configuration 1 (qui ne prennent aucune des places déjà occupées par le 1). Il trouve ensuite dans la liste l'ordre de la configuration 2 réelle du tableau et le stocke, puis copie cette configuration dans le nouveau tableau, qui ne contient plus que les 1 et les 2. Il répertorie ensuite toutes les configurations du nombre 3 compatibles avec les positions des 1 et des 2, etc.
Le décodage est la fonction inverse.
Python 2.5.
la source
C #, 150 octets
Sortie comprimée:
Comment ça marche:
Il génère toutes les permutations possibles de 123456789 et les mémorise. Ensuite, il compare les permutations avec les lignes du sudoku. Lorsqu'une permutation correspondante pour une ligne donnée est trouvée, elle se souvient de l'indice de cette permutation. Après chaque ligne, toutes les permutations seront supprimées s'il y a au moins un caractère dans la même position que la ligne actuelle. Cela garantit que chaque numéro est unique dans sa colonne. Ensuite, toutes les permutations qui ne fonctionnent plus selon les critères de la boîte sont supprimées. Comme la dernière ligne est triviale, elle génère 8 chiffres. J'ai testé la valeur maximale de chacun de ces nombres et généré un masque de décompte des chiffres pour chaque position de ceux-ci. {6, 5, 3, 5, 3, 1, 2, 1, 1}. La première est évidemment la plus longue avec 362880 permutations. En utilisant le masque de masque, je construis un BigInteger avec un 1 pour le rendre long de 28 chiffres. Cela donne un total de 11 octets. Ensuite, ces octets sont convertis en base64. Pour enregistrer un caractère, je supprime le signe = à la fin.
La reconstruction fonctionne de manière similaire.
Il reconstruit le BigInteger à partir de la base64string, puis le transforme à nouveau en chaîne et le scinde à nouveau à l'aide du masque mentiond num-count-mask. Ces chaînes sont analysées dans les index.
Ensuite, l'algorithme fait presque la même chose, au lieu de rechercher la ligne dans les permutations, il utilise simplement l'index pour obtenir la ligne, le reste fonctionne de la même manière.
Probablement, cela pourrait être un peu mieux d’utiliser réellement les 94 personnages possibles au lieu de seulement 64, mais il me manque le cerveau pour le faire.
Source : Copier et coller pour le faire fonctionner avec les 10 exemples. .dotNet-Fiddle me dit que cela dépasse la limite de mémoire, vous devez donc l'exécuter sur votre machine en texte.
la source
Perl - 290 caractères = 290 points
Ce programme n’utilise aucun codage dur et compresse de manière fiable une grille en 29 caractères exactement (théoriquement, il serait possible de trouver des caractères plus petits).
Voici comment cela fonctionne:
Commencez par convertir le tableau 9 x 9 en 60 nombres. Cela peut être fait comme la dernière colonne, la dernière ligne et le carré final de chaque cellule 3 x 3 peut être supprimé.
Convertissez ensuite en utilisant bigint en un entier unique, en utilisant 9 ^ 60 éléments.
Puis convertissez le bigint en base 95.
Compresseur et décompresseur:
la source
PHP, 214
Cette solution efface d'abord la colonne de droite et la rangée inférieure, ainsi que le coin inférieur droit de chaque bloc 3x3. Il essaie ensuite de vider une cellule. Si une solution simple existe, la cellule reste vide.
Ensuite, la grille de sudoku est formatée en une chaîne, de gauche à droite et de haut en bas, à l'exclusion de la colonne de droite, de la ligne inférieure et du coin inférieur droit. Les zéros au début sont comptés (qu’il en soit ainsi
z
) et supprimés. Les zéros de fin sont également supprimés.La chaîne est formatée soit en un entier de base 10, 11 ou 12 (soit cette base
b
), avecA
représentant deux zéros, etB
trois.Celui-ci est converti en un nombre entier base 95 et précédé du chiffre représentant base 95
z << 2 | (b - 10)
.Appel
php sudoku-compress.php enc
à encoder etphp sudoku-compress.php dec
à décoder. Encoder prend le format indiqué dans la question, avec un retour à la ligne obligatoire.Test des sorties:
la source
Java, 330 Points
Avant de me faire ridiculiser pour un score aussi élevé, permettez-moi de préciser que j'ai tenté d'essayer de résoudre ce problème différemment, sachant qu'il ne serait probablement pas aussi optimal que certaines des meilleures réponses données ici. J'étais plus ou moins curieux de savoir si je pouvais obtenir près ce qui à ma grande surprise , je ne savais pas à quel point le pire cela tournerait. Voici le résumé de mon approche:
Développez un algo pour résoudre un puzzle de sudoku.
Développez un algorithme de brouillage qui peut encore être résolu. Il le fait un peu au hasard tout en éliminant les indices qui peuvent être trivialement déterminés au préalable. Je pouvais obtenir environ 22 indices de manière fiable avant que cela prenne beaucoup trop de temps.
Une fois brouillé, le puzzle pourrait être représenté par un triplet d’entiers à un chiffre pour chaque indice, dans mon cas, 22 triplets de 3. Je pensais que si je pouvais les combiner en un seul nombre à 66 chiffres puis en code 95, alors j’ai quelque chose qui peut être facilement décodé.
La chaîne encodée a fini par être plus longue que ce que j'espérais, généralement autour de 33 caractères. À ce moment-là, j'ai essayé d'utiliser un autre moyen que Java BigInteger. J'ai créé un grand nombre à partir d'un masque de 81 bits représentant les 81 cellules d'une grille, où 1 signifie qu'un indice existe pour cette cellule. J'ai ensuite combiné ce masque binaire à des représentations sur 4 bits de chaque valeur de cellule dans un ordre séquentiel, arrondi au nombre d'octets, et constaté que j'avais à peu près la même longueur de chaîne codée après codé en base95.
Je publie donc mon code au cas où quelqu'un s'intéresserait à une approche différente qui n'aurait pas si bien fonctionné.
Classe Puzz
Mon cas de test
Test de sortie
la source
C ++ 241, note: 82 * 10 = 820
Ajoute '!' au début de la chaîne codée pour déterminer quelle opération effectuer.
241 personnages au golf
Ungolfed 312 caractères
la source