Fibonacci Domino Fliesen

11

Es gibt ein klassisches kombinatorisches Ergebnis, dass die Anzahl der Möglichkeiten, einen 2*nStreifen mit 1*2Dominosteinen zu kacheln, die n- te Fibonacci-Zahl ist. Ihr Ziel ist es, alle Kacheln für eine bestimmte zu drucken n, gezeichnet mit Strichen und vertikalen Linien wie diese 8 Kacheln für n=5:

|————
|————

——|——
——|——

|||——
|||——

————|
————|

||——|
||——|

|——||
|——||

——|||
——|||

|||||
|||||

Sie müssen ein Programm oder eine benannte Funktion bereitstellen, die nals Eingabe verwendet und die erforderliche Ausgabe druckt. Wenig Bytes gewinnen.

Eingang

Eine Zahl nzwischen 1und 10einschließlich über STDIN oder Funktionseingang.

Ausgabe

Drucken Sie alle möglichen Domino-Kacheln des 2*nStreifens horizontal gezeichnet. Die Fliesen können in beliebiger Reihenfolge sein, aber jede sollte genau einmal erscheinen. Sie müssen durch eine Leerzeile getrennt werden.

Ein vertikaler Domino besteht aus zwei vertikalen Balken ( |) und ein horizontaler Domino besteht aus zwei Strichen ( ). Sie können Bindestriche ( -) anstelle von Bindestrichen verwenden, um in ASCII zu bleiben.

Sie können mit Leerzeichen alles tun, solange die gedruckte Ausgabe gleich aussieht.

xnor
quelle
Würde ein zusätzlicher Zeilenvorschub nach dem letzten Kacheln unter irgendetwas mit Leerzeichen fallen ?
Dennis
@ Tennis Ja, extra leere Zeilen sind in Ordnung.
xnor
Ich bin wirklich überrascht, so viele verschiedene Ansätze zur Lösung des gleichen Problems zu sehen. Hast du das erwartet?
Level River St
@steveverrill Nein, ich habe es total nicht getan und freue mich, die Vielfalt zu sehen! Und deine nimmt den Kuchen für Unerwartetes. Ich dachte hauptsächlich an eine Rekursion im Fibonacci-Stil, da die meisten verwendeten Lösungen von mir verwendet wurden. Ich hatte nicht erwartet, dass das Filtern effektiv sein würde, und in dem Maße, in dem ich es tat, dachte ich, es würde Zeichenfolgen von ——und |nach Länge wie bei Dennis filtern , nicht Längenfolgen nvon und |gefiltert durch paarweises Erscheinen. Und für letzteres würde ich erwarten, dass es über reguläre Ausdrücke oder Zeichenfolgenoperationen für die erzeugte Zeichenfolge erfolgt, wie s.split('——) `, nicht durch einen arithmetischen Ansatz wie Ihren.
xnor
Ich denke "1x2 Dominosteine" ist überflüssig.
SuperJedi224

Antworten:

5

C 106

Golfversion

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;
}

Originalfassung

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");
  }
}

Wie es funktioniert

Die Variable iläuft von 1<<n-1bis 0 und erzeugt alle möglichen Binärzahlen mit nZiffern. 0 codiert für |und 1 codiert für -. Wir sind an Zahlen interessiert, die paarweise Einsen enthalten. Offensichtlich sind solche Zahlen durch 3 teilbar.

Wenn eine Zahl durch 3 geteilt wird, kann die ursprüngliche Zahl wiederhergestellt werden, indem das Ergebnis mit 2 multipliziert und zu sich selbst addiert wird (effektiv mit 3 multipliziert). Die meisten Zahlen erfordern einen Übertrag, aber wenn der Prozess mit den Zahlen von ausgeführt wird Interesse ist kein Carry erforderlich, daher kann OR nur in diesen Fällen anstelle von Addition verwendet werden. Dies wird verwendet, um die interessierenden Zahlen zu testen, da sie die einzigen sind, bei denen der Ausdruck i/3|i/3*2den ursprünglichen Wert von zurückgibt i. Siehe Beispiel unten.

1111= 15 ---> 0101= 5 ---> 1111= 15 (gültig, 0101|1010== 0101+1010)

1001= 9 ---> 0011= 3 ---> 0111= 7 (ungültig , 0011|0110! = 0011+0110)

Der Testwert ist immer gleich oder kleiner als der ursprüngliche Wert. Da Zahlen, die keine Vielfachen von 3 sind, auch eine Zahl zurückgeben, die kleiner als das Original ist, wenn sie durch 3 geteilt und dann mit 3 multipliziert werden, ergibt der Test auch für diese Zahlen die gewünschte FALSCH.

