Suggerimenti per giocare a golf in GolfScript


35

Cosa, questo post non esiste ancora?

Naturalmente, GolfScript è progettato per il golf, quindi potresti pensare che non siano davvero necessari suggerimenti specifici. Ma per sfruttare appieno le funzionalità di GolfScript, devi imparare alcuni trucchi non ovvi. Questo post è per raccogliere suggerimenti e trucchi così utili.

Per cominciare, ecco le pagine di riferimento ufficiali di GolfScript. Dovresti davvero familiarizzare con questi prima:

In particolare, suggerirei molto di leggere le pagine in questo ordine: il riferimento rapido è di scarsa utilità fino a quando non hai già ragionevolmente familiarità con i built-in e il tutorial include alcuni dettagli importanti che non sono spiegati nelle altre pagine .


Ps. Per motivi di ispirazione e interesse personale, ecco alcune domande a cui vorrei vedere delle belle risposte a:

  • Come eseguire una traslitterazione limitata in GolfScript? {FROM?TO=}%funziona se puoi essere sicuro che tutti gli input siano stati trovati FROM(o non ti dispiaccia che siano tutti mappati sull'ultimo elemento di TO), ma tutti i modi che ho visto per lasciare invariati i valori non modificati sono stati più o meno klugey.

  • Come convertire al meglio una stringa in un array di codici ASCII e viceversa? Quali operazioni fanno questo come effetto collaterale? Qual è il modo migliore per scaricare i caratteri di una stringa nello stack (come ~fa per gli array)?


Un'altra domanda: c'è un bel modo di trasformarsi ... xin ... [x]? Il meglio che posso vedere è [.;].
Peter Taylor,

@Peter: If xè un numero, quindi []+funziona ed è più corto di un carattere. E ovviamente, se xè l'unica cosa in pila, allora ]lo farà.
Ilmari Karonen,

Vorrei chiedere i modi migliori per fare: valore minimo, massimo e assoluto. Tutte le mie soluzioni sembrano assumere molti più personaggi di quanto dovrebbero.
Claudiu,

Qual è il modo migliore per modificare un array in un determinato indice?
user1502040

@ user1502040: risposta di seguito. (Se qualcuno conosce un modo migliore, per favore condividi!)
Ilmari Karonen,

Risposte:


29

Razionale / galleggiante / complesso

Ho letto così tante volte che GolfScript ha solo numeri interi che ho iniziato a crederci. Bene, non è vero.

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

L'output è

3/4

con l'interprete GolfScript standard e

0.75

su Web GolfScript .

Hack simili consentono di trasmettere a Rational, Float o persino Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex

9
OMGWTFHAX o_O !!!
Ilmari Karonen,

3
WAT! Abbastanza sicuro che questo sia un bug nell'interprete, ma wow
Doorknob

3
Linea 82 del interprete più recente: Gint.new(@val**b.val). Sembra che al Gintcostruttore manchi un cast int ...
primo

10

Negare un numero

Una cosa che manca a GolfScript è un operatore di negazione incorporato. I modi ovvi per convertire un numero nello stack nel suo negativo, come -1*o 0\-, richiedono tre caratteri. Tuttavia, c'è un modo per farlo in due:

~)

Questo funziona perché GolfScript usa l' aritmetica del complemento di due , in modo che ~ x sia uguale a - x −1.

