Tipps zum Golfen in GolfScript

35

Was, dieser Beitrag existiert noch nicht?

Natürlich GolfScript ist gemacht für Golf, so dass Sie , dass keine konkreten Tipps vielleicht denken wirklich benötigt werden. Um die Funktionen von GolfScript voll ausnutzen zu können, müssen Sie einige nicht offensichtliche Tricks lernen. In diesem Beitrag werden hilfreiche Tipps und Tricks gesammelt.

Zunächst finden Sie hier die offiziellen GolfScript-Referenzseiten. Sie sollten sich zuerst mit den folgenden Themen vertraut machen:

Insbesondere würde ich sehr empfehlen, die Seiten in dieser Reihenfolge zu lesen - die Kurzanleitung ist von geringem Nutzen, bis Sie mit den integrierten Funktionen bereits einigermaßen vertraut sind, und das Lernprogramm enthält einige wichtige Details, die auf den anderen Seiten nicht erläutert werden .


Ps. Aus Gründen der Inspiration und des persönlichen Interesses sind hier einige Fragen, auf die ich gern nette Antworten hätte:

  • Wie kann ich in GolfScript eine begrenzte Transliteration durchführen? {FROM?TO=}%funktioniert, wenn Sie sicher sein können, dass alle Eingaben in gefunden wurden FROM(oder nicht, dass sie alle dem letzten Element von zugeordnet wurden TO), aber alle Möglichkeiten, die ich gesehen habe, um nicht zugeordnete Werte unverändert zu lassen, mehr oder weniger klug waren.

  • Wie konvertiere ich einen String am besten in ein Array von ASCII-Codes und zurück? Welche Operationen machen das als Nebeneffekt? Wie lassen sich die Zeichen in einer Zeichenfolge am besten auf dem Stapel ablegen (wie ~bei Arrays)?

Ilmari Karonen
quelle
Eine andere Frage: Gibt es einen schönen Weg, sich ... xin etwas zu verwandeln ... [x]? Das Beste, was ich sehen kann, ist [.;].
Peter Taylor
@Peter: Wenn xes sich um eine Zahl handelt, []+funktioniert sie und ist ein Zeichen kürzer. Und natürlich, wenn xdas einzige auf dem Stapel ist, dann reicht es einfach ].
Ilmari Karonen,
Ich möchte nach den besten Möglichkeiten fragen: min, max und absoluter Wert. Alle meine Lösungen scheinen viel mehr Charaktere zu haben, als sie sollten.
Claudiu
Wie kann ein Array an einem bestimmten Index am besten geändert werden?
user1502040
@ user1502040: Wird unten beantwortet. (Wenn jemand einen besseren Weg kennt, bitte teilen!)
Ilmari Karonen

Antworten:

29

Rational / Float / Komplex

Ich habe so oft gelesen, dass GolfScript nur Ganzzahlen enthält, die ich zu glauben begann. Nun, das stimmt nicht.

2-1? # Raise 2 to the power of -1. Result: 0.5
4-1? # Raise 4 to the power of -1. Result: 0.25
+    # Add. Result: 0.75

Die Ausgabe ist

3/4

mit dem Standard GolfScript Interpreter und

0.75

auf Web GolfScript .

Ähnliche Hacks ermöglichen das Casting in Rational, Float oder sogar Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex
Dennis
quelle
9
OMGWTFHAX o_O !!!
Ilmari Karonen
3
WAT! Ich
bin
3
Zeile 82 des jüngsten Dolmetscher: Gint.new(@val**b.val). Es scheint, dass dem GintKonstruktor eine int-Besetzung fehlt ...
primo
10

Eine Zahl negieren

Eine Sache, die GolfScript fehlt, ist ein eingebauter Negationsoperator. Die offensichtlichen Möglichkeiten, eine Zahl auf dem Stapel in ihr Negativ umzuwandeln, wie -1*oder 0\-, erfordern drei Zeichen. Es gibt jedoch zwei Möglichkeiten:

~)

Dies funktioniert, weil GolfScript die Zweierkomplementarithmetik verwendet , sodass ~ x gleich - x −1 ist.