In der Originalversion werden einige Schleifen jverwendet, um die Bits von zu durchsuchen iund die Ausgabe zu erzeugen. In der Golfversion wird eine einzelne forSchleife verwendet, in der halle Zahlen von (n*2)*(1<<n)-1bis 0 durchlaufen werden. Werte von iwerden von generiert h/2/n. Die Variable jwird nicht mehr verwendet, da die äquivalente Menge von erhalten wird h%n. Durch die Verwendung von n*2können beide Zeilen aus derselben Schleife gedruckt werden, wobei in der putsAnweisung ein geschicktes Multiplexen erfolgt , um entweder eine oder zwei Zeilenumbrüche am Ende der Zeile zu drucken.

Beachten Sie, dass sich das Fleisch davon in der Inkrementposition der for()Klammer befindet und daher nach dem ausgeführt wird i=h/2/h.

Beispielausgabe n = 6:

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

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

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

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

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

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

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

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

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

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

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

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

||||||
||||||
Level River St.
quelle
Der i/3|i/3*2Trick ist genial! Ich habe keinen arithmetischen Ausdruck für die Grammatik erwartet.
xnor
3

CJam, 33 27 Bytes

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

Vielen Dank an @ jimmy23013 für das Golfen von 6 Bytes!

Probieren Sie es online aus!

Hintergrund

Dies ist eine iterative Implementierung eines rekursiven Algorithmus:

Die möglichen Kacheln für n können erhalten werden, indem ein vertikaler Dominostein zu den möglichen Kacheln für n - 1 und zwei horizontale Dominosteine ​​zu den möglichen Kacheln für n - 2 hinzugefügt werden .

Auf diese Weise ist die Anzahl der Kacheln für n die Summe der Anzahl der Kacheln für n - 1 und n - 2 , dh die n- te Fibonacci-Zahl.

Wie es funktioniert

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'                ";

Beispiellauf

$ 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
Dennis
quelle
LNli{_'|f\@"——"f\+2/}*\;{_N}/.
Jimmy23013
f\war noch nicht in 0.6.2 implementiert, aber ich konnte unsere Ansätze kombinieren. Vielen Dank!
Dennis
2

Haskell, 89 Bytes

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

fist eine Funktion, die bei gegebener Zahl eine Liste mit einer Zeile aller möglichen Fibonacci-Kacheln der Länge n zurückgibt. Es spielt keine Rolle, dass eine Zeile zurückgegeben wird, da beide Zeilen aller Kacheln gleich sind.

fWerke von rekursiv auf Aufruf n-1und n-2und das Hinzufügen "|"und "--"(jeweils) zu den Saiten.

gist die Funktion, die die Fragen beantwortet. Grundsätzlich ruft es fdie Eingabe auf, verdoppelt jede Zeichenfolge, sodass zwei Zeilen angezeigt werden, und verbindet sie alle durch Zeilenumbrüche.

Beispielausgabe:

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

|||--
|||--

||--|
||--|

|--||
|--||

|----
|----

--|||
--|||

--|--
--|--

----|
----|
stolzer haskeller
quelle
2

CJam, 42 37 Bytes

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

Ich habe die Striche jeweils als ein Byte gezählt, da die Frage es ermöglicht, sie durch ASCII-Bindestriche zu ersetzen.

Probieren Sie es online aus.

Wie es funktioniert

Um alle möglichen Kacheln von 2 × L zu erhalten , iterieren wir über alle nicht negativen ganzen Zahlen I <3 L , wobei gerade Ziffern in Basis 3 horizontalen Dominos und ungerade Ziffern vertikalen entsprechen.

Da jeder I hat L oder weniger Stellen in der Basis 3 erzeugt diese alle Möglichkeiten des Bedeckens der 2 × L - Streifen. Sie müssen lediglich die Abdeckungen herausfiltern, die größer oder kleiner als 2 × L sind, und die verbleibenden Abdeckungen drucken.

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'.           ";

Beispiellauf

$ 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
Dennis
quelle
Cool. Ich frage mich nur, warum Sie nicht Base 2 wie edc65 anstelle von Base 3 verwendet haben. Das hätte Sie vor Duplikaten bewahrt. Ich nehme an, das liegt daran, dass führende Nullen im Schritt wahrscheinlich abgeschnitten werden 3b. Ist das richtig?
Level River St
1
@steveverrill: Ja, genau das ist der Grund. Führende Nullen entsprechen sozusagen keinem Domino. Aber wenn ich keine Duplikate habe, kann ich die drei Blöcke durch einen einzigen ersetzen. Ich muss noch etwas darüber nachdenken.
Dennis
@steveverrill: Ich habe es nicht geschafft, Base 2 zum Laufen zu bringen, aber ein rekursiver Ansatz scheint noch kürzer zu sein.
Dennis
2

JavaScript (E6) 102

Generieren Sie Konfigurationen aus den Bitfolgen 0 -> '-' und 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 In der Firefox / Firebug-Konsole

F(5)

Ausgabe

|----
|----

--|--
--|--

----|
----|

|||--
|||--

||--|
||--|

|--||
|--||

--|||
--|||

|||||
|||||
edc65
quelle
1

Haskell: 109 Bytes

Dies ist eine Übersetzung des bekannten Haskell-Einzeilers zur trägen Berechnung der Folge von Fibonacci-Zahlen:

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

Die Hauptsequenz der Kacheln von Saiten, ungolfed:

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

Und der Fibonacci-Einzeiler zum Vergleich:

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

Anwendungsbeispiel:

$ 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>
Matt Noonan
quelle
1

Cobra - 176

Ich kann es kaum erwarten, bis ich das Cobra-Golfpaket abgeschlossen habe.

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'
Οurous
quelle
1

J - 54 char

Funktion nals Argument auf der rechten Seite.

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

Die Hauptwurzel dieses Golfs ist die (];'--'&,"1@[,'|',"1])&>/. Dies führt eine Liste der Kacheln der Länge (N-2) und (N-1) und gibt eine Liste der Kacheln der Länge (N-1) und N zurück. Dies ist die Standard-Fibonacci-Wiederholung à la lineare Algebra. ];Gibt die rechte Liste als neue linke zurück (da keine Änderung erfolgt). '--'&,"1@[Fügt --der linken Liste Kacheln '|',"1]hinzu , während |der rechten Liste Kacheln hinzugefügt werden, und diese zusammen bilden die neue rechte Liste.