Naturalmente, anche la variante (~funziona; la scelta tra loro è generalmente una questione di gusti.


9

Mescolare un array

Il modo più semplice per mescolare un array in GolfScript è ordinarlo tramite una chiave di ordinamento casuale. Se hai solo bisogno di mescolare grossolanamente alcuni valori, farà il seguente codice:

{;9rand}$

Si noti che, anche per gli elenchi brevi, questo non darà un ottimo shuffle. A causa del paradosso del compleanno , per ottenere uno shuffle ragionevolmente uniforme, l'argomento randdeve essere significativamente maggiore del quadrato della lunghezza dell'elenco che viene mischiato.

Sostituendo quanto 9sopra con risultati 99così ragionevolmente buoni per elenchi fino a dieci elementi, ma mostra una distorsione evidente per elenchi più lunghi.

Il seguente codice, che utilizza 9 9 = 387.420.489 valori possibili, è valido per un massimo di circa 1000 articoli (e accettabile per un massimo di circa 20.000):

{;9.?rand}$

Per elenchi davvero lunghi, aggiungi un altro 9 per 99 99 ≈ 3,7 × 10 197 valori:

{;99.?rand}$

test:

Ecco la distribuzione del primo elemento in un elenco di 10 elementi mischiato usando le diverse varianti mostrate sopra, campionato oltre 10.000 prove:

  • L'output di 10,{;9rand}$0=mostra una distorsione molto chiara, con 0una probabilità più di tre volte di finire in prima posizione come 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • Con 10,{;99rand}$0=, la maggior parte della distorsione è sparita, ma rimane ancora una quantità notevole:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • Con 10,{;9.?rand}$0=, l'output è sostanzialmente indistinguibile da un campione veramente casuale:

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

Ps. In caso di mischia davvero errata di matrici o stringhe numeriche, il seguente codice può talvolta essere accettabile:

{rand}$

Sarà generalmente ridicolmente distorto, ma fintanto che tutti gli elementi dell'array di input (o tutti i codici carattere nella stringa) sono maggiori di uno, ha una probabilità diversa da zero di produrre qualsiasi permutazione dell'array, che a volte può soddisfare requisiti di sfida scritti male.


3
Ricordo di aver fatto una volta scettica la matematica per il paradosso del compleanno dopo che mio fratello me ne aveva parlato, aveva ragione :(
ajax333221

8

Per rispondere a una specifica domanda:

Come convertire al meglio una stringa in un array di codici ASCII e viceversa? Quali operazioni fanno questo come effetto collaterale? Qual è il modo migliore per scaricare i caratteri di una stringa nello stack (come ~ fa per gli array)?

Per coloro che non comprendono il problema, il sistema di tipi di GolfScript dà la priorità ai tipi nell'ordine intero, array, stringa, blocco. Ciò significa che le normali operazioni di array applicate a una stringa forniscono quasi sempre una stringa. Per esempio

'ABC123'{)}%

lascerà 'BCD234'in pila.

Di conseguenza, il modo migliore per convertire una stringa in un array di codici ASCII è quasi certamente quello di scaricare i caratteri nello stack e poi riunirli in un array.

Qual è il modo migliore per scaricare i caratteri di una stringa nello stack? {}/

Qual è il modo migliore per convertire una stringa in un array di codici ASCII? [{}/](con il solito avvertimento che se non c'è nient'altro in pila puoi saltare il [)

Qual è il modo migliore per convertire una matrice di codici ASCII in una stringa? ''+(Notare che anche questo appiattisce l'array, quindi ad es. [65 [66 67] [[[49] 50] 51]]''+'ABC123')


Qual è il modo migliore per trasformare un singolo codice ASCII in una stringa? []+''+? (sembra piuttosto lungo)
Giustino il

@Quincunx, è piuttosto lungo, ma non conosco un modo migliore. La cosa da fare potrebbe essere guardare da dove proviene il codice ASCII e vedere se riesci a farlo arrivare già in un array.
Peter Taylor,

6

Se il tuo programma si rompe misteriosamente, controlla le tue variabili

Ho appena trascorso un po 'di debug di un programma apparentemente corretto che ha usato !come variabile (per il fatto che non lo avrei usato di nuovo). Purtroppo ho fatto uso if, e si scopre che l'attuazione di ifchiamate !a decidere quale ramo da seguire.


6

Avvolgere l'elemento in cima alla pila in un array

C'è un bel modo di trasformarsi ... xin ... [x]?

Per la massima generalità, l'opzione migliore sembra essere 4 caratteri. Tuttavia, in alcuni casi speciali è possibile ridurre questo.

1 carattere

]funziona nel caso speciale che xè l'unica cosa in pila.

3 caratteri

[]+funziona nel caso speciale che xè un numero intero.

.,/funziona nel caso speciale che xè una matrice o una stringa sincera. Ad esempio "AB".,/["AB"]; 3,.,/[[0 1 2]]. Tuttavia, "".,/ed [].,/entrambi danno [].

4 caratteri

[.;] funziona incondizionatamente.


6

Qual è il modo migliore per modificare un array in un determinato indice? - user1502040

Questa è una bella domanda. Non esiste un modo diretto per assegnare un valore a un elemento array in GolfScript, quindi, in un modo o nell'altro, dovrai ricostruire l'intero array.

Il modo più breve generale che conosco per inserire un nuovo valore xall'indicei in un array è quello di dividere l'array in corrispondenza dell'indice dato e aggiungerlo xalla prima metà prima di unirli nuovamente:

  • .i<[x]+\i>+ (11 caratteri): inserire il valore x nella matrice nell'indice (basato su 0)i

Per sostituire il valore all'indice iconx , dobbiamo solo accorciare la seconda metà dell'array di un elemento:

  • .i<[x]+\i)>+ (12 caratteri): sostituisce l'elemento nell'indice (basato su 0) i con il valorex

In alternativa, accorciare la prima metà farà effettivamente lo stesso, ma con l'indicizzazione basata su 1, che a volte può essere preferibile:

  • .i(<[x]+\i>+ (12 caratteri): sostituisce l'elemento nell'indice (basato su 1) i con il valorex

In tutti gli esempi precedenti, se xè un numero, le parentesi quadre attorno ad esso possono essere omesse per salvare due caratteri, poiché verranno costrette automaticamente in un array da+ comunque :

  • .i<x+\i>+(9 caratteri): inserire il numero xnell'array nell'indice (basato su 0)i
  • .i<x+\i)>+(10 caratteri): sostituisce l'elemento nell'indice (basato su 0) icon il numerox
  • .i(<x+\i>+(10 caratteri): sostituisce l'elemento nell'indice (basato su 1) icon il numerox

Le parentesi possono anche essere omesse x o gli "array" di input (o entrambi) sono effettivamente stringhe, nel qual caso il risultato verrà anche forzato in una stringa (usando le normali regole di conversione dell'array → stringa).


Ps. Come caso speciale, se sappiamo che l'array ha tra ie 2 × ielementi, possiamo inserire un nuovo elemento xnell'indice ( basato su 0) icon i/[x]*(6 caratteri). Ciò che effettivamente fa è dividere l'array in blocchi fino a un massimo di ielementi e inserirlo xtra ciascun blocco. Si noti che, in questo caso, le parentesi sono necessarie anche sex è un numero.


Pps. Un approccio alternativo consiste nell'utilizzare variabili con nome dinamico. Per esempio,

 'foo' 42 ':x'\+~

assegnerà il valore 'foo'alla variabile x42, mentre

 42 'x'\+~

lo recupererà.

Puoi ottimizzarlo ulteriormente omettendo il xprefisso e assegnando direttamente ai letterali numerici: questo è perfettamente legale in GolfScript e ti consente di salvare un carattere dal codice di assegnazione e abbreviare il codice di recupero a solo `~(o niente del tutto, se l'indice è costante!). Il lato negativo, ovviamente, è che l'assegnazione a un letterale numerico sovrascriverà il valore di quel letterale in qualsiasi altra parte del codice. Spesso, tuttavia, è possibile evitare l'uso di letterali numerici (o almeno limitarsi all'inizio del programma, prima che uno di essi venga riassegnato), nel qual caso questo trucco va benissimo.


3
Completamente fuori tema: congratulazioni per 10k! MrGreen
Maniglia della porta

1
Se si sa che l'array non ha valori duplicati, è possibile sostituire un valore in indice iper 9 byte:.[i=]/[x]*
Martin Ender,

5

Manipolazione dell'output finale

Per impostazione predefinita, quando termina il programma, l'interprete GolfScript emette tutto nello stack, più una riga finale, esattamente come se il programma terminasse con:

]puts

Ciò che la documentazione non menziona direttamente è che l'interprete chiama letteralmente il built-in putsper produrre questo output e che questo built-in è letteralmente definito come:

{print n print}:puts;

Pertanto, è possibile sopprimere o manipolare l'output finale ridefinendo puts, print e / o n(o  se ti senti davvero ritorto). Ecco alcuni esempi:

Elimina la riga finale:

'':n;

(Naturalmente puoi tralasciare il ; se non ti dispiace una stringa vuota in più nello stack.)

Elimina completamente l'output finale:

:puts

Questo si sovrascrive putscon qualsiasi cosa si trovi in ​​cima alla pila. Se sembra essere qualcosa che non vuoi eseguire, puoi usare ad es 0:puts;. Si noti che questo sopprime anche p(che è definito come {`puts}:p;), ma è comunque possibile utilizzarlo printper l'output, se lo si desidera.


E nothingintendi \n?
CalcolatriceFeline

Se non ti dispiace la nuova riga finale, puoi anche usare ];per sopprimere l'output finale.
wastl