Natürlich (~funktioniert die Variante auch; Die Wahl zwischen ihnen ist in der Regel Geschmackssache.

Ilmari Karonen
quelle
9

Ein Array mischen

Die einfachste Möglichkeit, ein Array in GolfScript zu mischen, besteht darin, es nach einem zufälligen Sortierschlüssel zu sortieren. Wenn Sie nur ein paar Werte grob mischen müssen, reicht der folgende Code aus:

{;9rand}$

Beachten Sie, dass dies selbst für kurze Listen kein sehr gutes Mischen ergibt. Aufgrund des Geburtstagsparadoxons muss das Argument für ein einigermaßen einheitliches Mischen randdeutlich größer sein als das Quadrat der Länge der Liste, die gemischt wird.

Das Ersetzen des 9obigen durch 99ergibt somit einigermaßen gute Ergebnisse für Listen mit bis zu zehn Elementen, zeigt jedoch eine merkliche Verzerrung für längere Listen.

Der folgende Code, der 9 9 = 387.420.489 mögliche Werte verwendet, ist für bis zu etwa 1000 Elemente geeignet (und für bis zu etwa 20.000 akzeptabel):

{;9.?rand}$

Fügen Sie für sehr lange Listen eine weitere 9 für 99 99 ≈ 3,7 × 10 197 Werte hinzu:

{;99.?rand}$

Testen:

Hier ist die Verteilung des ersten Elements in einer Liste mit 10 Elementen, die unter Verwendung der oben gezeigten verschiedenen Varianten gemischt wurde. Es wurden über 10.000 Versuche durchgeführt:

  • Die Ausgabe von 10,{;9rand}$0=zeigt eine sehr deutliche Tendenz, da 0es mehr als dreimal so wahrscheinlich ist, dass sie auf der ersten Position landet wie 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • Mit 10,{;99rand}$0=ist der größte Teil der Verzerrung verschwunden, aber es bleibt noch ein merklicher Betrag übrig:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • Bei 10,{;9.?rand}$0=ist die Ausgabe grundsätzlich nicht von einer wirklich zufälligen Stichprobe zu unterscheiden:

    0 9907  #################################
    1 9962  #################################
    2 10141 #################################
    3 10192 #################################
    4 9965  #################################
    5 9971  #################################
    6 9957  #################################
    7 9984  #################################
    8 9927  #################################
    9 9994  #################################
    

Ps. Für ein wirklich schlechtes Mischen von numerischen Arrays oder Zeichenfolgen kann der folgende Code manchmal akzeptabel sein:

{rand}$

Es wird im Allgemeinen lächerlich voreingenommen sein, aber solange alle Elemente des Eingabearrays (oder alle Zeichencodes in der Zeichenkette) größer als eins sind, hat es eine Wahrscheinlichkeit ungleich Null, eine Permutation des Arrays zu erzeugen, die manchmal erfüllt schlecht geschriebene Herausforderungsanforderungen.

Ilmari Karonen
quelle
3
Ich erinnere mich, dass ich einmal skeptisch die Mathematik für das Geburtstagsparadox gemacht habe, nachdem mein Bruder mir davon erzählt hatte, dass er Recht hatte :(
ajax333221
8

So adressieren Sie eine bestimmte Unterfrage:

Wie konvertiere ich einen String am besten in ein Array von ASCII-Codes und zurück? Welche Operationen machen das als Nebeneffekt? Was ist der beste Weg, um die Zeichen in einer Zeichenkette auf den Stapel zu legen (wie ~ bei Arrays)?

Für diejenigen, die das Problem nicht verstehen, gibt das Typensystem von GolfScript den Typen in der Reihenfolge Integer, Array, String, Block den Vorrang. Dies bedeutet, dass gewöhnliche Array-Operationen, die auf eine Zeichenfolge angewendet werden, fast immer eine Zeichenfolge ergeben. Z.B

'ABC123'{)}%

wird 'BCD234'auf dem Stapel verlassen.

Daher besteht die beste Möglichkeit, eine Zeichenfolge in ein Array von ASCII-Codes zu konvertieren, mit ziemlicher Sicherheit darin, die Zeichen auf dem Stapel zu sichern und sie dann in einem Array zusammenzufassen.

Was ist der beste Weg, um die Zeichen in einer Zeichenkette auf dem Stapel abzulegen? {}/

Wie kann man einen String am besten in ein Array von ASCII-Codes konvertieren? [{}/](mit dem üblichen Vorbehalt, dass man das überspringen kann, wenn nichts anderes auf dem Stapel ist [)

Wie kann ein Array von ASCII-Codes am besten in eine Zeichenfolge konvertiert werden? ''+(Beachten Sie, dass dies auch das Array abflacht, also zB [65 [66 67] [[[49] 50] 51]]''+gibt 'ABC123')

Peter Taylor
quelle
Wie lässt sich ein einzelner ASCII-Code am besten in eine Zeichenfolge umwandeln? []+''+? (scheint ziemlich lang zu sein)
Justin
@Quincunx, es ist ziemlich lang, aber ich kenne keinen besseren Weg. Die Sache, die zu tun ist, könnte sein, zu schauen, woher der ASCII-Code kommt, und zu sehen, ob Sie ihn dazu bringen können, bereits in einem Array anzukommen.
Peter Taylor
6

Wenn Ihr Programm auf mysteriöse Weise kaputt geht, überprüfen Sie Ihre Variablen

Ich habe gerade eine Weile damit verbracht, ein anscheinend korrektes Programm zu debuggen, das !als Variable verwendet wurde (mit der Begründung, dass ich es nicht wieder verwenden würde). Leider ich tat Gebrauch if, und es stellt sich heraus , dass die Durchführung von ifAnrufen , !die Verzweigung zu folgen , um zu entscheiden.

Peter Taylor
quelle
6

Wickeln Sie das oberste Element des Stapels in ein Array

Gibt es eine schöne Art und Weise zu transformieren ... xin ... [x]?

Für die vollständige Allgemeinheit scheint die beste Option 4 Zeichen zu sein. In bestimmten Sonderfällen ist es jedoch möglich, dies zu reduzieren.

1 Zeichen

]funktioniert in dem speziellen Fall, dass xdas einzige ist, was auf dem Stapel.

3 Zeichen

[]+Funktioniert in dem speziellen Fall, dass xes sich um eine Ganzzahl handelt.

.,/Funktioniert in dem speziellen Fall, dass xes sich um ein wahrheitsgemäßes Array oder eine Zeichenfolge handelt. ZB "AB".,/gibt ["AB"]; 3,.,/gibt [[0 1 2]]. Doch "".,/und [].,/beide geben nach [].

4 Zeichen

[.;] funktioniert bedingungslos.

Peter Taylor
quelle
6

Wie kann ein Array an einem bestimmten Index am besten geändert werden? - user1502040

Das ist eine gute Frage. Es gibt keine direkte Möglichkeit, einem Array-Element in GolfScript einen Wert zuzuweisen. Auf die eine oder andere Weise müssen Sie also das gesamte Array neu erstellen.

Die kürzeste allgemeine Möglichkeit, einen neuen Wert xam Index iin ein Array einzufügen, besteht darin, das Array am angegebenen Index zu teilen und xan die erste Hälfte anzuhängen , bevor Sie sie wieder zusammenfügen:

  • .i<[x]+\i>+(11 Zeichen) - Fügt den Wert xam (0-basierten) Index in das Array eini

Um den Wert bei Index durch zu ersetzen , müssen wir nur die zweite Hälfte des Arrays um ein Element kürzen:ix

  • .i<[x]+\i)>+(12 Zeichen) - Ersetzen Sie das Element am (0-basierten) Index idurch den Wertx

