Dies ist eine Tippfrage zum Golfen in Python bezüglich der Evil Numbers- Frage zu Anarchy Golf .
Eine Zahl ist böse, wenn ihre binäre Erweiterung eine gerade Zahl von 1 hat. Die Herausforderung besteht darin, die ersten 400 bösen Zahlen zu drucken 0,3,5,...,795,797,798
, eine pro Zeile.
Die Python 2-Einsendungen werden von llhuii mit einer 42-Byte-Lösung angeführt. Das nächstbeste sind 46 Bytes von Mitchs, gefolgt von fünf 47-Byte-Einsendungen. Es scheint, dass llhuii etwas wirklich Magisches gefunden hat, das vielen starken Python-Golfern über 2 Jahre lang entgangen ist. Das Speichern von 4 oder 5 Bytes ist für solch ein kurzes Golfspiel enorm.
Ich bin immer noch bei 47 Bytes. Ich hoffe, wir können dieses Puzzle als Community knacken. Wenn wir gemeinsam eine Antwort bekommen, würde ich sie unter den Namen aller einreichen, die dazu beigetragen haben. Eine Antwort auf diese Frage kann ein Stück Code oder eine neue Idee oder eine Analyse sein. Wenn Sie llhuii sind, verderben Sie es uns bitte noch nicht.
Obwohl Einsendungen nicht aufgedeckt werden, weil dieses Problem endlos ist, erhalten wir einige Hinweise. Die erfolgreiche Einreichung dauerte 0,1699 Sekunden, viel länger als jede andere, was auf eine ineffiziente Methode hindeutet. Aus der Bytestatistik sind von den 42 Zeichen 23 alphanumerisch [0-9A-Za-z]
und 19 ASCII-Symbole. Dies bedeutet, dass die Lösung von llhuii keine Leerzeichen enthält.
Sie können Ihren Code auf der Problemseite testen , indem Sie in der Dropdown-Liste "Sprache" die Option "Python" auswählen oder eine .py
Datei hochladen . Beachten Sie, dass:
- Python 2.7 wird verwendet
- Ihr Code muss ein vollständiges Programm sein, das gedruckt wird
- Es gibt keine Eingabe für dieses Problem, wie Kolmogorov-Komplexität
- Ihr Programm muss nur die 400 Werte wie angegeben ausgeben, auch wenn es bei größeren Werten abbrechen würde
- Programme müssen 2 Sekunden ausgeführt werden
- Programme werden möglicherweise mit einem Fehler beendet
- Sie können verwenden
exec
; Die Angabe "exec wird abgelehnt" bezieht sich auf die Shell exec
Antworten:
Dies ist nicht die gleiche Lösung wie die von llhuii, aber es ist auch 42 Byte lang.
Probieren Sie es online!
Dank @JonathanFrech sind wir jetzt bei 40 Bytes.
Probieren Sie es online!
Es muss noch ein Byte gespeichert werden, insgesamt 39.
Probieren Sie es online!
quelle
print+n
, muss ihre Lösung anders sein als meine.-
Zeichen möglicherweise durch Verschieben mitprint~n
oderprint-n
und Verwenden von&
oder zu entfernen~
, obwohl ich nichts zum Arbeiten bekommen habe. Auchn=0;exec"print n;d=n^n+2;n^=d^-d%3;"*400
ist hübsch, aber 40 Bytes.print-n
scheint unwahrscheinlich, da es keine einfache Beziehung zwischen den gesetzten Bits vonn
und gibt-n
.print~n
klingt in der Theorie vielversprechender, aber ich kann mit diesem Ansatz nicht unter 40 Bytes kommen.39 Bytes bekommen
Dies ist eine Erklärung, wie ich zu einer 39-Byte-Lösung gekommen bin, die Dennis und JonathanFrech ebenfalls separat gefunden haben. Oder vielmehr, es erklärt, wie man im Nachhinein zu der Antwort gelangen kann, und zwar auf eine Weise, die viel schöner ist als mein tatsächlicher Weg dahin, der voller schlammiger Überlegungen und Sackgassen war.
Wenn Sie dies etwas weniger golfen und mit mehr Parens schreiben, sieht das so aus:
Bitparitäten
Wir beginnen mit einer Idee von meiner 47-Byte - Lösung alle Zahlen der Form ausgeben ,
n=2*k+b
wok
aufwärts zählt,0,1,...,399
undb
ist ein Paritätsbit, das die Gesamtzahl von 1 macht , auch.Schreiben wir
par(x)
für die Bitparität vonx
, das ist das xor (^
) aller Bits inx
. Dies ist 0, wenn es eine gerade Anzahl von 1-Bits gibt (die Anzahl ist böse), und 1, wenn es eine ungerade Anzahl von 1-Bits gibt. Dennn=2*k+b
wir habenpar(n) = par(k)^b
, um das Böse zu erreichenpar(n)==0
, müssen wirb=par(k)
das letzte Bitn
der Bit-Parität der vorhergehenden Bits sein.Meine ersten Bemühungen um Golf waren die auf ausdrücken
par(k)
, zunächst direkt mitbin(k).count('1')%2
, und dann mit Bit - Manipulation .Paritätsaktualisierungen
Trotzdem schien es keinen kurzen Ausdruck zu geben. Stattdessen hat es geholfen zu erkennen, dass es mehr Informationen gibt, mit denen man arbeiten kann. Anstatt nur die Bit-Parität der aktuellen Zahl zu berechnen,
wir können die Bit - Parität aktualisieren , wie wir erhöhen
k
zuk+1
.Das heißt, da wir aufwärts zählen
k=0,1,2,...
, müssen wir nur die aktuelle Bitparität beibehalten, anstatt sie jedes Mal von Grund auf neu zu berechnen. Die Bitparitätsaktualisierungpar(k+1)^par(k)
ist die Parität der Anzahl von Bits, die beim Wechseln vonk
nachk+1
, dpar((k+1)^k)
. H., Gewechselt werden .Eine Form von
(k+1)^k
Jetzt müssen wir rechnen
par((k+1)^k)
. Es scheint, als hätten wir nichts erreicht, weil die Berechnung der Bit-Parität genau das Problem ist, das wir zu lösen versuchen. Zahlen, die als ausgedrückt werden,(k+1)^k
haben jedoch die Form1,3,7,15,..
, dh eine unter einer Potenz von 2, eine Tatsache, die häufig in Bit-Hacks verwendet wird . Mal sehen, warum das so ist.Wenn wir inkrementieren
k
, besteht der Effekt der binären Überträge darin, die letzten0
und alle1
nach rechts zu invertieren und eine neue Führung zu erzeugen,0
wenn keine vorhanden wäre. Nehmen wir zum Beispielk=43=0b101011
Die Spalten, die einen Übertrag verursachen, sind mit gekennzeichnet
*
. Diese haben eine1
Änderung von a0
und leiten ein Übertragsbit von weiter1
, das sich so lange nach links ausbreitet, bis es ein0
In trifftk
, das sich zu ändert1
. Etwaige Bits weiter links bleiben davon unberührt. Also, wennk^(k+1)
überprüft , welche Positionen ändern bißk
zuk+1
, findet er die Positionen der äußersten rechten0
und der1
‚s auf der rechten Seite . Das heißt, die geänderten Bits bilden ein Suffix. Das Ergebnis sind also Nullen, gefolgt von einer oder mehreren Einsen. Ohne die führenden Nullen gibt es Binärzahlen1, 11, 111, 1111, ...
, die unter einer Zweierpotenz liegen.Computing
par((k+1)^k)
Nun, da wir verstehen, dass dies auf
(k+1)^k
beschränkt ist1,3,7,15,...
, wollen wir einen Weg finden, die Bitparität solcher Zahlen zu berechnen. Hier ist eine nützliche Tatsache, dass1,2,4,8,16,...
abwechselnd modulo3
zwischen1
und2
, da2==-1 mod 3
. Also, unter1,3,7,15,31,63...
Modulo3
gibt1,0,1,0,1,0...
, was genau ihre Bit-Paritäten sind. Perfekt!So können wir das Update durchführen
par(k+1) = par(k) ^ par((k+1)^k)
alsUnter Verwendung
b
als Variable wir die Parität in sind speichern, das sieht aus wieCode schreiben
Setzen wir dies in Code zusammen, starten wir
k
und setzen das Paritätsbitb
beide auf0
, druckenn=2*k+b
und aktualisieren dann wiederholtb=b^((k+1)^k)%3
undk=k+1
.46 Bytes
Probieren Sie es online!
Wir haben Parens
k+1
in entfernt,((k+1)^k)%3
weil Python die Addition sowieso zuerst ausführt, komisch, wie es aussieht.Code Verbesserungen
Wir können es jedoch besser machen, indem wir direkt mit einer einzelnen Variablen arbeiten
n=2*k+b
und die Aktualisierungen direkt darauf durchführen. Tunk+=1
entsprichtn+=2
. Und die Aktualisierungb^=(k+1^k)%3
entsprichtn^=(k+1^k)%3
. Hierk=n/2
vor dem Updaten
.44 Bytes
Probieren Sie es online!
Wir können
n/2+1^n/2
dies(n/2+1)^n/2
durch Umschreiben verkürzen (denken Sie daran )Da
/2
das letzte Bit entfernt wird, spielt es keine Rolle, ob wir es vor oder nach dem xor-ing machen. Also haben wirn^=(n+2^n)/2%3
. Wir können ein weiteres Byte speichern mit der Feststellung , dass Modulo3
,/2
gleichwertig ist*2
äquivalent ist-
, unter Hinweis darauf , dassn+2^n
ist sogar so die Division ohne Boden tatsächliches Halbieren ist. Das gibtn^=-(n+2^n)%3
41 Bytes
Probieren Sie es online!
Schließlich können wir die Operationen
n^=c;n+=2
in kombinierenn=(n+2)^c
, woc
ein bisschen ist. Dies funktioniert, weil^c
nur das letzte Bit bearbeitet wird und das letzte Bit+2
nicht berücksichtigt wird, sodass die Operationen pendeln. Wieder lässt uns der Vorrang die Parens auslassen und schreibenn=n+2^c
.39 Bytes
Probieren Sie es online!
quelle
Dies gibt meine (xnor) 47-Byte-Lösung und das Denken, das mich dazu geführt hat. Lesen Sie dies nicht, wenn Sie dies selbst herausfinden möchten.
Eine natürliche erste Idee ist, durch die Zahlen 0 bis 799 zu iterieren und nur die mit einer geraden Zahl von Einsen im Binärformat zu drucken.
52 Bytes
Probieren Sie es online!
Hier
~
nimmt das Bit das Komplement, umeven<->odd
die Zählung einzuschalten und nur bei geraden Zählungen einen wahren Wert zu geben.Wir können diese Methode verbessern, indem wir alle Werte generieren, anstatt sie zu filtern. Beachten Sie, dass die Ausgabewerte die Zahlen 0 bis 399 sind, wobei jeweils ein Bit angehängt wird, um die Anzahl der 1-Bits gerade zu machen.
Also ist die
n
th Nummer entweder2*n+b
mit entwederb=0
oderb=1
. Das Bitb
kann durch Zählen1
in den Bits vonn
und Ermitteln des Zählmoduls 2 gefunden werden.49 Bytes
Probieren Sie es online!
Wir können die 2 Bytes
2*
durch Iteration kürzen0,2,4,...
, was die Anzahl der Bytes nicht verändert1
. Wir können dies tun, indem wir eineexec
Schleife verwenden, die 400-mal ausgeführt wird undn
jede Schleife um 2 erhöht .47 Bytes
Probieren Sie es online!
Und das ist meine 47-Byte-Lösung. Ich vermute die meisten, wenn nicht alle anderen 47-Byte-Lösungen gleich sind.
quelle
exec
Ansatz erlaubt?exec
sondern auf die Befehlszeileexec
.llhuii's Python 3 Einreichung
Hier sind die Python 3-Einreichungen für Evil Numbers zum Zeitpunkt des Schreibens:
llhuii hat ihren Trick wahrscheinlich auf Python 3 portiert und eine Lösung gefunden
Wenn wir xnors 47B buchstäblich nach Python 3 portieren, erhalten wir diese 50B:
Ich reichte es als
ppcg(xnor)
. (Es fügt Klammern zuexec
und hinzuprint
, die jetzt funktionieren.) Es hat andere Codestatistiken als die anderen Python 3-Antworten, in denen alle eine gewisse Menge an Leerzeichen enthalten sind. Interessant!Es gibt jedoch einen kürzeren Weg, es umzuschreiben (
exec
verliert in Python 3 tendenziell seinen Wettbewerbsvorteil):Es sind 49 Bytes. Ich reichte es als
ppcg(xnor,alternative)
. Dies hat zwei Bytes Leerzeichen, genau wie die Antwort von Llhui! Dies führt mich , dass llhuii Python 3 Antwort wie folgt aussieht irgendwie zu glauben (Newline, dann einewhile
so llhuii wahrscheinlich verwendet Schleife.)exec
In Python 2 undwhile
in Python 3, genau wie wir; Dies erklärt die Leerraum-Diskrepanz.Unsere 47B wurde in Python 3 zu einer 49B. Interessanterweise wurde die 42B von llhuii nicht zu einer 44B, sondern zu einer 45B! Irgendetwas an der Lösung von llhuii benötigt in Python 3 ein Byte mehr. Dies könnte eine Vielzahl von Dingen bedeuten.
Das erste , was in den Sinn kommt , ist Teilung : vielleicht llhuii verwendet
/
in Python 2, das wurde//
in Python 3. (Wenn sie zu zweit wie wir sind zu zählen, dannn/2
könnte zu verschieben verwendet werden ,n
um ein Bit nach rechts zurück?)Das andere, was mir einfällt, sind unäre Operatoren nach dem Druck . Unser
print blah
wurdeprint(blah)
(1 Byte extra), aber wenn llhuii so etwas wieprint~-blah
in Python 2 schrieb, würde esprint(~-blah)
in Python 3 werden.Vielleicht gibt es andere Ideen. Lass es mich wissen, bitte.
Codestatistik für alle Py3-Lösungen, einschließlich meiner jetzt:
quelle
Andere Ansätze
1) Verwenden einer Formel für A001969
Anstatt in eine Binärdatei zu konvertieren, kann möglicherweise die folgende Formel (aus OEIS ) verwendet werden:
Ich bin sehr schlecht im Golfspielen in Python, also werde ich es nicht einmal versuchen. Aber hier ist ein kurzer Versuch in JS.
NB: Ich glaube nicht, dass es sich um eine gültige JS-Übermittlung handelt, da sie nur ein Array ausfüllt, ohne es anzuzeigen. Und trotzdem ist es 5 Bytes länger als die derzeit beste JS-Lösung (das sind 45 Bytes). Aber darum geht es hier sowieso nicht.
Code-Snippet anzeigen
Hoffentlich kann es etwas Inspiration geben.
Die Verwendung eines Arrays ist wahrscheinlich keine gute Idee, da es initialisiert und aktualisiert werden muss. Es ist möglicherweise effizienter (in Bezug auf die Codegröße), stattdessen eine rekursive Funktion zu verwenden. Dies würde erklären, warum die erfolgreiche Lösung mehr Zeit in Anspruch nimmt als die anderen.
2) Aufbau der Thue-Morse-Sequenz mit Substitutionen
Theoretisch sollte dieser Code funktionieren:
Probieren Sie es online! (lauffähige Version auf 20 Begriffe begrenzt)
Es berechnet die Thue-Morse-Sequenz mit aufeinanderfolgenden Substitutionen und sucht nach der Position von Einsen (Evil Numbers) in derselben Schleife.
Aber:
3) Erstellen der Thue-Morse-Sequenz mit bitweisen Operationen
Ausgehend von Wikipedia's Direct Definition der Thue-Morse-Sequenz bin ich zu diesem Algorithmus gekommen (zurück zu JS ... sorry):
Dabei verfolgen wir die aktuelle Bösartigkeit der Sequenz in e und verwenden 170 als Bitmaske ungerader Bits in einem Byte.
quelle
f=lambda n:_
for n in range(400):print f(n)
braucht bereits 43 Bytes. Vielleicht gibt es eine Möglichkeit, die Rekursion zu simulieren, indem Sie ein Array erstellen, das auf sich selbst verweist, oder ein Array, das dem Ende zukünftige Elemente hinzufügt.def
,for
,while
,lambda
(mit einem Parameter zumindest) usw.while~0:print~1
benötigt keine Leerzeichen.((x=n++^n)^x/2)
Scheint in Methode Nummer 3 etwas wortreich zu sein, nur um das niedrigste gesetzte Bit zu finden. Das ganze Durcheinander kann durch ersetzt werden++n&-n
. Probieren Sie es online!Annäherung verschachtelter Zähler
Ich habe eine Idee für eine andere Herangehensweise, aber ich habe nicht genug Erfahrung mit Python-Golfen, daher überlasse ich es euch hier, um sie als einen weiteren möglichen Ausgangspunkt für das Golfen zu betrachten.
Die ungolfed Idee:
Probieren Sie es online!
Neun Ebenen Schachtelungstiefe, alle Schleifen sind gleich, daher sollten sie meiner Meinung nach von gebaut werden
exec"something"*9+"deepest stuff"
. In der Praxis weiß ich nicht, ob es möglich ist, so etwas mit einem for-Zyklus zu machen.Dinge, die Sie beim Golfen beachten sollten:
Vielleicht gibt es eine andere Möglichkeit, zweimal zu wechseln als eine for-Schleife (ich habe versucht, einen quine-ähnlichen Ansatz zu verwenden, bei dem der String zweimal als Formatierungsargument an sich selbst übergeben wurde, aber mein Kopf explodierte).
Es könnte auch eine bessere Alternative zu geben
if n<800:
, die hier benötigt wird, da wir sonst weiterhin böse Zahlen bis zu 2 ^ 10 ausgeben würdenquelle
print
ist eine Anweisung keine Funktion und kann daher nicht in einem Verständnis vorkommen.print '\n'.join([[[[[[[[[foo]foo]foo]foo]foo]foo]foo]foo]foo])
str.join
Funktioniert nur mit Listen, die Zeichenfolgen enthalten, und die zusätzlichen Listenzeichen dürfen nicht gedruckt werden. Das Formatieren allein würde eine erhebliche Menge an Bytes erfordern.Idee: Kürzere Bit-Parität
Es sind viele Zeichen erforderlich
bin(n).count('1')%2
, um die Parität der Bitanzahl zu berechnen. Möglicherweise ist eine arithmetische Methode kürzer, insbesondere bei einer begrenzten Bitlänge.Eine nette Methode gleicher Länge ist
int(bin(n)[2:],3)%2
, den Binärwert als Basis3
(oder irgendeine ungerade Basis) zu interpretieren . Leider müssen 4 der Bytes das0b
Präfix entfernen . Es funktioniert auchint(bin(n)[2:])%9%2
.Eine andere Idee ergibt sich aus der Kombination von Bits mit xor. Wenn
n
binäre Darstellung hatabcdefghi
, dannAlso,
r=n/16^n%16
ist böse , wenn und nur wenn dasn
Böse ist. Wir können dann wiederholen , dass alss=r/4^r%4
ein Werts
in0,1,2,3
, von denen1
und2
ist nicht böse, überprüfbar mit0<s<3
.52 Bytes
Probieren Sie es online!
Dies stellte sich viel länger heraus. Es gibt jedoch viele Drehknöpfe, um die Nummer zu teilen und die endgültige Nummer zu überprüfen (möglicherweise eine bitbasierte Nachschlagetabelle). Ich vermute, dass diese nur so weit gehen können.
quelle
to_bytes
Funktion von ganzen Zahlen zu verwenden? Ich bezweifle es aber etwas zu beachten :)0b
:int(bin(n),13)%2
! : Dn=0;exec"print~int(bin(n),13)%2+n;n+=2;"*400
Konstruktionsbedingt
n+n^n
ist es immer böse, aber meine schlechten Python-Kenntnisse konnten nur mit einer 61-Byte-Lösung aufwarten:Dank an @Peilonrayz für das Speichern von 5 Bytes und @ Mr.Xcoder für das Speichern von 1 Byte:
quelle
for n in sorted(n^n*2for n in range(512))[:400]:print n
.n+n^n
ist das gleiche wien^n*2
Idee: A006068 ("a (n) ist grau in n codiert")
Neils Idee, alles zu sortieren,
2n XOR n
faszinierte mich, also versuchte ich, die Indizes hinter dieser Art zu finden. Ich habe diesen Code geschrieben und es zeigt sich, dass wir so etwas schreiben können:Wo
a(n)
ist A006068 (n). Probieren Sie es online!Dies setzt jedoch voraus, dass wir einen kurzen Weg zur Berechnung von A006068 haben. Dies sind bereits 38 Bytes, vorausgesetzt, wir können es in 4 Bytes (dem
a(n)
Teil) berechnen . Die eigentliche Implementierung (im TIO-Header) ist weitaus länger. Ich denke nicht viel Hoffnung dafür.quelle
Idee: Über XOR reduzieren
Wenn Sie alle Teile
n
zusammen XOR , wird es0
für das Böse und1
für das Nicht-Böse sein. Sie können dies mit einer rekursiven Funktion tun (die möglicherweise mehr Zeit in Anspruch genommen hat?):Dies gibt 1 für das Böse zurück.
Das sind 35 Bytes und prüft, ob eine Zahl böse ist oder nicht. Leider sind
filter
es schon 6 Bytes, also war dies nicht die optimale Lösung, aber diese Idee kann wahrscheinlich golfen werden.quelle
f=lambda n:n>1and f(n/2^n&1)or-~-n
für -1 Byte tun .f(n/2^n&1)
0 zurückgibt ...Ersetzungsmethode: {1 -> {1, -1}, -1 -> {-1, 1}}
Sie können diese Ersetzung auch 10 Mal vornehmen {1 -> {1, -1}, -1 -> {-1, 1}}, dann die Positionen der Einsen reduzieren und überprüfen
Hier ist der Mathematica-Code
quelle