Wir wiederholen das immer und immer wieder n(das ist das @[&0) und beginnen mit der leeren Kachelung und der einzelnen Kachelung der Länge 1. Dann geben wir die erste des Paares mit zurück 0{::. Das heißt, wenn wir es null Mal ausführen, geben wir nur das erste zurück, dh die leere Kachelung. Wenn wir es nmal ausführen , berechnen wir bis zum nund ( n+1) Paar, verwerfen aber das letztere. Es ist zusätzliche Arbeit, aber weniger Charaktere.

Das (1 2$,:)ist etwas, was J tun muss, um die Kacheln in den Listen leicht erweiterbar zu machen. Wir machen die linke Startliste zu einer 1-Element-Liste einer 2-Zeilen-Matrix von Zeichen, wobei jede Zeile die Länge 0 hat. Die rechte Startliste ist dieselbe, aber die Zeilen haben die Länge 1, gefüllt mit |. Dann fügen wir jeder Zeile die neuen Kacheln hinzu und hängen die Matrizenlisten an, wenn wir die beiden Kachelsätze zusammenfügen. Es ist eine einfache Anwendung eines Konzepts, das J als Rang bezeichnet: im Wesentlichen die Dimensionalität seiner Argumente zu manipulieren und bei Bedarf implizit eine Schleife durchzuführen.

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

--|--
--|--

--|||
--|||

|----
|----

|--||
|--||

||--|
||--|

|||--
|||--

|||||
|||||

Probieren Sie es selbst bei tryj.tk aus .

Algorithmushai
quelle
1

Python 3: 70 Bytes

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

Erstellt rekursiv alle möglichen Zeichenfolgen, sdie eine Reihe von Dominosteinen darstellen, die dupliziert und gedruckt werden. Beginnend sals Newline - Zeichen macht die Leerzeile automatisch.

Der ==zwischen den beiden Aufrufen fbesteht lediglich darin, beide Funktionsaufrufe auszuführen. Diese werden normalerweise zurückgegeben, Noneweil sie nur gedruckt werden und ==einer der wenigen Operatoren sind, für die sie definiert sind None.

Die ands und ors sollen das richtige Kurzschlussverhalten erzeugen, um die ifs und elses des ungolfed Codes zu reproduzieren .

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)
xnor
quelle
1

Netzhaut , 44 Bytes

Hinweis: Die Netzhaut ist jünger als diese Herausforderung.

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

Übernimmt die Eingabe unary mit einem nachgestellten Zeilenumbruch.

Jede Zeile sollte in eine eigene Datei gehen und #in der Datei in eine neue Zeile geändert werden. Dies ist unpraktisch, aber Sie können den Code wie eine Datei mit dem -sFlag #ausführen , wobei die Markierungen beibehalten werden (und die neue Zeile auch #in der Eingabe geändert wird). #Wenn Sie möchten, können Sie die 's wieder in Zeilenumbrüche in der Ausgabe ändern, um die Lesbarkeit zu verbessern. Z.B:

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

||--
||--

|--|
|--|

--||
--||

----
----

Methode:

  • Ausgehend von der Eingabe tauschen wir jede Zeile gegen zwei andere aus: eine mit der ersten 1Änderung an |und eine mit den ersten beiden 1Änderungen an --. Wir machen das so lange, bis wir Linien mit mindestens zwei haben 1.
  • Wenn nur noch einzelne 1übrig sind, haben wir diese in geändert |.
  • Wir verdoppeln jede Zeile und fügen eine zusätzliche neue Zeile hinzu, um die gewünschte Ausgabe zu erhalten.
randomra
quelle
Nachgestellte Newline ist in Ordnung.
xnor