Alternativ kann auch die erste Hälfte gekürzt werden, jedoch mit einer 1-basierten Indizierung, was manchmal vorzuziehen ist:

  • .i(<[x]+\i>+(12 Zeichen) - Ersetzen Sie das Element am (1-basierten) Index idurch den Wertx

Wenn xes sich bei allen obigen Beispielen um eine Zahl handelt, können die eckigen Klammern weggelassen werden, um zwei Zeichen zu speichern, da sie +sowieso automatisch in ein Array umgewandelt werden:

  • .i<x+\i>+(9 Zeichen) - Fügen Sie die Zahl xam (0-basierten) Index in das Array eini
  • .i<x+\i)>+(10 Zeichen) - Ersetzen Sie das Element am (0-basierten) Index idurch die Zahlx
  • .i(<x+\i>+(10 Zeichen) - Ersetzen Sie das Element bei (1-basiertem) Index idurch die Zahlx

Die Klammern können auch weggelassen werden, wenn es sich bei einem xoder beiden "Array" -Eingaben (oder beiden) tatsächlich um Zeichenfolgen handelt. In diesem Fall wird das Ergebnis auch in eine Zeichenfolge umgewandelt (unter Verwendung der üblichen Regeln für die Konvertierung von Feldern → Zeichenfolgen).


Ps. Wenn wir als Sonderfall wissen, dass das Array zwischen iund 2 × iElemente enthält, können wir xam (0-basierten) Index ein neues Element imit i/[x]*(6 Zeichen) einfügen . Tatsächlich wird das Array in Blöcke von bis zu iElementen aufgeteilt und xzwischen den einzelnen Blöcken eingefügt. Beachten Sie, dass in diesem Fall die Klammern erforderlich sind, auch wenn xes sich um eine Zahl handelt.


Pps. Ein alternativer Ansatz besteht darin, dynamisch benannte Variablen zu verwenden. Beispielsweise,

 'foo' 42 ':x'\+~

ordnet den Wert 'foo'der Variablen zu x42, während

 42 'x'\+~

werde es abrufen.

Sie können dies weiter optimieren, indem Sie das xPräfix weglassen und nur die numerischen Literale direkt zuweisen. Dies ist in GolfScript völlig legal und ermöglicht Ihnen, ein Zeichen aus dem Zuweisungscode zu speichern und den Abrufcode auf "nur" `~(oder gar nichts, wenn dies der Fall ist) zu verkürzen der Index ist konstant!). Der Nachteil ist natürlich, dass die Zuweisung zu einem numerischen Literal den Wert dieses Literal an einer anderen Stelle in Ihrem Code überschreibt. Häufig kann jedoch die Verwendung von Zahlenliteralen vermieden werden (oder zumindest auf den Beginn des Programms beschränkt werden, bevor eines von ihnen neu zugewiesen wird). In diesem Fall ist dieser Trick völlig in Ordnung.

Ilmari Karonen
quelle
3
Ganz abseits des Themas: Herzlichen Glückwunsch zum 10k! :-D
Türklinke
1
Wenn Sie wissen, dass das Array keine doppelten Werte enthält, können Sie einen Wert am Index ifür 9 Bytes ersetzen :.[i=]/[x]*
Martin Ender,
5

Endgültige Ausgabe-Manipulation

Wenn Ihr Programm endet, gibt der GolfScript-Interpreter standardmäßig alles auf dem Stapel sowie eine letzte neue Zeile so aus, als würde Ihr Programm mit folgendem Ergebnis beendet:

]puts

Was die Dokumentation nicht direkt erwähnen ist , dass der Dolmetscher wörtlich nennt die eingebaute in putsdieser Ausgabe zu erzeugen, und dass dieses eingebaut ist wörtlich wie folgt definiert:

{print n print}:puts;

So können Sie die endgültige Ausgabe durch eine Neudefinition unterdrücken oder manipulieren puts, print und / oder n(oder  wenn Sie das Gefühl wirklich verdreht). Hier sind einige Beispiele:

Letzte Zeile unterdrücken:

'':n;

(Natürlich können Sie das weglassen, ;wenn Sie nichts gegen eine zusätzliche leere Zeichenfolge auf dem Stapel haben.)

Endausgabe vollständig unterdrücken:

:puts

Dies überschreibt putsalles, was sich auf dem Stapel befindet. Wenn das etwas ist, das Sie nicht ausführen möchten, können Sie 0:puts;stattdessen zB verwenden. Beachten Sie, dass dies auch unterdrückt p(was als definiert ist {`puts}:p;), Sie können es aber trotzdem printfür die Ausgabe verwenden, wenn Sie möchten.

