Risolutore di puzzle binario


10

introduzione

Regole del puzzle:

Il puzzle binario (noto anche come Takuzu o Subiku) è molto semplice da capire e ha solo alcune regole:
poiché il nome del gioco è binario è abbastanza ovvio, ma puoi solo inserire zeri e uno.

  1. Non più di due della stessa cifra possono essere adiacenti verticalmente o orizzontalmente
  2. Ogni riga e ogni colonna devono contenere una quantità uguale di zeri e di uno (ciò implica implicitamente che ogni gioco binario avrà sempre dimensioni pari).
  3. Non ci possono essere righe duplicate e colonne duplicate (con lo stesso identico ordine di zeri e quelli).

Puoi giocare a www.binarypuzzle.com se vuoi.

tattiche:

A causa della regola 1, possiamo sempre inserire una cifra se:
- Esistono già due della stessa cifra verticalmente o orizzontalmente adiacenti l'una all'altra, nel qual caso possiamo riempire la cifra opposta su entrambi i lati. Cioè .11...0110...
- Ci sono due della stessa cifra in verticale o in orizzontale con un solo spazio tra loro. Cioè .1.1...101..

A causa della regola 1, quando rimangono tre spazi vuoti e non possiamo avere tre spazi adiacenti della stessa cifra, possiamo riempire uno degli spazi vuoti. Cioè .0.1.010.1.0(Dobbiamo ancora riempire due, e non possiamo avere tre adiacenti nel mezzo, quindi il primo gap deve essere a 1.)

A causa della regola 2, possiamo sempre colmare i vuoti rimanenti in una riga o colonna se la metà di essi è già riempita con la cifra opposta. Cioè .1.011010011

A causa della regola 3, possiamo sempre inserire le cifre opposte se ne rimangono solo due su una riga ugualmente ordinata. Cioè 101100 & 1..100101100 & 110100

A causa della regola 3, a volte possiamo riempire un vuoto quando tre lacune vengono lasciate su una linea ugualmente ordinata. Vale a dire 010011 & .1.01.010011 & .1.010(Qui non possiamo riempire a 1alla fine, perché ciò significherebbe che dobbiamo riempire gli zeri negli altri due spazi vuoti, rendendo entrambe le righe uguali in ordine.)

Esempio:

Iniziamo con la seguente griglia 6x6 con alcuni e zeri riempiti (e i punti sono vuoti che dobbiamo ancora riempire):

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

A causa delle regole 1 e 2 possiamo inserire queste cifre:

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

A causa della regola 1 possiamo inserire un 1 nella riga 5, colonna 1:

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

A causa della regola 3 possiamo inserire uno 0 nella riga 1, colonna 6 (quando si guarda la riga 4):

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

Ora possiamo continuare a colmare le lacune con le cifre dovute alle regole 1 e 2:

.1.010
010101
101100
010011
10.1.0
.010.1

Ora possiamo finire la riga 5 a causa della regola 3 (guardando la riga 3):

.1.010
010101
101100
010011
100110
.010.1

E quindi possiamo finire il puzzle a causa delle regole 1 e 2:

011010
010101
101100
010011
100110
101001

Sfida:

La sfida è semplicemente: data la griglia di partenza, esce il puzzle risolto.

NOTA: non è necessario implementare le regole sopra. Certo che puoi, e dovrebbe darti suggerimenti su come implementare questa sfida, ma forzare la soluzione con le regole in mente va benissimo.
Come risolverlo dipende da te, ma la sfida è quella di creare il puzzle risolto.

Regole della sfida:

  • Il formato di input e output per la griglia è flessibile, ma si prega di indicare ciò che si utilizza. (Vale a dire array di byte 2D; String con newline; ecc.)
  • Questo sopra vale anche per i personaggi usati. Nell'esempio che ho usato 01., ma se vuoi puoi usare ABxinvece. Indica quale formato di input / output e quali caratteri hai utilizzato.
  • È possibile assumere saranno utilizzati solo i seguenti dimensioni della griglia: 6x6; 8x8; 10x10; 12x12; 14x14; 16x16.

Regole generali:

  • Questo è , quindi vince la risposta più breve in byte.
    Non lasciare che le lingue di code-golf ti scoraggino dal pubblicare risposte con lingue non codegolfing. Prova a trovare una risposta il più breve possibile per "qualsiasi" linguaggio di programmazione.
  • Per la tua risposta valgono regole standard , quindi puoi usare STDIN / STDOUT, funzioni / metodo con i parametri corretti, programmi completi. La tua chiamata.
  • Le scappatoie predefinite sono vietate.
  • Se possibile, aggiungi un link con un test per il tuo codice.
  • Inoltre, si prega di aggiungere una spiegazione, se necessario.

