Solveur de puzzle binaire


10

introduction

Les règles du puzzle:

Le puzzle Binary (également connu sous le nom de Takuzu ou Subiku) est très simple à comprendre et n'a que quelques règles:
puisque le nom du jeu est binaire, c'est assez évident, mais vous ne pouvez remplir que des zéros et des uns.

  1. Pas plus de deux du même chiffre peuvent être adjacents verticalement ou horizontalement
  2. Chaque ligne et chaque colonne doit contenir une quantité égale de zéros et de uns (cela signifie implicitement que chaque jeu binaire aura toujours des dimensions égales).
  3. Il peut ne pas y avoir de lignes et de colonnes dupliquées (avec exactement le même ordre de zéros et de uns).

Vous pouvez jouer au jeu sur www.binarypuzzle.com si vous le souhaitez.

Tactique:

En raison de la règle 1, nous pouvons toujours remplir un chiffre si:
- Il y a déjà deux du même chiffre verticalement ou horizontalement adjacents, auquel cas nous pouvons remplir le chiffre opposé des deux côtés. C'est à dire .11...0110...
- Il y a deux du même chiffre verticalement ou horizontalement avec un seul espace entre eux. C'est à dire .1.1...101..

En raison de la règle 1, lorsque trois espaces sont laissés et que nous ne pouvons pas avoir trois adjacents du même chiffre, nous pouvons remplir l'un des espaces. Ie .0.1.010.1.0(Nous devons encore en remplir deux, et nous ne pouvons pas en avoir trois adjacents au milieu, donc le premier écart doit être a 1.)

En raison de la règle 2, nous pouvons toujours combler les lacunes restantes dans une ligne ou une colonne si la moitié d'entre elles est déjà remplie avec le chiffre opposé. C'est à dire .1.011010011

En raison de la règle 3, nous pouvons toujours remplir les chiffres opposés s'il ne reste que deux à résoudre sur une ligne également ordonnée. C'est à dire 101100 & 1..100101100 & 110100

En raison de la règle 3, nous pouvons parfois combler un espace lorsque trois espaces sont laissés sur une ligne également ordonnée. C'est-à-dire 010011 & .1.01.010011 & .1.010(Ici, nous ne pouvons pas remplir un 1à la fin, car cela signifierait que nous devons remplir des zéros aux deux autres espaces, ce qui rend les deux lignes égales dans l'ordre.)

Exemple:

Nous commençons avec la grille 6x6 suivante avec des uns et des zéros remplis (et les points sont des lacunes que nous devons encore remplir):

.1....
.10.0.
1.11..
.1....
...1.0
......

En raison des règles 1 et 2, nous pouvons remplir ces chiffres:

.1.01.
.1010.
101100
010011
.0.1.0
.010..

En raison de la règle 1, nous pouvons remplir un 1 à la ligne 5, colonne 1:

.1.01.
.1010.
101100
010011
10.1.0
.010..

En raison de la règle 3, nous pouvons remplir un 0 à la ligne 1, colonne 6 (en regardant la ligne 4):

.1.010
.1010.
101100
010011
10.1.0
.010..

Maintenant, nous pouvons continuer à combler les lacunes avec des chiffres en raison des règles 1 et 2:

.1.010
010101
101100
010011
10.1.0
.010.1

Maintenant, nous pouvons terminer la ligne 5 en raison de la règle 3 (en regardant la ligne 3):

.1.010
010101
101100
010011
100110
.010.1

Et puis nous pouvons terminer le puzzle en raison des règles 1 et 2:

011010
010101
101100
010011
100110
101001

Défi:

Le défi est simple: compte tenu de la grille de départ, sortez le puzzle résolu.

REMARQUE: vous n'avez pas à implémenter les règles ci-dessus. Bien sûr, vous pouvez, et cela devrait vous donner des conseils sur la façon de mettre en œuvre ce défi, mais le renforcement de la solution avec les règles en tête est tout à fait correct.
La façon dont vous le résolvez dépend de vous, mais le défi consiste à produire le puzzle résolu.

Règles du défi:

  • Le format d'entrée et de sortie de la grille est flexible, mais veuillez indiquer ce que vous utilisez. (C'est-à-dire un tableau d'octets 2D; Chaîne avec des retours à la ligne; etc.)
  • Ceci ci-dessus s'applique également aux caractères utilisés. Dans l'exemple que j'ai utilisé 01., mais si vous le souhaitez, vous pouvez utiliser à la ABxplace. Veuillez indiquer le format d'entrée / sortie et les caractères que vous avez utilisés.
  • Vous pouvez supposer que seules les tailles de grille suivantes seront utilisées 6x6:; 8x8; 10x10; 12x12; 14x14; 16x16.

