Piastrellatura domino Fibonacci


11

C'è classico risultato combinatorio che il numero di modi per piastrelle di una 2*nstriscia dal 1*2domino è il n ° numero di Fibonacci. Il tuo obiettivo è stampare tutti i tasselli per un dato n, disegnati con trattini e linee verticali come questi 8 tasselli per n=5:

|————
|————

——|——
——|——

|||——
|||——

————|
————|

||——|
||——|

|——||
|——||

——|||
——|||

|||||
|||||

È necessario fornire un programma o una funzione denominata che accetta ncome input e stampa l'output richiesto. Vince il minor numero di byte.

Ingresso

Un numero ncompreso 1e 10compreso tramite STDIN o input di funzione.

Produzione

Stampa tutti i possibili soffitti domino della 2*nstriscia, disegnati orizzontalmente. I limiti possono essere in qualsiasi ordine, ma ognuno dovrebbe apparire esattamente una volta. Devono essere separati da una linea vuota.

Un domino verticale è composto da due barre verticali ( |) e un domino orizzontale è composto da due trattini ( ). È possibile utilizzare trattini ( -) al posto dei trattini per rimanere in ASCII.

Puoi fare qualsiasi cosa con gli spazi bianchi purché l'output stampato sia uguale.


Un ulteriore avanzamento di riga dopo l'ultima piastrellatura cadrebbe sotto qualsiasi cosa con spazi bianchi ?
Dennis,

@Dennis Sì, le righe vuote extra vanno bene.
xnor

Sono davvero sorpreso di vedere così tanti approcci diversi per risolvere lo stesso problema. Te lo aspettavi?
Level River St,