Casi test:

I punti vengono aggiunti solo per la leggibilità, sentiti libero di usare spazi o qualsiasi altra cosa preferisci per gli spazi vuoti. Sia il formato di output che quello di output sono flessibili.

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


Risposte:


4

Brachylog , 34 byte

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

Provalo online!

Questo è dannatamente lento, quindi il test case su TIO è 4x4. Attualmente sto eseguendo il test case 6x6 sul mio computer per vedere quanto tempo ci vuole.

Questo accetta un elenco di elenchi come input. I valori sconosciuti dovrebbero essere indicati con variabili, ovvero con stringhe maiuscole (e dovrebbero essere tutti diversi, altrimenti si indicherebbe che alcune celle devono avere lo stesso valore)

Spiegazione

Vincoliamo i valori da inserire {0,1}, quindi proviamo le istanze delle variabili fino a quando non si rispettano tutte e 3 le regole. Questo è il motivo per cui è così lento (perché proverà tutti fino a trovarne uno; e perché in quel caso Brachylog non è implementato abbastanza bene da poter imporre vincoli prima di provare una possibile 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)

Per curiosità, in che modo Brachylog indica variabili oltre l'alfabeto maiuscolo? Quindi supponiamo che la tua soluzione funzioni più velocemente, non sarà in grado di riempire tutti gli spazi vuoti su una griglia 14x14 con Athrough Y(con Zcome parametro di output). Ha procedi con AA, ABecc?
Kevin Cruijssen,

2
@KevinCruijssen Qualsiasi identificatore tutto maiuscolo è una variabile, quindi sì AAè una variabile ed KEVINCRUIJSSENè anche una variabile.
Fatalizza

3
Come sospettavo, una sfida fatta per Brachylog: D
Jonathan Allan,

3

JavaScript (ES6), 274 270 byte

Accetta input come un array 2D, in cui le celle vuote sono contrassegnate con 2. Stampa tutte le possibili soluzioni sulla 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))

Come funziona

La prima parte del codice utilizza la M()funzione per verificare la validità della scheda corrente, sia in orizzontale che in verticale.

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 = {}
  )

Mappa una riga o colonna completa sulla stringa s . Questo è in realtà un array costretto a una stringa, quindi sembra "1,2,2,0,2,2".

Utilizza:

  • L'espressione regolare /(0|1),\1,\1/per rilevare 3 o più cifre identiche consecutive.
  • La contatori b e c per tenere traccia del numero di quelli e zeri . Entrambi i contatori vengono inizializzati su w / 2 e decrementati ogni volta che si incontra uno o uno zero (rispettivamente). Questo porta a:
    • b = c = 0 b * c = 0 → la linea è completa e corretta (come molti zeri come quelli )
    • b> 0 e C> 0 b * c> 0 → la linea non è completa ma corretta finora (non abbiamo più di w / 2 zeri o superiore w / 2 quelli )
    • b <0 O c <0 b * c <0 → la riga non è valida
  • La bandiera m (per "mancante") che è diversa da zero se ce ne sono almeno due rimanenti sul tabellone.
  • L'oggetto o di tenere traccia di tutti i motivi di linea incontrati finora.

Se la scheda non è valida, ci fermiamo immediatamente. Se la scheda è valida e completa, la stampiamo sulla console. Altrimenti, la seconda parte del codice tenta di sostituire ogni 2 con uno zero o uno con chiamate ricorsive:

[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
  )
)

dimostrazione


Grazie per aver aggiunto la spiegazione. E mi piace come stampi tutti i possibili output, invece di uno solo!
Kevin Cruijssen,

1
@KevinCruijssen Questo è probabilmente tutt'altro che ottimale ma è stato divertente scriverlo. Bella sfida!
Arnauld,

1

Gelatina , 53 51 byte

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

Prende una lista di liste rappresentano la griglia, contenenti 0, 1e 2(gli spazi). Restituisce un elenco di elenchi di elenchi, ogni elenco di elenchi è nello stesso formato (sebbene senza 2s) e rappresenta una possibile soluzione all'input.

Provalo online! (questo non eseguirà nessuno dei casi di test della domanda a causa delle limitazioni di memoria - tutte le 2griglie nSpaces sono create come un elenco di elenchi di numeri interi - ma ho messo un caso relativamente pesante lì con un'unica soluzione). Il piè di pagina separa e formatta le griglie.

Metodo di pura forza bruta - implementa le regole e le controlla per ogni griglia che potrebbe essere formata sostituendo una delle 2s con 1s o 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.