5

Vorrei chiedere i modi migliori per fare: valore minimo, massimo e assoluto. Tutte le mie soluzioni sembrano assumere molti più personaggi di quanto dovrebbero. - Claudiu

minimo Massimo

Per trovare il valore più piccolo / più grande in un array, basta ordinarlo e prendere il primo / ultimo elemento:

  • $0= (3 caratteri) - elemento minimo in un arry
  • $-1= (4 caratteri) - elemento massimo in un array

Se conosci la lunghezza dell'array, ed è pari o inferiore a 10 elementi, puoi trovare il massimo in tre caratteri sostituendolo -1con l'indice dell'ultimo elemento.

Se hai i valori nello stack, puoi prima raccoglierli in un array. Per questo, un trucco di tanto in tanto utile è che [\]raccoglie i primi due elementi dello stack in un array, mentre [@]raccoglie i primi tre. Quindi, otteniamo:

  • [\]$0= (6 caratteri) - minimo di due valori nello stack
  • [@]$0= (6 caratteri) - minimo di tre valori nello stack
  • [\]$1= (6 caratteri) - massimo di due valori nello stack
  • [@]$2= (6 caratteri) - massimo di tre valori nello stack

Lo stesso trucco può essere utilizzato anche per trovare la mediana di tre valori, che possono essere occasionalmente utili:

  • [@]$1= (6 caratteri) - mediana di tre valori in pila