Ilmari Karonen
quelle
Und nothingdu meinst \n?
CalculatorFeline
Wenn Ihnen der Zeilenumbruch nichts ausmacht, können Sie auch ];die endgültige Ausgabe unterdrücken.
Wastl
5

Ich möchte nach den besten Möglichkeiten fragen: min, max und absoluter Wert. Alle meine Lösungen scheinen viel mehr Charaktere zu haben, als sie sollten. - Claudiu

Minimal Maximal

Um den kleinsten / größten Wert in einem Array zu finden, sortieren Sie ihn einfach und nehmen Sie das erste / letzte Element:

  • $0= (3 Zeichen) - Minimum Element in einer Arry
  • $-1= (4 Zeichen) - Maximales Element in einem Array

Wenn Sie die Länge des Arrays kennen und es 10 Elemente oder weniger sind, können Sie das Maximum in drei Zeichen finden, indem Sie es -1durch den Index des letzten Elements ersetzen .

Wenn Sie die Werte auf dem Stapel haben, können Sie sie einfach zuerst in einem Array sammeln. Ein gelegentlich nützlicher Trick besteht darin, [\]die beiden obersten Elemente des Stapels in einem Array zu [@]sammeln , während die drei obersten Elemente gesammelt werden. So erhalten wir:

  • [\]$0= (6 Zeichen) - Mindestens zwei Werte im Stapel
  • [@]$0= (6 Zeichen) - mindestens drei Werte im Stapel
  • [\]$1= (6 Zeichen) - Maximal zwei Werte im Stapel
  • [@]$2= (6 Zeichen) - Maximal drei Werte im Stapel

Mit demselben Trick kann auch der Median von drei Werten ermittelt werden, was gelegentlich nützlich sein kann:

  • [@]$1= (6 Zeichen) - Median von drei Werten im Stapel

Hier ist ein weiterer potenziell nützlicher Trick, um das Minimum / Maximum zweier Werte zu ermitteln, während die ursprünglichen Werte auf dem Stapel belassen werden :

  • .2$>$ (5 Zeichen) - Finden Sie mindestens zwei Werte im Stapel, ohne die ursprünglichen Werte zu verändern
  • .2$<$ (5 Zeichen) - Finden Sie maximal zwei Werte im Stapel, ohne die ursprünglichen Werte zu verändern

Es funktioniert so, dass .2$die beiden obersten Elemente des Stapels in umgekehrter Reihenfolge geklont werden (dh a ba b b a), </ >die Kopien verglichen werden und 0 oder 1 zurückgegeben $werden. Je nach Ergebnis des Vergleichs kopiert scalar dann einen der beiden Eingabewerte.


Wenn Sie zwei nichtnegative Ganzzahlen auf dem Stapel haben, können Sie mit ,\,&,(5 Zeichen) das Minimum und mit ,\,|,(5 Zeichen) das Maximum ermitteln. Bei diesem Trick werden Schnittmenge und Vereinigung über die Bereiche festgelegt. Sie können ein anderes Zeichen speichern, wenn Sie ,jedes Argument einzeln anwenden können , ohne es austauschen zu müssen. Da diese Methode einen Bereich für jedes Argument berechnet, ist sie für größere Zahlen nicht sehr effizient, kann jedoch für kleinere Eingaben sehr nützlich sein.