Règles générales:

  • C'est le , donc la réponse la plus courte en octets l'emporte.
    Ne laissez pas les langues de golf de code vous décourager de publier des réponses avec des langues non-golfeur de code. Essayez de trouver une réponse aussi courte que possible pour «n'importe quel» langage de programmation.
  • Des règles standard s'appliquent à votre réponse, vous êtes donc autorisé à utiliser STDIN / STDOUT, des fonctions / méthodes avec les paramètres appropriés, des programmes complets. Ton appel.
  • Les failles par défaut sont interdites.
  • Si possible, veuillez ajouter un lien avec un test pour votre code.
  • Veuillez également ajouter une explication si nécessaire.

Cas de test:

Les points ne sont ajoutés que pour la lisibilité, n'hésitez pas à utiliser des espaces ou tout ce que vous préférez pour les espaces à la place. Le format de sortie et de sortie est flexible.

Input:
1..0..
..00.1
.00..1
......
00.1..
.1..00

Output:
101010
010011
100101
011010
001101
110100

Input:
.1....
.10.0.
1.11..
.1....
...1.0
......

Output:
011010
010101
101100
010011
100110
101001

Input:
.......1..
.00..0..1.
.0..1..0.0
..1...1...
1.1......1
.......1..
.0..1...0.
....11...0
.0.0..1..0
0...0...1.

Output:
0110010101
1001100110
1001101010
0110011001
1010100101
0101010110
1001101001
0110110100
1010011010
0101001011


Réponses:


4

Brachylog , 34 octets

{ℕ<2}ᵐ²&≜{d?ọᵐctᵐ=&{ḅlᵐ⌉<3}ᵐ}&\↰₂&

Essayez-le en ligne!

C'est sacrément lent, donc le cas de test sur TIO est 4x4. J'exécute actuellement le cas de test 6x6 sur mon ordinateur pour voir combien de temps cela prend.

Cela prend une liste de listes en entrée. Les valeurs inconnues doivent être indiquées avec des variables, c'est-à-dire avec des chaînes tout en majuscules (et elles doivent toutes être différentes, sinon vous indiqueriez que certaines cellules doivent avoir la même valeur)

Explication

Nous contraignons les valeurs à entrer {0,1}, puis nous essayons des instanciations des variables jusqu'à ce que l'on respecte les 3 règles. C'est pourquoi cela est si lent (car il va tous les essayer jusqu'à en trouver un; et parce que dans ce cas, Brachylog n'est pas assez bien implémenté pour que des contraintes puissent être imposées avant d'essayer une éventuelle matrice).

                                 &  Output = Input
{   }ᵐ²                             Map two levels on the Input (i.e. each cell):
 ℕ<2                                  The cell is either 0 or 1
       &≜                           Assign values to all cells
         {                  }       Define predicate 2:
          d?                          The Input with no duplicates is still the Input
                                        (i.e. all rows are different)
           ?ọᵐctᵐ=                    All occurences of 1s and 0s for each rows are equal
                  &{      }ᵐ          Map on rows:
                    ḅlᵐ                 Get the lengths of runs of equal values
                       ⌉<3              The largest one is strictly less than 3
                             &\↰₂   Apply predicate 2 on the transpose of the Input
                                      (i.e. do the same checks but on columns)

Par curiosité, comment Brachylog indique-t-il des variables au-delà de l'alphabet majuscule? Supposons donc que votre solution fonctionne plus rapidement, elle ne pourra pas remplir tous les espaces vides sur une grille 14x14 avec Athrough Y(avec Zcomme paramètre de sortie). Est - il poursuivre AA, ABetc?
Kevin Cruijssen

2
@KevinCruijssen Tout identifiant tout en majuscules est une variable, donc oui AAest une variable et KEVINCRUIJSSENest également une variable.
Fatalize

3
Comme je le soupçonnais, un défi a été lancé pour Brachylog: D
Jonathan Allan

3

JavaScript (ES6), 274 270 octets

Prend l'entrée comme un tableau 2D, où les cellules vides sont marquées avec 2. Imprime toutes les solutions possibles sur la console.

f=(a,x=0,y=0,w=a.length,p,R=a[y])=>(M=z=>!a.some((r,y)=>/(0|1),\1,\1/.exec(s=r.map((v,x)=>(v=z?v:a[x][y],b-=v&1,c-=!v,m|=v&2,v),b=c=w/2))||b*c<0|o[b*c||s]&(o[s]=1),o={}))(m=0)&M(1)&&(m?R&&[0,1].map(n=>(p=R[x])==n|p>1&&(R[x]=n,f(a,z=(x+1)%w,y+!z),R[x]=p)):console.log(a))

Comment ça fonctionne

La première partie du code utilise la M()fonction pour vérifier la validité de la carte actuelle, à la fois horizontalement et verticalement.

M = z =>
  !a.some((r, y) =>
    /(0|1),\1,\1/.exec(
      s = r.map((v, x) =>
        (
          v = z ? v : a[x][y],
          b -= v & 1,
          c -= !v,
          m |= v & 2,
          v
        ),
        b = c = w / 2
      )
    ) ||
    b * c < 0 |
    o[b * c || s] &
    (o[s] = 1),
    o = {}
  )