Ecco un altro trucco potenzialmente utile per trovare il minimo / massimo di due valori lasciando nello stack i valori originali :

  • .2$>$ (5 caratteri): trova almeno due valori nello stack, lasciando intatti i valori originali
  • .2$<$ (5 caratteri): trova un massimo di due valori nello stack, lasciando intatti i valori originali

Il modo in cui funziona è che .2$clona i due principali elementi nello stack in ordine inverso (cioè a ba b b a), </ >confronta le copie e restituisce 0 o 1, e scalare $quindi copia uno dei due valori di input in base al risultato del confronto.


Se hai due interi non negativi nello stack, puoi usare ,\,&,(5 caratteri) per trovare il loro minimo e ,\,|,(5 caratteri) per trovare il loro massimo. Questo trucco utilizza rispettivamente l'intersezione e l'unione tra gli intervalli. Puoi salvare un altro personaggio se è possibile applicare ,separatamente ogni argomento senza doverli scambiare. Poiché questo metodo calcola un intervallo per ciascun argomento, non è molto efficiente per numeri più grandi, ma potrebbe essere molto utile per input più piccoli.

Un modo ancora più breve per trovare il minimo di due numeri interi non negativi nello stack è ,<,(3 caratteri). Purtroppo, questo trucco non funziona per trovare il massimo.