@steveverrill No, assolutamente no, e sono felice di vedere la varietà! E il tuo prende la torta per imprevisti. Per lo più avevo in mente una ricorsione in stile Fibonacci, come la maggior parte delle soluzioni utilizzate che ho usato. Non mi aspettavo che il filtraggio fosse efficace, e nella misura in cui lo facevo, pensavo che avrebbe filtrato stringhe di lunghezza ——e |lunghezza come quelle di Dennis, non nstringhe di lunghezza e |filtrate apparendo in coppia. E per quest'ultimo, mi aspetto che avvenga tramite regex o operazioni su stringa sulla stringa prodotta, come s.split('——) `, non con un approccio aritmetico come il tuo.
xnor,

Penso che "domino 1x2" sia ridondante.
SuperJedi224,

Risposte:


5

C, 106

Versione golfizzata

f(n){
  for(int i,h=n*2<<n;h--;(i/3|i/3*2)-i||(putchar(i>>h%n&1?45:124),h%n||puts(h%(n*2)?"":"\n")))
    i=h/2/n;
}

Versione originale

i,j,n;
main(){
  scanf("%d",&n);
  for(i=1<<n;i--;)if((i/3|i/3*2)==i){
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("");
    for(j=1<<n;j/=2;)printf("%c",i&j?'-':'|');puts("\n");
  }
}

Come funziona

La variabile iva da 1<<n-10 a zero, producendo tutti i possibili numeri binari con ncifre. 0 codifica per |e 1 codifica per -. Siamo interessati a numeri che contengono 1 in coppia. Ovviamente tali numeri sono divisibili per 3.

Quando un numero viene diviso per 3, il numero originale può essere recuperato moltiplicando il risultato per 2 e aggiungendolo a se stesso (effettuando una conversione effettiva per 3.) La maggior parte dei numeri richiederà un carry, ma quando il processo viene eseguito sui numeri di interesse, nessun riporto è richiesto, quindi solo in questi casi, OR può essere usato al posto dell'aggiunta. Viene utilizzato per verificare i numeri di interesse, in quanto sono i soli in cui l'espressione i/3|i/3*2restituisce il valore originale di i. Vedi esempio sotto.

1111= 15 ---> 0101= 5 ---> 1111= 15 (valido, 0101|1010== 0101+1010)

1001= 9 ---> 0011= 3 ---> 0111= 7 (non valido 0011|0110,! = 0011+0110)

Il valore del test è sempre uguale o inferiore al valore originale. Poiché i numeri che non sono multipli di 3 restituiscono anche un numero inferiore all'originale quando vengono divisi per 3 e poi moltiplicati per 3, il test fornisce anche il FALSO desiderato su questi numeri.

Nella versione originale un paio di loop jsono usati per scansionare i bit di ie produrre l'output. Nella versione golfata forviene utilizzato un singolo loop, in cui hscorre tutti i numeri da (n*2)*(1<<n)-10 a 0. I valori di isono generati da h/2/n. La variabile jnon viene più utilizzata, poiché la quantità equivalente viene ottenuta da h%n. L'uso di n*2consente a entrambe le linee di essere stampate dallo stesso loop, con un po 'di multiplexing elegante nell'istruzione putsper stampare una o due nuove righe alla fine della riga.

Si noti che la carne di questo è nella posizione di incremento della for()parentesi e quindi viene eseguita dopo il i=h/2/h.

Uscita campione n = 6:

$ ./a
6
------
------

----||
----||

--|--|
--|--|

--||--
--||--

--||||
--||||

|----|
|----|

|--|--
|--|--

|--|||
|--|||

||----
||----

||--||
||--||

|||--|
|||--|

||||--
||||--

||||||
||||||

Il i/3|i/3*2trucco è geniale! Non mi aspettavo un'espressione aritmetica per la grammatica.
xnor

3

CJam, 33 27 byte

LN{_'|f+@"——"f++}ri*\;{_N}/

Grazie a @ jimmy23013 per giocare a golf con 6 byte!

Provalo online!

sfondo

Questa è un'implementazione iterativa di un algoritmo ricorsivo:

I possibili tasselli per n possono essere ottenuti aggiungendo un domino verticale ai possibili tasselli per n - 1 e due domini orizzontali ai possibili soffitti per n - 2 .

In questo modo, il numero di tassellature per n è la somma dei numeri di tilings per n - 1 e n - 2 , vale a dire, il n ° numero di Fibonacci.

Come funziona

LN                                " A:= [''] B:= ['\n']                         ";
  {             }ri*              " Repeat int(input()) times:                  ";
   _'|f+                          "   C = copy(B); for T ∊ C: T += '|'          ";
              @                   "   Swap A and B.                             ";
               "——"f+             "   for T ∊ B: T += "——"                      ";
                     +            "   B = C + B                                 ";
                        \;        " Discard A.                                  ";
                          {_N}/   " for T ∊ B: print T, T + '\n'                ";

Esempio di esecuzione

$ alias cjam='java -jar cjam-0.6.2.jar'

$ cjam domino.cjam <<< 3
|||
|||

——|
——|

|——
|——

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done1
2
3
5
8
13
21
34
55
89

LNli{_'|f\@"——"f\+2/}*\;{_N}/.
jimmy23013,

f\non era ancora stato implementato in 0.6.2, ma sono stato in grado di combinare i nostri approcci. Grazie!
Dennis,

2

Haskell, 89 byte

f(-1)=[]
f 0=[""]
f n=map('|':)(f$n-1)++map("--"++)(f$n-2)
g=unlines.(>>= \x->[x,x,""]).f

fè una funzione che dato un numero restituisce un elenco di una riga di tutti i possibili massimali di Fibonacci della lunghezza n possibile. non importa che restituisca una riga, poiché entrambe le linee di tutti i limiti sono uguali.

ffunziona chiamando ricorsivamente n-1e n-2e aggiungendo "|"e "--"(rispettivamente) alle stringhe.

gè la funzione che risponde alle domande. fondamentalmente chiama fl'input, raddoppia ogni stringa in modo da mostrare due linee e le unisce tutte con nuove linee.

esempio di output:

*Main> putStrLn $ g 5
|||||
|||||

|||--
|||--

||--|
||--|

|--||
|--||

|----
|----

--|||
--|||

--|--
--|--

----|
----|

2

CJam, 42 37 byte

3li:L#,{3b"——|"2/f=s}%{,L=},_&{N+_N}/

Ho contato i trattini come un byte ciascuno poiché la domanda consente di sostituirli con trattini ASCII.

Provalo online.

Come funziona

Per ottenere tutti i possibili limiti di 2 × L , ripetiamo su tutti gli interi non negativi I <3 L , facendo in modo che le cifre pari nella base 3 corrispondano ai domini orizzontali e alle cifre dispari a quelle verticali.

Poiché ogni I ha L o meno cifre nella base 3, questo genera tutti i modi possibili di coprire la striscia 2 × L. Non resta che filtrare i rivestimenti più grandi o più piccoli di 2 × L e stampare i rivestimenti rimanenti.

3li:L#,      " Read an integer L from STDIN and push A := [ 0 1 ... (3 ** N - 1) ].       ";
{            " For each integer I in A:                                                   ";
  3b         " Push B, the array of I's base 3 digits.                                    ";
  "——|"2/    " Push S := [ '——' '|' ].                                                    ";
  f=         " Replace each D in B with S[D % 2] (the modulus is implicit).               ";
  s          " Flatten B.                                                                 ";
}%           " Collect the result in an array R.                                          ";
{,L=},       " Filter R so it contains only strings of length L.                          ";
_&           " Intersect R with itself to remove duplicates.                              ";
{N+_N}/      " For each string T in B, push (T . '\n') twice, followed by '\n'.           ";

Esempio di esecuzione

$ cjam domino.cjam <<< 3
|——
|——

——|
——|

|||
|||

$ for i in {1..10}; do echo $[$(cjam domino.cjam <<< $i | wc -l) / 3]; done
1
2
3
5
8
13
21
34
55
89

Freddo. Mi chiedo solo perché non hai usato la base 2 come edc65 invece della base 3. Ciò ti avrebbe salvato dai duplicati. Suppongo sia perché gli zero iniziali probabilmente vengono troncati nel passaggio 3b. È giusto?
Level River St,

1
@steveverrill: Sì, questo è esattamente il motivo. Così com'è, gli zeri iniziali non corrispondono a nessun domino. Ma non avere duplicati mi permetterebbe di sostituire i tre blocchi con uno singolo. Dovrò pensarci ancora un po '.
Dennis,

@steveverrill: non sono riuscito a far funzionare la base 2, ma un approccio ricorsivo sembra essere ancora più breve.
Dennis,

2

JavaScript (E6) 102

Genera configurazioni da sequenze di bit, 0 -> '-' e 1 -> '|'.

F=n=>{
  for(i=0;(j=++i)<2<<n;s.length==1+n&&console.log('\n'+s+s))
    for(s='\n';j>1;j>>=1)s+=j&1?'|':'--';
}

Test nella console firefox / firebug

F(5)

Produzione

|----
|----

--|--
--|--

----|
----|

|||--
|||--

||--|
||--|

|--||
|--||

--|||
--|||

|||||
|||||

1

Haskell: 109 byte

Questa è una traduzione del noto one-liner Haskell per calcolare pigramente la sequenza dei numeri di Fibonacci:

b=map.map.(++)
w=zipWith
z=w(++)
s=["\n"]:["|\n"]:z(b"--"s)(b"|"$tail s)
f=sequence_.map putStrLn.(w z s s!!)

La sequenza principale di stringhe di piastrellatura, non rigata:

dominos = [""] : ["|"] : zipWith (++) ("--" `before` dominos) ("|" `before` tail dominos)
    where before = map . map . (++)

E il Fibonacci one-liner per il confronto:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Esempio di utilizzo:

$ ghci fibtile
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( fibtile.hs, interpreted )
Ok, modules loaded: Main.
*Main> f 5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

*Main>

1

Cobra - 176

Non vedo l'ora di aver finito il pacchetto golf Cobra.

def m(n)
    for t in.f(n),print t+t
def f(n,x='')as String*
    if x.length<n,for i in.f(n,x+'-').toList+.f(n,x+'|').toList,yield i
    else if not'-'in x.replace('--',''),yield x+'\n'

1

J - 54 caratteri

Funzione che assume ncome argomento a destra.

0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')

La radice principale di questo golf è il (];'--'&,"1@[,'|',"1])&>/. Questo prende un elenco di limiti di lunghezza (N-2) e (N-1) e restituisce un elenco di limiti di lunghezza (N-1) e N. Questa è la ricorrenza standard di Fibonacci, algebra lineare. ];restituisce l'elenco di destra come la nuova sinistra (in quanto non vi è alcuna modifica). '--'&,"1@[aggiunge --i riquadri all'elenco di sinistra, mentre '|',"1]aggiunge |i riquadri all'elenco di destra e quelli insieme sono il nuovo elenco di destra.

Lo ripetiamo nripetutamente (questo è il @[&0) e iniziamo con la piastrellatura vuota e la piastrellatura singola di lunghezza 1. Quindi restituiamo il primo della coppia con 0{::. Ciò significa che se lo eseguiamo zero volte, restituiamo solo la prima, ovvero la piastrellatura vuota. Se lo eseguiamo nvolte, calcoliamo fino alla coppia ne ( n+1), ma scartiamo quest'ultima. È un lavoro extra ma meno personaggi.

Il (1 2$,:)è qualcosa J deve fare in modo da rendere le tassellature nelle liste facilmente estendibile. Facciamo che l'elenco di partenza a sinistra sia un elenco di 1 elemento di una matrice di caratteri a 2 righe, ciascuna delle quali ha lunghezza 0. L'elenco di partenza destro è lo stesso, ma ha le righe della lunghezza 1, riempite |. Quindi, aggiungiamo le nuove tessere ad ogni riga e aggiungiamo gli elenchi di matrici quando uniamo le due serie di tasselli insieme. È una semplice applicazione di un concetto che J chiama rank: essenzialmente manipolando la dimensionalità dei suoi argomenti e implicitamente eseguendo il loop quando necessario.

   0{::(];'--'&,"1@[,'|',"1])&>/@[&0&((1 2$,:)&.>'';,'|')5
----|
----|

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

Provare per credere a tryj.tk .


1

Python 3: 70 byte

f=lambda n,s="\n":n>0and f(n-1,"|"+s)==f(n-2,"--"+s)or n or print(s*2)

Costruisce in modo ricorsivo tutte le stringhe possibili che srappresentano una riga di domino, che sono duplicate e stampate. A spartire dal carattere di nuova riga, la riga vuota si verifica automaticamente.

Il ==tra i due inviti fè solo di eseguire entrambe le chiamate di funzione. Questi di solito ritornano Noneperché sono appena stampati ed ==è uno dei pochi operatori definiti per None.

Gli ands e ors devono produrre il giusto comportamento di cortocircuito per riprodurre i ifs e elses del codice non golfato.

Ungolfed:

def f(n,s="\n"):
 if n==-1:pass
 elif n==0: print(s*2)
 else: f(n-1,"|"+s);f(n-2,"--"+s)

1

Retina , 44 byte

Nota: Retina è più giovane di questa sfida.

+`([-|]*)11(1*#)
$1|1$2$1--$2
1
|
.*?#
$0$0#

Riceve input in unario con una nuova riga finale.

Ogni riga dovrebbe andare nel proprio file e #dovrebbe essere cambiata in newline nel file. Ciò non è pratico, ma è possibile eseguire il codice come in un unico file con il -sflag, mantenendo i #marker (e modificando anche la nuova riga #nell'input). #Se lo si desidera, è possibile modificare la schiena in newline nell'output per la leggibilità. Per esempio:

> echo 1111# | retina -s fib_tile | tr # '\n'
||||
||||

||--
||--

|--|
|--|

--||
--||

----
----

Metodo:

  • Partendo dall'input scambiamo ogni riga con altre due: una con la prima 1modifica in |e una con le prime due 1cambiate in --. Lo facciamo fino a quando non abbiamo linee con almeno due 1.
  • Quando sono 1rimasti solo i single , li abbiamo cambiati in |.
  • Raddoppiamo ogni riga e aggiungiamo una nuova riga in più per ottenere l'output desiderato.

La nuova riga finale va bene.
xnor
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.