Ein noch kürzerer Weg, um das Minimum von zwei nicht negativen ganzen Zahlen auf dem Stapel zu finden, ist ,<,(3 Zeichen). Leider funktioniert dieser Trick nicht, um das Maximum zu finden.


Absolutwert

Der in GolfScript integrierte Absolutwertoperator ist abs(3 Zeichen). Das sind zwar zwei Zeichen mehr, als ich vorziehen würde, aber im Allgemeinen ist es schwer zu schlagen.

In einigen Fällen (z. B. zum Sortieren nach dem absoluten Wert) ist das Quadrat einer Zahl möglicherweise ein geeigneter Ersatz für den absoluten Wert. Dies kann entweder 2?oder in zwei Zeichen berechnet werden .*. So erhalten wir:

  • {.*}$0= (7 Zeichen) - Minimum Element durch absoluten Wert im Array
  • {.*}$-1= (8 Zeichen) - Maximales Element nach Absolutwert im Array

Anstatt beispielsweise zu testen, ob der absolute Wert einer Zahl mit abs 3<(6 Zeichen, einschließlich Leerzeichen) kleiner als 3 ist , können Sie mit .*9<(4 Zeichen, kein Leerzeichen erforderlich) auch testen, ob das Quadrat kleiner als 9 ist .

Ilmari Karonen
quelle
Wenn Sie zwei nichtnegative Ganzzahlen auf dem Stapel haben, können Sie mit ,\,&,(5 Zeichen) das Minimum und mit ,\,|,(5 Zeichen) das Maximum ermitteln. Bei diesem Trick werden Schnittmenge und Vereinigung über die Bereiche festgelegt. Sie können ein anderes Zeichen speichern, wenn Sie ,jedes Argument einzeln anwenden können , ohne es austauschen zu müssen. Da diese Methode einen Bereich für jedes Argument berechnet, ist sie für größere Zahlen nicht sehr effizient, kann jedoch für kleinere Eingaben sehr nützlich sein.
KirarinSnow
@KirarinSnow: Danke! Ich habe es der Antwort hinzugefügt.
Ilmari Karonen
4

Duplikate aus einem Array entfernen

Die Mengenoperatoren |(Vereinigung), &(Schnittmenge) und ^(symmetrischer Unterschied) reduzieren mehrere Array-Elemente zu einem. Der einfachste Weg, um doppelte Elemente aus einem Array zu entfernen, besteht darin, seine Vereinigung oder Schnittmenge mit sich selbst zu nehmen:

.|

oder:

.&

Diese Operatoren behandeln Zeichenfolgen als Arrays von Zeichen, sodass sie auch zum Entfernen doppelter Zeichen aus Zeichenfolgen verwendet werden können.

Ilmari Karonen
quelle
4

Eingeschränkte Transliteration

So adressieren Sie eine bestimmte Unterfrage: Welche Methode eignet sich bei einer bestimmten Zeichenfolge am besten zum Ausführen von tr? Z.Btr/ABC/abc/

Wenn alle Zeichen in der Zeichenfolge betroffen sind, ist dies recht einfach: {'ABC'?'abc'=}%(Overhead: 9 Zeichen).

Jedoch, dass die Pausen, wenn einige der Charaktere nicht transkribiert und 'ABC'?gibt -1.

Wenn die Transliteration nicht zyklisch ist, kann sie einzeln durch Zeichenfolgensplits und -verknüpfungen ersetzt werden: 'AaBbCc'1/2/{~@@/\*}/(Overhead: 15 Zeichen). Das ist zwar verbesserungsfähig, aber es gibt einen alternativen Ansatz, der derzeit besser ist und für zyklische Transliterationen funktioniert.

Derzeit haben die kürzesten allgemeinen Lösungen einen Overhead von 14 Zeichen:

  • Ein Ansatz beinhaltet ein Escape-Zeichen:, wobei das ein literales Null-Byte bezeichnet. (Natürlich ist diese Methode nicht vollständig{.'ABC'?'abc0'=\or}%0 allgemein: Sie kann kein anderes Zeichen in ein Null-Byte abbilden.)

  • Alternativ {.'ABC'?'abc'@),+=}%wird derselbe Overhead benötigt, es werden jedoch nur druckbare ASCII-Zeichen verwendet. Dies @),+ist ein umständlicher (aber anscheinend der kürzeste) Weg, um sicherzustellen, dass die Ersetzungszeichenfolge immer mit dem Eingabezeichen endet.

Peter Taylor
quelle
Mit dem letzten Ansatz 'ABCDEF'erhalte ich für die Eingabezeichenfolge das Ergebnis 'abc000', aber das richtige Ergebnis wäre 'abcDEF'. Vermisse ich etwas?
Cristian Lupascu
1
@ w0lf, diese 0 ist fett gedruckt, da es sich um das zuvor erwähnte Escape-Zeichen handelt - dh das Byte 0.
Peter Taylor
4