valore assoluto

L' operatore di valore assoluto incorporato di GolfScript èabs (3 caratteri). Sebbene si tratti di due caratteri in più di quanto preferirei, è difficile da battere in generale.

In alcuni casi (ad es. Per l'ordinamento per valore assoluto) potresti trovare il quadrato di un numero un sostituto adeguato del suo valore assoluto; questo può essere calcolato in due caratteri, o 2?o .*. Quindi, otteniamo:

  • {.*}$0= (7 caratteri) - elemento minimo per valore assoluto nell'array
  • {.*}$-1= (8 caratteri) - elemento massimo per valore assoluto nell'array

Allo stesso modo, invece di testare se il valore assoluto di un numero è inferiore a 3 con abs 3<(6 caratteri, incluso lo spazio), è possibile verificare se il suo quadrato è inferiore a 9 con .*9<(4 caratteri, senza spazio necessario).


Se hai due interi non negativi nello stack, puoi usare ,\,&,(5 caratteri) per trovare il loro minimo e ,\,|,(5 caratteri) per trovare il loro massimo. Questo trucco utilizza rispettivamente l'intersezione e l'unione tra gli intervalli. Puoi salvare un altro personaggio se è possibile applicare ,separatamente ogni argomento senza doverli scambiare. Poiché questo metodo calcola un intervallo per ciascun argomento, non è molto efficiente per numeri più grandi, ma potrebbe essere molto utile per input più piccoli.
KirarinSnow

@KirarinSnow: Grazie! L'ho aggiunto alla risposta.
Ilmari Karonen,

4

Rimozione dei duplicati da un array

Gli operatori set |(unione), &(intersezione) e ^(differenza simmetrica) comprimeranno più elementi dell'array in uno. Pertanto, il modo più semplice per rimuovere elementi duplicati da un array è di prendere la sua unione o intersezione con se stesso:

.|

o:

.&

Questi operatori tratteranno le stringhe come matrici di caratteri, quindi potranno anche essere utilizzate per rimuovere i caratteri duplicati dalle stringhe.


4

Traslitterazione limitata

Per rispondere a una specifica domanda: data una stringa, qual è il modo migliore per eseguire una tr? Per esempiotr/ABC/abc/

Se tutti i caratteri nella stringa saranno interessati, questo è abbastanza semplice: {'ABC'?'abc'=}%(sovraccarico: 9 caratteri).

Tuttavia, ciò si interrompe se alcuni dei personaggi non sono traslitterati e 'ABC'?-1 .

Se la traslitterazione non è ciclica, può essere eseguita una sostituzione alla volta con suddivisioni e join di stringhe: 'AaBbCc'1/2/{~@@/\*}/(sovraccarico: 15 caratteri). Questo può essere migliorabile, ma esiste un approccio alternativo che è attualmente migliore e funziona per traslitterazioni cicliche.

Attualmente, le soluzioni generali più brevi hanno un sovraccarico di 14 caratteri:

  • Un approccio prevede un carattere di escape:, dove denota un byte null letterale. (Naturalmente, questo metodo non è completamente generale: non può mappare nessun altro carattere in un byte null.){.'ABC'?'abc0'=\or}%0

  • In alternativa, {.'ABC'?'abc'@),+=}%ha lo stesso sovraccarico, ma utilizza solo caratteri ASCII stampabili. La @),+è una involuta (ma, evidentemente, il più breve) modo per garantire che la stringa di sostituzione sempre termina con il carattere di input.


Usando l'ultimo approccio, per la stringa di input 'ABCDEF'ottengo il risultato 'abc000', ma il risultato giusto sarebbe 'abcDEF'. Mi sto perdendo qualcosa?
Cristian Lupascu,