Il associe une ligne ou une colonne complète à la chaîne s . Il s'agit en fait d'un tableau contraint à une chaîne, donc il ressemble "1,2,2,0,2,2".

Il utilise:

  • Expression régulière /(0|1),\1,\1/pour détecter au moins 3 chiffres identiques consécutifs.
  • Les compteurs b et c pour garder une trace du nombre de uns et de zéros . Les deux compteurs sont initialisés à w / 2 et décrémentés chaque fois qu'un ou un zéro (respectivement) est rencontré. Cela conduit à:
    • b = c = 0 b * c = 0 → la ligne est complète et correcte (autant de zéros que de uns )
    • b> 0 et c> 0 b * c> 0 → la ligne n'est pas complète mais correcte jusqu'à présent (nous n'avons plus de w / 2 zéros ou plus w / 2 les )
    • b <0 OU c <0 b * c <0 → la ligne n'est pas valide
  • Le drapeau m (pour « manquante ») , qui est non nulle s'il y a au moins un reste deux sur le plateau.
  • L'objet o de garder une trace de tous les modèles de ligne rencontrés jusqu'à présent.

Si la carte n'est pas valide, nous nous arrêtons immédiatement. Si la carte est valide et complète, nous l'imprimons sur la console. Dans le cas contraire, la deuxième partie des tentatives de code pour remplacer chaque 2 avec soit un zéro ou un un avec appels récursifs:

[0, 1].map(n =>
  (p = a[y][x]) == n |
  p > 1 && (
    a[y][x] = n,
    f(a, z = (x + 1) % w, y + !z),
    a[y][x] = p
  )
)

Démo


Merci d'avoir ajouté l'explication. Et j'aime la façon dont vous imprimez toutes les sorties possibles, au lieu d'une seule!
Kevin Cruijssen

1
@KevinCruijssen C'est probablement loin d'être optimal mais c'était amusant à écrire. Beau défi!
Arnauld

1

Gelée , 53 51 octets

ṡ€3ḄFf0,7L
SḤnLṀȯÇ
⁻QȯÇ
Fṣ©2L’0,1ṗż@€®F€s€LÇÐḟZÇ$Ðḟ

Prend une liste de listes représentant la grille, contenant 0, 1et 2(les espaces). Renvoie une liste de listes de listes, chaque liste de listes est au même format (mais sans 2s) et représente une solution possible à l'entrée.

Essayez-le en ligne! (cela n'exécutera aucun des cas de test de la question en raison de limitations de mémoire - les 2grilles nSpaces sont créées sous la forme d'une liste de listes de listes d'entiers - mais j'y ai mis un cas relativement lourd avec une seule solution). Le pied de page sépare et met en forme les grilles.

Méthode de force brute pure - implémente les règles et les vérifie pour chaque grille qui pourrait être formée en remplaçant l'un des 2s par 1s ou 0s.

ṡ€3ḄFf0,7L - Link 1, # of runs of 3 1s or 3 0s by row: list of lists
ṡ€3        - all contiguous slices of length 3 for €ach list
   Ḅ       - convert all results from binary
    F      - flatten into one list
     f     - filter keep values in:
      0,7  -   0 paired with 7: [0,7]
         L - length

SḤnLṀȯÇ - Link 2, unequal counts of 1s and 0s by column ...or link 1: list of lists
S       - sum (vectorises, hence "by column", counts 1s since only 1s or 0s appear)
 Ḥ      - double
   L    - length (number of rows - OK since square)
  n     - not equal? (vectorises)
    Ṁ   - maximum (1 if any not equal)
     ȯÇ - ... or last link (1) as a monad

⁻QȯÇ - Link 3, rows are unique ...or link 2: list of lists
 Q   - unique
⁻    - not equal?
  ȯÇ - ... or last link (2) as a monad

Fṣ©2L’0,1ṗż@€®F€s€LÇÐḟZÇ$Ðḟ - Main link: list of lists
F                           - flatten
 ṣ©2                        - split at 2s and copy the result to the register
    L                       - length (# of such slices)
     ’                      - decrement (# of 2s)
      0,1                   - 0 paired with 1
         ṗ                  - Cartesian power (all binary lists of length # of 2s)
             ®              - recall value from register (the flat version split at 2s)
          ż@€               - zip (reversed @rguments) for €ach (1s & 0s where 2s were)
              F€            - flatten €ach
                s€L         - split €ach into chunks of length length(input) (into rows)
                    Ðḟ      - filter discard if:
                   Ç        -   call last link(3) as a monad
                         Ðḟ - filter discard if:
                        $   -   last two links as a monad:
                      Z     -     transpose
                       Ç    -     call last link(3) as a monad
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.