Verwandle einen String in ein Array von Zeichen

Sie können dies tun, indem Sie Folgendes eingeben: 1/danach.

Beispiel: "String"1/Drückt, um das Array zu stapeln ['S''t''r''i''n''g'].

Dies ist praktisch, wenn Sie Zeichen in der Zeichenfolge verschieben möchten.

user3700847
quelle
1
Können Sie ein Beispiel geben, wie dies nützlich sein könnte? Strings verhalten sich bereits wie Arrays, daher scheint dies nicht so nützlich zu sein.
Justin
@ Quincunx ist praktisch, wenn Sie Zeichen und nicht ihren ASCII-Wert
herausholen
Und wann möchten Sie das tun?
Justin
5
@Quincunx: Zum Beispiel eine Zeichenfolge drehen. "abc"1/(+-> "bca", aber "abc"(+-> bc97.
Dennis
4

Zuordnung zu Zahlenliteralen

Anstatt 1:xdie Variable zu schreiben und dann zu verwenden / aktualisieren x, können Sie sie häufig einfach direkt verwenden und aktualisieren 1:

1:^;{^.p.+:^;}5*
{1.p.+:1;}5*       (4 bytes shorter)

Dies funktioniert natürlich auch für andere Startwerte, bricht jedoch ab, wenn dieser Wert an einer anderen Stelle in Ihrem Code auftritt.

Zeichensetzung als Variablennamen

Wenn Sie haben Variablen zu verwenden, ist es auch oft weise Interpunktion zu verwenden , die nicht bereits in Ihrem Code ist - viele Programme tun können , ohne &, |, ^, oder ?. Auf diese Weise können Sie beispielsweise schreiben, &nanstatt x nIhre Variable und dann eine neue Zeile zu schreiben.

Lynn
quelle
3
Einige Aufgaben können jedoch unerwartete Nebenwirkungen haben. Insbesondere gilt es , die Zuordnung !ist oft eine schlechte Idee, da sie brechen ifund do(sowie while, until, and, orund xor). Ebenso orwird vom Interpreter als Alias ​​für definiert 1$\if, also neu definiert 1, $oder es \wird auch gebrochen. Die Neudefinition `Pausen p.
Ilmari Karonen,
3

Ein Array filtern

Die allgemeinste Methode zum Filtern eines Arrays ist die Verwendung von { },, die den Codeblock für jedes Element des Arrays auswertet und die Elemente auswählt, für die der resultierende Wert wahr ist (dh, sie verhalten sich wiegrep in Perl).

Die Verwendung des Array-Subtraktionsoperators -ist jedoch häufig kürzer. Dieser Operator nimmt zwei Arrays und entfernt jedes Element, das im zweiten Array vorkommt, aus dem ersten. Die Reihenfolge der Elemente im ersten Array wird nicht geändert oder Duplikate werden ausgeblendet. Ein nützlicher Trick besteht darin, die Subtraktionsoperation zweimal anzuwenden, um einen nicht kollabierenden Array-Schnittoperator zu erhalten:

  • a b -: Entferne alle im Array gefundenen Elemente baus dem Arraya
  • a. b --: Entferne alle Elemente, die nicht im Array gefunden wurden, baus dem Arraya

Dies kann insbesondere verwendet werden, um zu zählen, wie oft ein Element in einem Array vorkommt:

  • a.[c]--,: Zähle, wie oft das Element cim Array vorkommta

Im Allgemeinen ist diese Methode nicht optimal, da:

  • a[c]/,(: Zähle, wie oft das Element cim Array vorkommta
  • a{c=},,: Zähle, wie oft das Element cim Array vorkommta

ist ein Zeichen kürzer (und wenn es in Ordnung ist, die Anzahl um eins zu a[c]/,verringern, wird ein Zeichen mehr gespeichert). In dem speziellen Fall, in dem es sich cum eine Zahl und aein normales Array (keine Zeichenfolge) handelt, können die eckigen Klammern cweggelassen werden, da der -Operator seine Argumente auf den gleichen Typ zwingt:

  • a.c--,: Zähle, wie oft die Zahl cim Array vorkommt (keine Zeichenkette!)a

(Wenn aes sich um eine Zeichenfolge handelt und ceine Zahl zwischen 0 und 9 ist, a.c--wird die Häufigkeit gezählt, mit der die Ziffer c vorkommt a.)


Ein ähnlicher Trick kann verwendet werden, um das häufigste Element in einem Array zu finden :

:a{a\[.]-,}$0=

Wenn die Eingabe wiederum ein Array von Zahlen ist, kann die gesamte [.]Sequenz weggelassen werden. Leider funktioniert dies nicht für Saiten ohne die [.].

Ilmari Karonen
quelle
Zum Zählen von Vorkommen (allgemeiner Fall) a[c]/,(und a{c=},,sind ein Byte kürzer.
Dennis
@ Tennis: Danke! Ich habe das in bearbeitet.
Ilmari Karonen
3

Lesen Sie aus STDIN

GolfScript kann von stdin lesen:

"#{STDIN.read}"

Dies liest weiter von STDIN, bis die EOF erreicht ist. Alternative:

"#{STDIN.gets}"

oder

"#{STDIN.readline}"

Andere Dinge zur Verfügung:

getbyte
getc
gets([sep])
gets(limit)
gets(sep, limit)
inspect # perhaps useful for an underhanded contest
isatty
read([length])
readbyte
readchar
readline([sep])
readline(limit)
readline(sep, limit)
readlines([sep])
readlines(limit)
readlines(sep, limit)
readpartial(maxlen [, outbuf])

Sie können jeweils nur einmal verwendet werden (und auch einmal für jede Änderung des Parameters, auch noch einmal mit leeren Klammern). Danach erhalten Sie den ursprünglichen Wert anstelle eines neuen Werts.

Justin
quelle
2
Möglicherweise möchten Sie eine Anmerkung hinzufügen, {"#{STDIN.readline}"p}2*die nicht 2 Zeilen liest, sondern die Zeichenfolge nur einmal ausgewertet wird.
Howard
2
Wenn Sie ieine Ganzzahl initialisieren , '"#{'i):i';STDIN.gets}"'++~wird bei jeder Auswertung ein anderes Ergebnis ausgegeben. Auch Backticks sind erwähnenswert. Wenn wir von Linux ausgehen, können wir zB `head -1`statt STDIN.gets.
Dennis
@Dennis: Mit dieser Option können "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";Sie auch einen neuen GolfScript-Operator definieren g , der eine Zeile von stdin liest und auf den Stapel schiebt.
Ilmari Karonen
2

Hexadezimale Eingabe decodieren

GolfScript hat keine hexadezimalen Integer-Literale. Sie können also leider nicht einfach hexadezimale Eingaben mit analysieren ~ . Wenn Ihr Code hexadezimal eingegeben werden muss, müssen Sie ihn stattdessen manuell analysieren.

Diese 8-Zeichen-Schleife, die auf eine Zeichenfolge angewendet wird, konvertiert hexadezimale Kleinbuchstaben in ihre numerischen Entsprechungen:

{39%9-}%

Wenn Sie (auch) hexadezimale Großbuchstaben akzeptieren müssen, besteht die einfachste (und wahrscheinlich kürzeste) Lösung darin, diese zuerst mit Kleinbuchstaben zu versehen 32|, für insgesamt 11 Zeichen:

{32|39%9-}%

Beachten Sie, dass die Ausgabe technisch gesehen immer noch eine Zeichenfolge (bestehend aus den ASCII-Zeichen 0 bis 15) ist, die meisten GolfScript-Array-Funktionen jedoch auch Zeichenfolgen akzeptieren. Wenn Sie unbedingt ein Array benötigen, können Sie es immer verwenden [{39%9-}/](wobei das erste [optional ist, wenn der Stapel ansonsten leer ist).

Um die Ausgabe des obigen Codes in eine Ganzzahl umzuwandeln, können Sie einfach 16base(6 Zeichen) verwenden. Wenn Sie stattdessen ein Array von Bytes wünschen, ist die kürzeste Lösung, die ich gefunden habe, einfach jedes Paar von Hexadezimalziffern mit 2/{16base}%(11 Zeichen) zu decodieren . Alles in allem ist der kürzeste Code, den ich gefunden habe, um einen Hex-String in ein Byte-Array umzuwandeln, 8 + 11 = 19 Zeichen:

{39%9-}%2/{16base}%

Beachten Sie, dass die Ausgabe dieses Codes ist in der Tat ein Array, kein String. Bei Bedarf können Sie die Zeichenfolge verketten, indem Sie sie z. B. mit ""+oder verknüpfen n+.

Ilmari Karonen
quelle
2

Neue eingebaute Operatoren definieren

Der standardmäßige GolfScript-Interpreter verfügt über eine selten verwendete Funktion , die interpolierten Ruby-Code in Strings in doppelten Anführungszeichen ermöglicht.

Ein Grund, warum diese Funktion nicht häufiger verwendet wird, ist, dass der interpolierte Code umständlich zur Kompilierungszeit ausgeführt wird und die Ausgabe vom GolfScript-Interpreter zwischengespeichert wird, so dass dasselbe Zeichenfolgenliteral auch innerhalb immer den gleichen Wert ergibt string eval.

Eine Sache, für die sich diese Funktion als gut herausstellt, ist die Definition neuer GolfScript-Operatoren, die in Ruby-Code implementiert sind. So definieren Sie beispielsweise einen neuen binären Additionsoperator, der genau wie der integrierte Standardoperator funktioniert +:

"#{var'add','gpush a+b'.cc2}";

Es spielt keine Rolle, wo Sie die Definition in Ihren Code einfügen. Der neue Operator wird definiert, sobald die doppelte Zeichenfolge mit dem Ruby-Code analysiert wird. Der addoben definierte Operator funktioniert genauso wie der eingebaute +Operator und kann genauso verwendet werden:

1 2 add          # evaluates to 3
"foo" "bar" add  # evaluates to "foobar"

Das Definieren eines neuen Additionsoperators ist natürlich ziemlich nutzlos, es sei denn, Sie haben etwas Dummes getan, wie den eingebauten +Operator zu löschen . Mit demselben Trick können Sie jedoch neue Operatoren definieren, die Dinge tun, die Golfscript nicht (ohne weiteres) von Haus aus tun kann, z. B. das einheitliche Mischen eines Arrays:

"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";

10,shuf          # evaluates to 0,1,2,...,9 in random order

oder den Inhalt des gesamten Stapels drucken:

"#{var'debug','puts Garray.new($stack).ginspect'.cc}";

4,) ["foo" debug  # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched

oder interaktive Eingabe:

"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";

]; { "> " print gets ~ ]p 1 } do   # simple GolfScript REPL

oder sogar Webzugriff:

"#{
  require 'net/http'
  require 'uri'
  var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";

"http://example.com" get

Eine etwas golferischere (und riskantere!) Implementierung der letzteren wäre natürlich zB:

"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";

Dies ist an sich nicht besonders golfen, ermöglicht Ihnen jedoch, die Fähigkeiten von GolfScript über das hinaus zu erweitern, was die eingebauten Befehle bieten.


Wie funktioniert es?

Die maßgebliche Referenz zur Definition neuer GolfScript-Operatoren auf diese Weise ist natürlich der Quellcode für den Interpreter . Das heißt, hier sind ein paar kurze Tipps:

  • Um einen neuen Operator zu definieren name, der den Ruby-Code ausführt code, verwenden Sie:

    var'name','code'.cc
  • Verwenden Sie im Code, um gpopeinen Wert aus dem Stapel zu lesen und gpushwieder einzuschieben. Sie können auch direkt über das Array auf den Stapel zugreifen $stack. Zum Beispiel, um beide aund bauf den Stapel zu schieben , ist es golfer, $stack<<a<<bals zu tun gpush a;gpush b.

    • Die Positionen der [Array-Startmarkierungen werden im $lbArray gespeichert . Die gpopFunktion sorgt dafür, dass diese Markierungen nach unten korrigiert werden, wenn der Stapel unter ihre Position schrumpft, nicht jedoch, wenn das $stackArray direkt manipuliert wird.
  • Die .ccZeichenfolgenmethode, mit der Ruby-Code in einer Zeichenfolge in einen GolfScript-Operator kompiliert wird, ist nur ein praktischer Wrapper Gblock.new(). Es hat auch die Varianten .cc1, .cc2und .cc3das macht den Bediener automatisch 1 Pop, 2 oder 3 Argumente vom Stapel und weisen Sie auf die Variablen a, bund c. Es gibt auch ein .orderVerfahren , das funktioniert wie .cc2, mit der Ausnahme , dass es automatisch die Argumente sortiert Typ Priorität .

  • Alle Werte auf dem GolfScript Stapel (und sollen!) Objekte vom Typ Gint, Garray, Gstringoder Gblock. Auf die zugrunde liegende native Ganzzahl oder das zugrunde liegende Array kann bei Bedarf über die .valMethode zugegriffen werden .

    • Beachten Sie jedoch, dass Gstring.valein Array von Gints! Um eine Gstringin eine native Ruby-Zeichenfolge zu verwandeln , rufen Sie .to_ssie stattdessen auf (oder verwenden Sie sie in einem Kontext, der dies automatisch ausführt, z. B. bei der Zeichenfolgeninterpolation). Der Aufruf .to_gsauf jedem GS Wert verwandelt es in ein Gstring, so kann jeder GS - Wert mit Zeichenfolge werden .to_gs.to_s.
  • Die gpushFunktion bricht native Ruby-Zahlen, -Strings oder -Arrays nicht automatisch in die entsprechenden GS-Typen ein, sodass Sie dies häufig selbst tun müssen, indem Sie z Gstring.new(). B. explizit aufrufen . Wenn Sie etwas anderes als einen der GS-Werttypen auf den Stapel schieben, stürzt wahrscheinlich jeder Code ab, der später versucht, ihn zu manipulieren.

  • Die GS- .factoryWerttypen verfügen auch über eine Methode, die den Konstruktor des Typs aufruft. Dies kann nützlich sein, um z. B. Arrays / Strings nach der Bearbeitung ihres Inhalts neu zu verpacken. Alle Typen haben auch eine .coerceMethode, mit der Typenzwang ausgeführt wird : a.coerce(b)Gibt ein Paar zurück, das denselben Typ enthält aund zu diesem bgezwungen wird.

Ilmari Karonen
quelle