1
@ w0lf, quello 0 è in grassetto perché è il carattere di escape menzionato in precedenza - ovvero il byte 0.
Peter Taylor

4

Trasforma una stringa in una matrice di caratteri

Puoi farlo digitando: 1/dopo di esso.

Esempio: "String"1/spinge per impilare l'array ['S''t''r''i''n''g'].

Ciò è utile quando si desidera spostare i caratteri nella stringa.


1
Puoi fare un esempio di come potrebbe essere utile? Le stringhe si comportano già come array, quindi non sembra così utile.
Giustino,

@Quincunx è utile quando vuoi far apparire i personaggi e non il loro valore ascii
user3700847

E quando vorresti farlo?
Giustino il

5
@Quincunx: rotazione di una stringa, ad esempio. "abc"1/(+-> "bca", ma "abc"(+-> bc97.
Dennis,

4

Assegnare a numeri letterali

Spesso, invece di scrivere 1:xe quindi utilizzare / aggiornare la variabile x, puoi semplicemente utilizzare e aggiornare 1direttamente:

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

Naturalmente, questo funziona anche per altri valori iniziali, ma si interromperà se quel valore si verifica in qualsiasi altra parte del codice.

Punteggiatura come nomi di variabili

Se si dispone di utilizzare le variabili, è anche spesso saggio usare la punteggiatura che non sia già nel codice - un sacco di programmi possono fare a meno &, |, ^, o ?. In questo modo, ad esempio, puoi scrivere &ninvece di x nspingere la tua variabile e poi spingere una nuova riga.


3
Tuttavia, alcuni incarichi possono avere effetti collaterali imprevisti. In particolare, l'assegnazione a !è spesso una cattiva idea, come si romperà ife do(così come while, until, and, ore xor). Allo stesso modo, orè definito dall'interprete come un alias per 1$\if, quindi ridefinendo 1, $o \anche romperlo. Ridefinire le `pause p.
Ilmari Karonen,

3

Filtraggio di un array

Il modo più generale di filtrare un array è usare { },, che valuta il blocco di codice per ciascun elemento dell'array e seleziona quegli elementi per i quali il valore risultante è vero (cioè si comporta come grepin Perl).

Tuttavia, l'utilizzo dell'operatore di sottrazione di array -è spesso più breve. Questo operatore accetta due array e rimuove ogni elemento presente nel secondo array dal primo. Esso non altera l'ordine degli elementi della prima matrice o collasso duplicati. Un trucco utile è applicare l'operazione di sottrazione due volte per produrre un operatore di intersezione di array non collassante:

  • a b -: rimuove qualsiasi elemento trovato nell'array bdall'arraya
  • a. b --: rimuove qualsiasi elemento non trovato nell'array bdall'arraya

In particolare, questo può essere usato per contare il numero di volte in cui un elemento si presenta in un array:

  • a.[c]--,: conta il numero di volte in cui l'elemento si cpresenta nell'arraya

In generale, questo metodo non è ottimale, poiché uno dei due:

  • a[c]/,(: conta il numero di volte in cui l'elemento si cpresenta nell'arraya
  • a{c=},,: conta il numero di volte in cui l'elemento si cpresenta nell'arraya

è più corto di un carattere (e, se è corretto che il conteggio sia disattivato di uno, a[c]/,salva un altro personaggio). Tuttavia, nel caso speciale in cui cè un numero ed aè un array normale (non una stringa), le parentesi quadre intorno cpossono essere omesse perché l' -operatore costringe i suoi argomenti allo stesso tipo:

  • a.c--,: conta il numero di volte che si cverifica il numero nell'array (non stringa!)a

(Se aè una stringa ed cè un numero compreso tra 0 e 9, a.c--conterà il numero di volte in cui si verifica la cifra .)ca


Un trucco simile può essere utilizzato per trovare l' elemento più comune in un array :

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

Ancora una volta, se l'input è un array di numeri, l'intera [.]sequenza può essere omessa. Purtroppo, questo non funziona per le stringhe senza il [.].


Per il conteggio delle occorrenze (caso generale) a[c]/,(e a{c=},,sono più brevi di un byte.
Dennis

@Dennis: grazie! L'ho modificato in.
Ilmari Karonen il

3

Leggi da STDIN

GolfScript può leggere da stdin:

"#{STDIN.read}"

Questo continuerà a leggere da STDIN fino al raggiungimento dell'EOF. In alternativa:

"#{STDIN.gets}"

o

"#{STDIN.readline}"

Altre cose disponibili:

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])

Per ognuno di questi, possono essere utilizzati una sola volta (e anche una volta per ogni modifica del parametro, anche una volta di più con parentesi vuote); successivamente, il valore originale è quello che otterrai invece di un nuovo valore.


2
Potresti voler aggiungere un'osservazione che {"#{STDIN.readline}"p}2*non legge 2 righe ma invece la stringa viene valutata una sola volta.
Howard,

2
Se si esegue l' inizializzazione isu qualsiasi numero intero, si '"#{'i):i';STDIN.gets}"'++~otterrà un risultato diverso ogni volta che viene valutato. Vale anche la pena menzionare i backtick. Se assumiamo Linux, possiamo usare, ad esempio, `head -1`invece di STDIN.gets.
Dennis,

@Dennis: "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";ti permetterebbe anche di definire un nuovo operatore GolfScript g che legge una riga da stdin e la inserisce nello stack.
Ilmari Karonen,

2

Decodifica input esadecimale

GolfScript non ha valori letterali interi esadecimali, quindi purtroppo non puoi semplicemente analizzare l'input esadecimale ~. Invece, se il tuo codice deve accettare input esadecimali, dovrai analizzarlo manualmente.

Questo ciclo di 8 caratteri, applicato a una stringa, convertirà le cifre esadecimali minuscole nei loro equivalenti numerici:

{39%9-}%

Se devi (anche) accettare cifre esadecimali maiuscole, la soluzione più semplice (e probabilmente la più breve) è prima di minuscole con 32|, per un totale di 11 caratteri:

{32|39%9-}%

Si noti che l'output sarà tecnicamente ancora una stringa (composta dai caratteri ASCII 0 - 15), ma anche la maggior parte delle funzioni dell'array GolfScript accetta stringhe. Se hai assolutamente bisogno di un array, puoi sempre usare [{39%9-}/](dove il primo [è facoltativo se lo stack è altrimenti vuoto).

Per convertire l'output del codice sopra in un numero intero, puoi semplicemente usare 16base(6 caratteri). Se invece desideri una matrice di byte, la soluzione più breve che ho trovato è semplicemente quella di decodificare ogni coppia di cifre esadecimali con 2/{16base}%(11 caratteri). Tutto sommato, il codice più corto che ho trovato per trasformare una stringa esadecimale in una matrice di byte è 8 + 11 = 19 caratteri:

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

Si noti che l'output di questo codice è effettivamente un array, non una stringa. Se necessario, è possibile stringa i che concatenando esso ad esempio con ""+o, se non ti dispiace un ritorno a capo extra alla fine, n+.


2

Definizione di nuovi operatori integrati

L'interprete GolfScript standard ha una funzione usata raramente che consente il codice Ruby interpolato in valori letterali di stringa tra virgolette doppie.

Uno dei motivi per cui questa funzione non è più comunemente usata è che, a disagio, il codice interpolato viene eseguito in fase di compilazione e l'output viene memorizzato nella cache dall'interprete GolfScript in modo che la stessa stringa letterale da allora in poi produrrà sempre lo stesso valore, anche all'interno valutazione delle stringhe.

Tuttavia, una cosa per cui questa funzionalità risulta utile è la definizione di nuovi operatori GolfScript implementati nel codice Ruby. Ad esempio, ecco come definire un nuovo operatore di aggiunta binaria che funziona esattamente come l' +operatore integrato standard :

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

Non importa dove metti la definizione nel tuo codice; il nuovo operatore viene definito non appena viene analizzata la stringa tra virgolette doppie contenente il codice Ruby. L' addoperatore sopra definito funziona esattamente come l' +operatore integrato e può essere utilizzato esattamente allo stesso modo:

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

Naturalmente, definire un nuovo operatore addizione è abbastanza inutile, a meno che tu non abbia fatto qualcosa di stupido come cancellare l' +operatore incorporato . Ma puoi usare lo stesso trucco per definire nuovi operatori che fanno cose che Golfscript non può (facilmente) fare nativamente come, per esempio, mescolare uniformemente un array:

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

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

o stampando il contenuto dell'intera pila:

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

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

o input interattivo:

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

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

o persino l'accesso al web:

"#{
  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

Naturalmente, un'implementazione un po 'più golfosa (e più rischiosa!) Di quest'ultima sarebbe ad esempio:

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

Sebbene non sia particolarmente golfoso in sé, ciò consente di estendere le capacità di GolfScript oltre a ciò che offrono i comandi integrati.


Come funziona?

Il riferimento autorevole su come definire i nuovi operatori GolfScript in questo modo è, ovviamente, il codice sorgente per l'interprete . Detto questo, ecco alcuni suggerimenti rapidi:

  • Per definire un nuovo operatore nameche esegue il codice Ruby code, utilizzare:

    var'name','code'.cc
  • All'interno del codice, utilizzare gpopper leggere un valore dallo stack e gpushper reinserirne uno. È inoltre possibile accedere allo stack direttamente tramite l'array $stack. Ad esempio, per spingere entrambi ae bnello stack, è più golfoso di $stack<<a<<bquello gpush a;gpush b.

    • Le posizioni dei [marker di inizio dell'array sono memorizzate $lbnell'array. La gpopfunzione si occupa di regolare questi marker verso il basso se lo stack si riduce al di sotto della loro posizione, ma la manipolazione $stackdiretta dell'array no.
  • Il .ccmetodo stringa che compila il codice Ruby in una stringa in un operatore GolfScript è solo un comodo wrapper Gblock.new(). Ha anche le varianti .cc1, .cc2e .cc3che rendono l'operatore pop automaticamente 1, 2 o 3 argomenti dallo stack e li assegna alle variabili a, be c. C'è anche un .ordermetodo che funziona come .cc2, tranne che ordina automaticamente gli argomenti per tipo di priorità .

  • Tutti i valori sullo stack GolfScript sono (e dovrebbe essere!) Oggetti di tipo Gint, Garray, Gstringo Gblock. L'intero o l'array nativo sottostante, ove necessario, è accessibile tramite il .valmetodo.

    • Tuttavia, si noti che Gstring.valrestituisce una matrice di Gints! Per trasformare a Gstringin una stringa Ruby nativa, chiamala .to_sinvece (o usala in un contesto che lo fa automaticamente, come l'interpolazione di stringhe). La chiamata .to_gsa qualsiasi valore GS lo trasforma in a Gstring, quindi è possibile stringere qualsiasi valore GS .to_gs.to_s.
  • La gpushfunzione non avvolge automaticamente numeri, stringhe o matrici di Ruby nativi nei corrispondenti tipi GS, quindi spesso dovrai farlo tu stesso chiamando esplicitamente ad es Gstring.new(). Se si inserisce nello stack qualcosa di diverso da uno dei tipi di valore GS, è probabile che si verifichi un arresto anomalo di qualsiasi codice che successivamente tenta di manipolarlo.

  • I tipi di valore GS hanno anche un .factorymetodo che chiama il costruttore del tipo, che può essere utile, ad esempio, per riavvolgere matrici / stringhe dopo averne manipolato il contenuto. Tutti i tipi hanno anche un .coercemetodo che esegue la coercizione del tipo : a.coerce(b)restituisce una coppia contenente ae bcostretta allo stesso tipo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.