Ich habe diese Sequenz während der Arbeit an Evolution of OEIS gefunden , bin aber nie dazu gekommen, sie als Antwort zu veröffentlichen. Nachdem ich eine Referenzimplementierung in Mathematica geschrieben hatte, dachte ich, dass dies eine lustige Übung ist, die als separate Herausforderung zu tun ist.
Bauen wir einen numerischen Spaltreaktor! Betrachten Sie eine positive ganze Zahl N
. Als Beispiel schauen wir uns an 24
. Um diese Zahl zu spalten, müssen wir die größte Anzahl aufeinanderfolgender positiver Ganzzahlen finden, die sich summieren N
. In diesem Fall ist das so 7 + 8 + 9 = 24
. Also haben wir uns 24
in drei neue Zahlen aufgeteilt. Ohne Kettenreaktionen wäre dies jedoch kein großer Spaltreaktor. Wiederholen wir den Vorgang also rekursiv für diese Komponenten:
24
/|\
/ | \
/ | \
7 8 9
/ \ /|\
3 4 / | \
/ \ / | \
1 2 2 3 4
/ \
1 2
Beachten Sie, dass wir den Prozess anhalten, wenn die Zahl nicht in kleinere aufeinanderfolgende ganze Zahlen zerlegt werden kann. Beachten Sie auch, dass wir 9
als geschrieben haben könnten 4 + 5
, aber 2 + 3 + 4
mehr Komponenten hat. Die Spaltungszahl von N
ist nun definiert als die Anzahl der in diesem Prozess erhaltenen ganzen Zahlen, einschließlich sich N
selbst. Der obige Baum hat also 13 Knoten F(24) = 13
.
Diese Sequenz ist OEIS-Eintrag A256504 .
Die ersten 40 Begriffe beginnen N = 1
mit
1, 1, 3, 1, 5, 6, 5, 1, 6, 7, 12, 10, 12, 11, 12, 1, 8, 16, 14, 17, 18, 18,
23, 13, 21, 18, 22, 23, 24, 19, 14, 1, 22, 20, 23, 24, 31, 27, 25, 26
Die ersten 1000 Begriffe finden Sie in diesem Pastebin .
Die Herausforderung
N
Bestimmen Sie bei einer positiven Ganzzahl deren Fission-Nummer F(N)
. (Sie müssen also nicht die in 0
OEIS aufgeführten führenden Unternehmen abdecken .)
Sie können ein Programm oder eine Funktion schreiben, indem Sie eine Eingabe über STDIN (oder die nächstgelegene Alternative), ein Befehlszeilenargument oder ein Funktionsargument vornehmen und das Ergebnis über STDOUT (oder die nächstgelegene Alternative), einen Funktionsrückgabewert oder einen Funktionsparameter (out) ausgeben.
Dies ist Codegolf, daher gewinnt die kürzeste Antwort (in Bytes).
Bonusfrage: Können Sie interessante Eigenschaften dieser Sequenz finden?
quelle
Antworten:
Pyth,
232221 BytesDies definiert eine rekursive Funktion
y
. Probieren Sie es online aus: DemonstrationErläuterung:
quelle
Fission ,
1328989887797 BytesDiese Antwort ist etwas unangemessen lang (ich wünschte, wir hätten zusammenklappbare Regionen ) ... bitte vergiss nicht, darüber zu scrollen und den anderen Antworten etwas Liebe zu zeigen!
Die Arbeit an diesem Code hat diese Herausforderung inspiriert. Ich wollte EOEIS eine Antwort in Fission hinzufügen, was mich zu dieser Sequenz führte. Es dauerte jedoch ein paar Wochen, bis Fission tatsächlich erlernt und implementiert wurde. In der Zwischenzeit war die Sequenz wirklich auf mich gewachsen, sodass ich mich entschlossen habe, eine separate Herausforderung dafür zu stellen (außerdem wäre dies auf EOEIS sowieso nicht besonders weit unten im Baum gewesen).
Also präsentiere ich euch die Monstrosität:
Es wird erwartet, dass die Eingabe keinen nachgestellten Zeilenumbruch enthält, sodass Sie sie möglicherweise so aufrufen möchten
echo -n 120 | ./Fission oeis256504.fis
.Das Layout könnte wahrscheinlich noch effizienter sein, daher denke ich, dass es hier noch viel Raum für Verbesserungen gibt (zum Beispiel
911581461374 Plätze).Bevor wir zur Erklärung kommen, ein Hinweis zum Testen: Der offizielle Dolmetscher funktioniert nicht so, wie er ist. a)
Mirror.cpp
Kompiliert nicht auf vielen Systemen. Wenn Sie auf dieses Problem stoßen, kommentieren Sie einfach die betreffende Zeile aus - die betroffene Komponente (ein zufälliger Spiegel) wird in diesem Code nicht verwendet. b) Es gibt einige Fehler, die zu undefiniertem Verhalten führen können (und wahrscheinlich für ein Programm dieses Komplexes). Sie können diesen Patch anwenden , um sie zu beheben. Sobald Sie dies getan haben, sollten Sie in der Lage sein, den Interpreter mit zu kompilierenUnterhaltsame Tatsache: Dieses Programm verwendet fast alle Komponenten, die Fission zu bieten hat, mit Ausnahme von
#
(zufälliger Spiegelung),:
(halber Spiegelung)-
oder|
(einfacher Spiegelung) und"
(Druckmodus).Was in aller Welt?
Warnung: Dies wird ziemlich lange dauern ... Ich gehe davon aus, dass Sie wirklich interessiert sind, wie Fission funktioniert und wie man es programmieren könnte. Denn wenn nicht, bin ich mir nicht sicher, wie ich das möglicherweise zusammenfassen könnte. (Der nächste Absatz enthält jedoch eine allgemeine Beschreibung der Sprache.)
Fission ist eine zweidimensionale Programmiersprache, bei der sowohl Daten- als auch Steuerfluss durch Atome dargestellt werden , die sich durch ein Gitter bewegen. Wenn Sie Marbelous schon einmal gesehen oder verwendet haben , sollte das Konzept vage bekannt sein. Jedes Atom hat zwei ganzzahlige Eigenschaften: eine nicht negative Masse und eine beliebige Energie. Wenn die Masse jemals negativ wird, wird das Atom aus dem Gitter entfernt. In den meisten Fällen können Sie die Masse als "Wert" des Atoms und die Energie als eine Art Meta-Eigenschaft behandeln, die von mehreren Komponenten verwendet wird, um den Fluss der Atome zu bestimmen (dh die meisten Arten von Schaltern hängen vom Vorzeichen ab) die Energie). Ich werde Atome
(m,E)
bei Bedarf mit bezeichnen. Zu Beginn des Programms beginnt das Raster mit einer Reihe von(1,0)
Atome von jedem beliebigen Ort aus einer der vier KomponentenUDLR
(wobei der Buchstabe die Richtung angibt, in die sich das Atom anfangs bewegt). Die Platine wird dann mit einer ganzen Reihe von Komponenten bestückt, die die Masse und Energie von Atomen ändern, ihre Richtungen ändern oder andere anspruchsvollere Dinge tun. Eine vollständige Liste finden Sie auf der Esolangs-Seite. Die meisten davon stelle ich in dieser Erklärung vor. Ein weiterer wichtiger Punkt (von dem das Programm mehrmals Gebrauch macht) ist, dass das Gitter torisch ist: Ein Atom, das auf eine der Seiten auftrifft, erscheint auf der gegenüberliegenden Seite wieder und bewegt sich in die gleiche Richtung.Ich habe das Programm in mehreren kleineren Teilen geschrieben und diese am Ende zusammengestellt, so gehe ich die Erklärung durch.
atoi
Diese Komponente mag ziemlich uninteressant erscheinen, aber sie ist nett und einfach und ermöglicht es mir, viele wichtige Konzepte des Arithmetik- und Kontrollflusses von Fission vorzustellen. Daher werde ich diesen Teil sehr detailliert durchgehen, damit ich die anderen Teile auf die Einführung neuer Fission-Mechaniken und auf übergeordnete Komponenten beschränken kann, deren detaillierter Kontrollfluss Sie selbst nachvollziehen können sollten.
Fission kann nur Byte-Werte von einzelnen Zeichen lesen, nicht von ganzen Zahlen. Während das hier akzeptabel ist, dachte ich, während ich dabei war, könnte ich es richtig machen und tatsächliche Ganzzahlen auf STDIN analysieren. Hier ist der
atoi
Code:Zwei der wichtigsten Komponenten in Fission sind Spaltungs- und Fusionsreaktoren. Spaltreaktoren sind beliebige der
V^<>
(im obigen Code verwendeten<
und>
). Ein Spaltreaktor kann ein Atom speichern (indem er es in den Keil des Charakters schickt)(2,0)
. Wenn ein Atom die Spitze des Charakters trifft, werden zwei neue Atome an die Seiten geschickt. Ihre Masse wird bestimmt, indem die ankommende Masse durch die gespeicherte Masse dividiert wird (dh standardmäßig halbiert) - das linksgerichtete Atom erhält diesen Wert und das rechtsgerichtete Atom den Rest der Masse (dh die Masse bleibt in der Spaltung erhalten). . Beide ausgehenden Atome haben die ankommende Energie minusdie gespeicherte Energie. Das heißt, wir können Spaltungsreaktoren für die Arithmetik verwenden - sowohl für die Subtraktion als auch für die Division. Wenn ein Spaltreaktor von der Stelle getroffen wird, wird das Atom einfach diagonal reflektiert und bewegt sich dann in Richtung der Spitze des Charakters.Fusionsreaktoren sind beliebige
YA{}
(der oben genannte Code verwendetY
und{
). Ihre Funktion ist ähnlich: Sie können ein Atom speichern (Standardeinstellung(1,0)
) und wenn sie von der Spitze getroffen werden, werden zwei neue Atome an die Seiten geschickt. In diesem Fall sind die beiden Atome jedoch identisch, behalten immer die ankommende Energie bei und multiplizieren die ankommende Masse mit der gespeicherten Masse. Das heißt, der Fusionsreaktor dupliziert standardmäßig einfach jedes Atom, das auf seinen Scheitelpunkt trifft. Wenn Fusionsreaktoren von der Seite getroffen werden, sind sie etwas komplizierter: Das Atom ist es auchgespeichert (unabhängig vom anderen Speicher), bis ein Atom auf die gegenüberliegende Seite trifft. In diesem Fall wird ein neues Atom in Richtung des Apex freigesetzt, dessen Masse und Energie die Summe der beiden alten Atome ist. Wenn ein neues Atom auf die gleiche Seite trifft, bevor ein passendes Atom die gegenüberliegende Seite erreicht, wird das alte Atom einfach überschrieben. Mit Fusionsreaktoren können Addition und Multiplikation durchgeführt werden.Eine andere einfache Komponente, die ich aus dem Weg räumen möchte, ist
[
und]
die einfach die Richtung des Atoms nach rechts bzw. links setzt (unabhängig von der eingehenden Richtung). Die vertikalen Entsprechungen lautenM
(nach unten) undW
(nach oben), werden jedoch nicht für denatoi
Code verwendet.UDLR
wirken auch wieWM][
nach der Freisetzung ihrer ursprünglichen Atome.Wie auch immer, schauen wir uns den Code dort oben an. Das Programm beginnt mit 5 Atomen:
R
undL
am Boden erhalten einfach ihr Masseninkrement (mit+
)(10,0)
und werden dann in einer Spaltung bzw. einem Fusionsreaktor gespeichert. Wir werden diese Reaktoren verwenden, um den Base-10-Eingang zu analysieren.L
Masse in der oberen rechten Ecke wird dekrementiert (mit_
)(0,0)
und auf der Seite eines Fusionsreaktors gelagertY
. Dies dient dazu, die Zahl, die wir lesen, im Auge zu behalten. Diese Zahl wird schrittweise erhöht und multipliziert, wenn wir Zahlen lesen.R
Masse in der linken oberen Ecke wird auf den Zeichencode0
(48) mit gesetzt'0
, dann werden Masse und Energie mit getauscht@
und schließlich die Masse einmal mit erhöht+
, um zu geben(1,48)
. Es wird dann mit Diagonalspiegeln umgelenkt\
und/
in einem Spaltreaktor gelagert. Wir werden die48
for-Subtraktion verwenden, um die ASCII-Eingabe in die tatsächlichen Werte der Ziffern umzuwandeln. Wir mussten auch die Masse erhöhen,1
um eine Teilung durch zu vermeiden0
.U
linke untere Ecke alles in Bewegung und wird zunächst nur für den Kontrollfluss verwendet.Nach der Umleitung nach rechts trifft das Kontrollatom
?
. Dies ist die Eingabekomponente. Es liest ein Zeichen und setzt die Masse des Atoms auf den gelesenen ASCII-Wert und die Energie auf0
. Wenn wir stattdessen EOF drücken, wird die Energie auf eingestellt1
.Das Atom fährt fort und trifft dann
%
. Dies ist ein Spiegelschalter. Bei nicht positiver Energie wirkt dies wie ein/
Spiegel. Aber für positive Energie wirkt es wie ein\
(und dekrementiert die Energie auch um 1). Während wir die Zeichen lesen, wird das Atom nach oben reflektiert und wir können das Zeichen verarbeiten. Wenn wir mit der Eingabe fertig sind, wird das Atom nach unten reflektiert und wir können eine andere Logik anwenden, um das Ergebnis abzurufen. Zu Ihrer Information, die entgegengesetzte Komponente ist&
.Wir haben also vorerst ein Atom im Aufwind. Was wir für jedes Zeichen tun möchten, ist, seinen Ziffernwert zu lesen, diesen zu unserer laufenden Summe zu addieren und dann diese laufende Summe mit 10 zu multiplizieren, um sich auf die nächste Ziffer vorzubereiten.
Das Charakteratom trifft zuerst auf einen (Standard-) Fusionsreaktor
Y
. Dies teilt das Atom und wir verwenden die nach links gehende Kopie als Kontrollatom, um in die Eingabekomponente zurückzukehren und das nächste Zeichen zu lesen. Die rechtsgültige Kopie wird bearbeitet. Stellen Sie sich den Fall vor, in dem wir den Charakter gelesen haben3
. Unser Atom wird sein(51,0)
. Wir tauschen Masse und Energie mit@
, so dass wir die Subtraktion des nächsten Spaltreaktors nutzen können. Der Reaktor subtrahiert48
die Energie (ohne die Masse zu verändern) und sendet zwei Kopien davon aus(0,3)
- die Energie entspricht nun der gelesenen Ziffer. Die aufsteigende Kopie wird einfach mit verworfen;
(eine Komponente, die nur alle eingehenden Atome zerstört). Wir werden weiter mit der ausgehenden Kopie arbeiten. Sie müssen seinem Weg durch die folgen/
und\
spiegelt ein bisschen.Der
@
kurz vor dem Fusionsreaktor tauscht wieder Masse und Energie aus, so dass wir(3,0)
unsere laufende Summe in der ergänzenY
. Beachten Sie, dass die laufende Summe selbst immer0
Energie hat.Jetzt
J
ist ein Sprung. Was es tut, ist ein ankommendes Atom durch seine Energie nach vorne zu springen. Wenn es so ist0
, bewegt sich das Atom einfach weiter geradeaus. Wenn es1
so ist, überspringt es eine Zelle, wenn es so ist2
, überspringt es zwei Zellen und so weiter. Die Energie wird im Sprung verbraucht, so dass das Atom immer mit Energie endet0
. Da die laufende Summe keine Energie hat, wird der Sprung vorerst ignoriert und das Atom in den Fusionsreaktor umgeleitet, der{
seine Masse mit multipliziert10
. Die abgehende Kopie wird verworfen,;
während die abgehende KopieY
als neue laufende Summe in den Reaktor zurückgeführt wird.Das oben Gesagte wird so lange wiederholt (in einer lustigen Pipeline-Art und Weise, in der neue Ziffern verarbeitet werden, bevor die vorherigen fertig sind), bis wir EOF erreichen. Nun
%
wird das Atom nach unten gesendet. Die Idee ist, dieses Atom(0,1)
vor dem Auftreffen auf den laufenden Gesamtreaktor in ein Jetzt umzuwandeln, so dass a) die Gesamtmenge nicht beeinflusst wird (Nullmasse) und b) wir eine Energie erhalten,1
um über den Reaktor zu springen[
. Wir können uns leicht um die Energie kümmern, mit der die Energie$
inkrementiert wird.Das Problem ist, dass
?
die Masse nicht zurückgesetzt wird, wenn Sie EOF treffen, sodass die Masse immer noch die des zuletzt gelesenen Zeichens ist und die Energie0
(weil%
das1
Zurück zu dekrementiert wird0
). Also wollen wir diese Masse loswerden. Dazu tauschen wir wieder Masse und Energie aus@
.Ich brauche eine weitere Komponente einzuführen , bevor Sie diesen Abschnitt Finishing:
Z
. Dies ist im Wesentlichen dasselbe wie%
oder&
. Der Unterschied besteht darin, dass es Atome mit positiver Energie durchlässt (während es die Energie dekrementiert) und Atome mit nicht positiver Energie um 90 Grad nach links ablenkt. Wir können dies nutzen, um die Energie eines Atoms zu eliminieren, indem wir es immer wieder durchschleifenZ
- sobald die Energie weg ist, wird das Atom abgelenkt und verlässt die Schleife. Das ist dieses Muster:wo sich das Atom nach oben bewegt, sobald die Energie Null ist. Ich werde dieses Muster in der einen oder anderen Form mehrmals in den anderen Programmteilen verwenden.
Also , wenn das Atom diese kleine Schleife verlässt, wird es sein ,
(1,0)
und tauschte(0,1)
durch die@
vor den Fusionsreaktor trifft das Endergebnis der Eingang freizugeben. Die laufende Summe wird jedoch um den Faktor 10 verringert, da wir sie bereits für eine andere Ziffer vorläufig multipliziert haben.Jetzt mit Energie
1
wird dieses Atom das überspringen[
und in das springen/
. Dies lenkt es in einen Spaltreaktor um, den wir vorbereitet haben, um durch 10 zu teilen und unsere fremde Multiplikation zu fixieren. Wieder verwerfen wir die eine Hälfte mit;
und behalten die andere als Ausgabe (hier dargestellt, beiO
der einfach das entsprechende Zeichen gedruckt und das Atom zerstört wird - im vollständigen Programm verwenden wir stattdessen weiterhin das Atom).itoa
Natürlich müssen wir das Ergebnis auch wieder in einen String konvertieren und ausdrucken. Dafür ist dieser Teil da. Dies setzt voraus, dass die Eingabe nicht vor Tick 10 oder so eintrifft, sondern im vollständigen Programm, das leicht gegeben ist. Dieses Bit befindet sich am Ende des vollständigen Programms.
Dieser Code führt eine neue, sehr mächtige Fission-Komponente ein: den Stack
K
. Der Stapel ist anfangs leer. Wenn ein Atom mit nicht negativer Energie auf den Stapel trifft, wird das Atom einfach auf den Stapel geschoben. Wenn ein Atom mit negativer Energie auf den Stapel trifft, werden seine Masse und Energie durch das Atom auf der Oberseite des Stapels ersetzt (das dadurch abgesprungen ist). Ist der Stapel jedoch leer, kehrt sich die Richtung des Atoms um und seine Energie wird positiv (dh multipliziert mit-1
).Okay, zurück zum eigentlichen Code. Die Idee des
itoa
Snippets besteht darin, das Eingabemodul 10 wiederholt zu verwenden, um die nächste Ziffer zu finden, während die Eingabe für die nächste Iteration durch 10 geteilt wird. Dies ergibt alle Ziffern in umgekehrter Reihenfolge (von der niedrigsten zur höchsten). Um die Reihenfolge festzulegen, schieben wir alle Ziffern auf einen Stapel und ziehen sie am Ende einzeln ab, um sie zu drucken.Die obere Hälfte des Codes führt die
L
Ziffernberechnung durch : das mit den Pluszeichen gibt eine 10, die wir klonen und in eine Spaltung und einen Fusionsreaktor einspeisen, so dass wir teilen und mit 10 multiplizieren können. Die Schleife beginnt[
im Wesentlichen nach der in der oberen linken Ecke . Der aktuelle Wert wird geteilt: Eine Kopie wird durch 10 geteilt, dann mit 10 multipliziert und in einem Spaltreaktor gespeichert, der dann von der anderen Kopie am Scheitelpunkt getroffen wird. Dies berechneti % 10
alsi - ((i/10) * 10)
. Beachten Sie auch, dass dasA
Zwischenergebnis nach der Division und vor der Multiplikation aufgeteilt wird, sodass wiri / 10
in die nächste Iteration einspeisen können.Das
%
bricht die Schleife ab, sobald die Iterationsvariable 0 erreicht. Da dies mehr oder weniger eine do-while-Schleife ist, würde dieser Code sogar zum Drucken funktionieren0
(ohne ansonsten führende Nullen zu erzeugen). Sobald wir die Schleife verlassen, wollen wir den Stapel leeren und die Ziffern ausdrucken.S
ist das Gegenteil vonZ
, es ist also ein Schalter, der ein ankommendes Atom mit nicht positiver Energie um 90 Grad nach rechts ablenkt. Das Atom bewegt sich also tatsächlich über die Kante von derS
Geraden zurK
, um eine Ziffer auszublenden (beachten Sie~
, dass dies sicherstellt, dass das ankommende Atom Energie hat-1
). Diese Ziffer wird um erhöht48
, um den ASCII-Code des entsprechenden Ziffernzeichens zu erhalten. DasA
teilt die Ziffer, mit der eine Kopie gedruckt werden soll!
und geben Sie die andere KopieY
für die nächste Ziffer in den Reaktor zurück. Die gedruckte Kopie wird als nächster Auslöser für den Stapel verwendet (beachten Sie, dass die Spiegel sie auch um die Kante herum senden, um dieM
von links zu treffen ).Wenn der Stapel leer ist,
K
reflektiert der Wille das Atom und wandelt seine Energie in um+1
, so dass es direkt durch den Stapel läuftS
.N
druckt eine neue Zeile (nur weil es ordentlich ist :)). Und dann geht das AtomR'0
wieder durch und landet auf der Seite vonY
. Da es keine weiteren Atome gibt, wird dies niemals veröffentlicht und das Programm wird beendet.Berechnung der Spaltungsnummer: Das Framework
Kommen wir zum eigentlichen Fleisch des Programms. Der Code ist im Grunde ein Port meiner Mathematica-Referenzimplementierung:
wo
div
ist die Anzahl der ganzen Zahlen in der maximalen Partition.Die Hauptunterschiede bestehen darin, dass wir in Fission nicht mit halben Ganzzahlen umgehen können, also mache ich eine Menge Dinge, die mit zwei multipliziert werden, und dass es in Fission keine Rekursion gibt. Um dies zu umgehen, schiebe ich alle Ganzzahlen in einer Partition in eine Warteschlange, um sie später zu verarbeiten. Für jede Zahl, die wir verarbeiten, erhöhen wir einen Zähler um eins und sobald die Warteschlange leer ist, geben wir den Zähler frei und senden ihn zum Drucken ab. (Eine Warteschlange
Q
funktioniert genau soK
, nur in FIFO-Reihenfolge.)Hier ist ein Rahmen für dieses Konzept:
Die wichtigsten neuen Komponenten sind die Ziffern. Das sind Teleporter. Alle Teleporter mit der gleichen Ziffer gehören zusammen. Wenn ein Atom einen Teleporter trifft, bewegt es sofort den nächsten Teleporter in derselben Gruppe, wobei der nächste in der üblichen Reihenfolge von links nach rechts von oben nach unten bestimmt wird. Diese sind nicht notwendig, helfen aber beim Layouten (und damit ein bisschen Golfen). Es gibt auch das,
X
was ein Atom einfach dupliziert und eine Kopie geradeaus und die andere rückwärts sendet.Inzwischen können Sie möglicherweise den größten Teil des Frameworks selbst aussortieren. In der oberen linken Ecke befindet sich die Warteschlange mit den noch zu verarbeitenden Werten und wird einzeln freigegeben
n
. Eine Kopie vonn
wird nach unten teleportiert, weil wir sie für die Berechnung des Bereichs benötigen. Die andere Kopie wird in den oberen Block geschrieben, der berechnet wirddiv
(dies ist bei weitem der größte Abschnitt des Codes). Einmaldiv
berechnet, wird es dupliziert - eine Kopie erhöht einen Zähler in der oberen rechten Ecke, der in gespeichert istK
. Die andere Kopie wird nach unten teleportiert. Wenndiv
war1
, ablenken wir es nach oben sofort und verwenden Sie es als ein Auslöser für die nächste Iteration, ohne neue Werte Einreihen. Ansonsten verwenden wirdiv
undn
Klicken Sie im unteren Bereich auf, um den neuen Bereich (dh einen Strom von Atomen mit den entsprechenden Massen, die anschließend in die Warteschlange gestellt werden) zu generieren, und geben Sie dann einen neuen Auslöser frei, nachdem der Bereich abgeschlossen wurde.Sobald die Warteschlange leer ist, wird der Auslöser reflektiert, geht geradewegs durch die
S
und erscheint wieder in der oberen rechten Ecke, wo er den Zähler (das Endergebnis) freigibtA
, von dem er dann zuitoa
via teleportiert wird8
.Berechnung der Spaltungsnummer: The Loop Body
Sie müssen also nur noch die beiden Abschnitte berechnen
div
und den Bereich generieren. Computingdiv
ist dieser Teil:Sie haben jetzt wahrscheinlich genug gesehen, um dies mit etwas Geduld selbst herauszufinden. Die Aufschlüsselung auf hoher Ebene lautet wie folgt: Die ersten 12 Spalten oder so erzeugen einen Strom von Teilern von
2n
. Die nächsten 10 Spalten filtern diejenigen heraus, die nicht zufriedenstellenOddQ@# == IntegerQ[n/#]
. Die nächsten 8 Spalten filtern diejenigen heraus, die nicht zufriedenstellenn/# > (# - 1)/2)
. Schließlich schieben wir alle gültigen Divisoren auf einen Stapel, und sobald wir fertig sind, leeren wir den gesamten Stapel in einen Fusionsreaktor (überschreiben alle bis auf den letzten / größten Divisor) und geben dann das Ergebnis frei, gefolgt von der Eliminierung seiner Energie (die nicht vorhanden war) -zero von der Überprüfung der Ungleichung).Es gibt eine Menge verrückter Pfade, die eigentlich gar nichts bewirken. Überwiegend der
\/\/\/\/
Wahnsinn oben (die5
s sind auch Teil davon) und ein Pfad um den Boden (der durch das7
s führt). Ich musste diese hinzufügen, um mit einigen schlechten Rennbedingungen fertig zu werden. Fission könnte eine Verzögerungskomponente verwenden ...Der Code, aus dem der neue Bereich generiert wird, lautet
n
wiediv
folgt:Wir berechnen zuerst
n/div - (div + 1)/2
(beide Begriffe sind mit einem Floor versehen, was dasselbe Ergebnis ergibt) und speichern es für später. Dann generieren wir einen Bereich vondiv
unten bis1
und addieren den gespeicherten Wert zu jedem von ihnen.Es gibt zwei neue gemeinsame Muster in beiden, die ich erwähnen sollte: Eines ist
SX
oderZX
von unten getroffen (oder gedrehte Versionen). Dies ist eine gute Möglichkeit, ein Atom zu duplizieren, wenn Sie möchten, dass eine Kopie direkt weitergeleitet wird (da das Umleiten der Ausgänge eines Fusionsreaktors manchmal umständlich sein kann). DasS
oderZ
dreht das Atom in dasX
und dreht dann die gespiegelte Kopie zurück in die ursprüngliche Ausbreitungsrichtung.Das andere Muster ist
Wenn wir irgendeinen Wert in speichern, können
K
wir ihn wiederholt abrufen, indem wirK
mit negativer Energie von oben aufschlagen. DasA
dupliziert den Wert, an dem wir interessiert sind und sendet die Kopie direkt zurück auf den Stapel, damit wir sie das nächste Mal benötigen.Nun, das war ein ziemlicher Zeitvertreib ... aber wenn Sie es tatsächlich geschafft haben, dann haben Sie hoffentlich die Idee, dass Fission ein Problem für Sie darstellt
quelle
Now with 100% fewer scrollbars.
Also sagst du .. und es ist noch zu machen ...CJam,
4241 BytesEine einfache erste Durchquerung der Breite und ein Haltezustand des leeren nächsten Levels.
Wie es funktioniert :
Probieren Sie es hier online aus
quelle
Python 3, 112 Bytes
4 Bytes gespart dank @FryAmTheEggman.
Erklärung kommt später ...
Bonus-Fakt: Jede Potenz von 2 hat eine Fission-Nummer von 1. Dies liegt daran, dass die Summe einer Folge gerader Länge immer die Summe der beiden mittleren Zahlen ist, die ungerade ist, multipliziert mit der halben Länge der Folge, die ganzzahlig ist . Die Summe einer Sequenz ungerader Länge ist die mittlere Zahl multipliziert mit der Sequenzlänge, die ungerade ist. Da eine Potenz von 2 keinen ungeraden Teiler hat, kann sie nur als die Summe von sich selbst ausgedrückt werden.
quelle
Python 2,
11110297 BytesEtwas lesbar:
Nicht so lesbar:
Beide 97 Bytes.
b
ist dasn
Minus der(a-1)th
Dreieckszahl. Wenn jab % a == 0
, dannn
ist das die Summe dera
fortlaufenden Nummern abb
.quelle
1else
. Nur die 2. Lösung funktioniert. Erst mit Python 3else
kann eine Zahl unmittelbar folgen.Python 2, 86
Weniger golfen:
Die Idee ist, potenzielle Läufe von aufeinanderfolgenden ganzen Zahlen zu testen, die sich summieren
n
. Der Lauf wird direkt als SetR
und nicht über seine Endpunkte gespeichert .Wir prüfen anhand der
n
Differenz , wie die Summe des aktuellen Laufs mit der gewünschten Summe verglichen wird .f
dem Lauf zu, summieren und addieren 1 für den aktuellen Knoten. Wenn der Lauf ist{n}
, haben wir alle nicht trivialen möglichen Summen versucht, stoppen Sie die Rekursion, indem Sien
zuerst entfernen .Dank an Sp3000 für das Speichern von 3 Zeichen.
quelle
Python 2, 85
Ich bin sehr stolz auf diese Antwort, da es für n = 9 bereits zehn Sekunden und für n = 10 fünf bis zehn Minuten dauert. Im Codegolf wird dies als wünschenswertes Attribut eines Programms angesehen.
Es gibt auch eine Kurzschlussversion, die nicht so lange dauert und die gleiche Anzahl von Bytes verwendet:
Es kann schneller sein, überschreitet aber zumindest die Standard-Rekursionsgrenze, sobald n etwas über 40 liegt.
Die Idee ist es, eine Brute - Force - Suche nach Zahlen zu tun
a
undd
so , dassa + a+1 + ... + a+d == n
, auf Werte zwischen 1 undn
. Derf(n,a+d/n,d%n+1)
Zweig der Rekursion durchläuft die(a, d)
Paare. Für den Fall, dass die Gleichheit erfüllt ist, schaffe ich es, einen teurenmap(range(...))
Anruf zu vermeiden , indem ich mich in nur zwei Zweige aufteile, unabhängig davon, wie lang die Sequenz ist. Diea+1
durchgehenden Nummernd
werden zu einem Aufruf zusammengefasst,f
indem dera
Parameter so eingestellt wird, dass keine andere Methode zum Aufteilen der Sequenz verwendet werden kann.quelle
Haskell,
7669 BytesVerwendungszweck:
Wie es funktioniert:
quelle
Netzhaut , 66 Bytes
Übernimmt die Eingabe und druckt die Ausgabe in unary.
Sie können jede Zeile in eine einzelne Datei einfügen oder den Code so wie er ist mit dem
-s
Flag ausführen . Z.B:Erläuterung:
1
's) und konvertieren den Rest in1
' s.Die Zustände des Strings während des gesamten Prozesses mit Eingabe
11111111111111 (unary 14)
:Vielen Dank für @MartinButtner für die Hilfe im Chat!
quelle
CJam (43 Bytes)
Online-Demo
Ich bin sicher , dass ich mit den erweiterten Schleifen ein paar Tricks bin fehlt, aber das macht ausnutzen ordentlich die CJam Eigenschaft (die mir vorher geärgert hat) , dass im Inneren eine
%
Karte , um die Ergebnisse auf dem Stapel bleiben und daher zugegriffen werden kann unter Verwendung von$
mit einem negativer Offset.quelle
,
den Anfang brauchst du das nicht ./
und%
und einige andere verwandeln implizit Zahlen in Bereiche.,_m*
kann durch ersetzt werden2m*
. Die arithmetische Fortschrittsformel kann durch~,>:Y_,+:+
und ersetzt~\,>0\
werden!Y
. Wenn Sie{}#
statt verwenden{}=
, brauchen Sie das)
After nichtX
. Alles zusammen:ri{):X2m*{~,>:Y_,+:+X=}#!Y{~$+}/)}%W=
Los, 133 Bytes
Dies ist mein erster Code Golf, sorry wenn ich Fehler gemacht habe.
Dies basiert auf der Idee, dass die spaltbare "Zusammensetzung" auch als Unterschied zwischen zwei Folgen geordneter ganzer Zahlen angesehen werden kann. Nehmen Sie zum Beispiel die spaltbare "Komposition" für die Zahl 13. Sie ist 6,7. Aber es kann als die Summe der ganzen Zahlen 1 ... 7 minus der Summe der ganzen Zahlen 1 ... 5 gesehen werden
Erinnern Sie sich an die Formel aus Gauß 'Schultagen, Summe 1 ... n = (n ^ 2 + n) / 2. Um also eine Komposition sequentieller Ganzzahlen für ein gegebenes n zu finden, können wir auch sagen, wir suchen nach 'Endpunkten' p und q im Bereich 1 ... n, so dass (p ^ 2 + p) / 2 - ( q ^ 2 + q) / 2 = n. Im obigen Beispiel hätten wir nach 'Endpunkten' 5 und 7 gesucht, weil 7 ^ 2 + 7 = 56/2, 5 ^ 2 + 5 = 30/2, 56 / 2-30 / 2 = 28-15 = 13.
Nun gibt es mehrere Möglichkeiten, eine Zahl auf spaltbare Weise zusammenzusetzen, wie Martin feststellte: 9 = 2 + 3 + 4, aber auch 4 + 5. Es scheint jedoch offensichtlich, dass die "niedrigste" Startsequenz auch die längste sein wird, da sie länger dauert kleine Zahlen ergeben eine große Zahl als mittlere Zahlen. (Ich habe leider keinen Beweis)
Um die Zusammensetzung von 9 zu finden, testen Sie jedes 'Endpunktpaar', p und q, wobei Sie sowohl p als auch q getrennt von 0 bis 9 durchlaufen, und testen Sie, ob p ^ p + p / 2 - q ^ 2 + q / 2 = 9. Oder, einfacher gesagt, multiplizieren Sie die Gleichung mit 2, um die Divisionsthemen der Rundung zu vermeiden und die gesamte Mathematik in ganzen Zahlen zu halten. Dann suchen wir nach p und q, so dass (p ^ p + p) - (q ^ q + q) = 9 * 2 ist. Die erste Übereinstimmung, die wir finden, sind die Endpunkte der spaltbaren Zusammensetzung, da, wie bereits erwähnt, die niedrigste Gruppe von Zahlen auch die längste ist und wir von niedrig nach hoch suchen (0 bis 9). Wir brechen aus der Schleife aus, sobald wir eine Übereinstimmung finden.
Jetzt findet die rekursive Funktion die spaltbaren Endpunkte p und q für das gegebene n und ruft sich dann für jedes der Kinder im Baum von p bis q auf. Für 9 würde es 1 und 4 finden (20-2 = 18), dann würde es sich auf 2, 3 und 4 zurückrufen und die Ergebnisse aufsummieren. Bei Zahlen wie 4 findet es einfach keine Übereinstimmung und gibt daher '1' zurück. Dies kann verkürzt werden, entspricht jedoch meinem dritten Go-Programm und ich bin kein Rekursionsexperte.
Danke fürs Lesen.
quelle
CJam,
403533 BytesDanke an @Optimizer für den Vorschlag
few
, der 2 Bytes gespart hat.Probieren Sie es online im CJam-Interpreter aus .
Wie es funktioniert
quelle
ri{_,:)_few:+W%{1b1$=}=|{F}*}:F~],