Suggerimenti per giocare a golf in Postscript?


Risposte:


3

Decodificatore incorporato

Un programma Postscript ha una capacità unica (?) Di leggere il proprio testo del programma come dati. Questo è normalmente utilizzato dal imagegestore che riceve un -acquisizione dati procedura come input, e questa procedura utilizza spesso currentfileseguito da readline, readstringo readhexstring. Ma visto in un altro modo, imageè solo un altro operatore di loop, quindi qualsiasi loop può leggere di nuovo . Un esempio è l'emulatore di stampante di linea del Libro verde.

L'utilizzo tokendell'operatore richiama lo scanner su un file o una stringa, estraendo un numero o uno spazio (o altro-: vedi altra risposta) nome delimitato.

Un semplice interprete PS in PS:

{currentfile token not {exit} if dup type /arraytype ne {exec} if }loop

Decodificatore di stringa dell'operatore binario

Dal momento che non riesco a far funzionare i token binari non elaborati per me (vedi altre risposte), ho fatto uso dell'idea di "decodifica incorporata" per sfruttare il meccanismo di token binario per comprimere il codice in stringhe di 8 bit e quindi manipola e analizza i comandi dalla stringa al volo .

/.{
    <920>  % two-byte binary-encoded name template with 0x92 prefix
    dup 1 4 3 roll put  % insert number into string
    cvx exec  % and execute it
}def
/${
    //.   %the /. procedure body defined above
    73 .  %"forall" (by code number)
}def

La .procedura prende un numero dallo stack e lo inserisce come secondo byte in una stringa di due byte, il primo byte è il byte prefisso per un token binario, specificando un nome di sistema eseguibile. Salviamo un byte nell'esagono utilizzando una regola dello scanner in base alla quale un numero dispari di stuzzichini nell'esagono viene riempito con uno stuzzichino 0 aggiuntivo, quindi 3 stuzzichini esadecimali producono una stringa di 2 byte. La stringa viene quindi contrassegnata come eseguibile e chiamata con la execquale richiama lo scanner, produce il nome del sistema eseguibile desiderato, quindi carica il nome ed esegue l'operatore. Lo $fa su ogni byte di una stringa nello stack, usando la .procedura due volte , una volta come il corpo del ciclo, e quindi per eseguire l'operatore di ciclo in forallbase al numero.

In modo più compatto, queste procedure si presentano così:

 /.{<920>dup 1 4 3 roll put cvx exec}def/${//. 73 .}def
%123457890123456789012345678901234567890123456789012345
%        1         2         3         4         5

Quindi, 55 caratteri acquistano stringhe binarie di token. Oppure, per 6 caratteri (forse 7, se lo si termina con uno spazio), è possibile caricare la libreria G con la (G)runquale definisce .e $come sopra (+ alcuni altri per estendere l'intervallo di codici ascii-raggiungibili).

Illustrato ulteriormente nella mia risposta al cruciverba .


1
In realtà, se il Postscript è in forma codificata, allora è necessario prestare particolare attenzione al confronto delle cose. In particolare, se si osservano gli operatori, è necessario analizzarlo come token e quindi confrontare il nome del token con il valore target.
AJMansfield,

2

Quando si genera output grafico e l'output della console non ha importanza, utilizzare =invece di pop.


2

Sostituire le stringhe con ASCII85

Probabilmente vecchie notizie, ma l'ho appena imparato. :)

Puoi farlo utilizzando l'interprete Postscript in modo interattivo con un filtro di codifica e taglia e incolla. Ma ho intenzione di mostrare come utilizzare dcper farlo "a mano".

Quindi, ecco una stringa esadecimale. Lo abbiamo suddiviso in blocchi di 4 byte.

95 20 6e d8   d0 59 49 35   50 74 ba c5   08 2d

Accendendo dc, li inseriamo come numeri a 32 bit (non firmati) di ordine di byte big-endian. Quindi mod -off base-85 cifre (dovrebbero esserci 5 fino ad arrivare a 0).

0> dc
16i
95206ED8
Ai
D85% N85 /
82
D85% N85 /
83
D85% N85 /
82
D85% N85 /
78
D85% N85 /
47
D85% N85 /
0                    

Il riempimento dell'ultimo blocco con 00 00, produce (decimale), omettendo lo stesso numero di byte che abbiamo riempito.

47 78 82 83 82   66 81 72 79 83   25 72 82 25 69  2 53 30 [2 53]

Aggiungi 33 per passare alla gamma stampabile di ASCII e poof! ASCII85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
che decodifica in: Postscript: is: f # V? %%% Oops! dovrei dire "divertente"! Ho fatto un casino da qualche parte. :)

Avvolgilo in <~... ~>e Postscript di livello 2 può accedere ai dati a 8 bit, più economico di esadecimale.


2

Ecco una breve: avvolgere più definizioni [...>>beginper eliminare la parola chiave def(nb. [È la stessa di <<).

 def def
[>>begin

Quindi ricorda: più ditredue ... si affollano insieme ! ;)


La regola non dovrebbe essere "più di due"? Confronta /a 1 def/b 2 def/c 3 defcon <</a 1/b 2/c 3>>begin. Abbiamo bisogno di più spazi per def.
Thomas W.

Wow. Non ci avevo pensato. Sì, il calcolo deve essere migliorato.
Luser droog

In realtà, questo dovrebbe essere[/a 1/b 2/c 3>>begin
Thomas W.

faccia di palma. . . .
Luser droog

1
Ciò potrebbe non applicarsi se si sta nominando qualcosa che termina con un token di delimitazione automatica. In /a{pop 2 mul}defo \b[2 3]def, l' defunico costo è di 3 caratteri, non 4.
AJMansfield,

2

Mentre la maggior parte degli operatori di postscript sono identificatori sintattici (e quindi devono essere delimitati da spazio (o altrimenti)), i nomi [, ]e <<, >>sono auto-delimitati e lo scanner li rileverà senza spazio di intervento. Per lo stesso motivo, non è possibile fare riferimento a questi nomi con la solita /literalsintassi (ad es. Sono /[due token: un nome letterale vuoto equivalente a ()cvn cvlite il nome eseguibile [equivalente a ([)cvn cvx exec).

Per ridefinire questi nomi, che non possono essere menzionati per nome, possiamo usare stringhe che sono implicitamente convertite in nomi quando usate come chiavi in ​​un dizionario (conveniente!).

Questo esempio illustra l'abuso di questi operatori per eseguire l'aritmetica.

%!
([)0 def
(])1 def
(<<){add}def
(>>){mul}def
 ]]<<]]]<<<<>> =
%1 1 add 1 1 1 add add mul = %prints 6

Anche <<e [(e mark) significano tutti la stessa cosa.


Il mio interprete PostScript , xpost , rende disponibile anche la parentesi graffa a destra con alcune restrizioni. discussione


2
Inoltre, /termina il token precedente in modo da non aver bisogno di uno spazio prima di esso.
Geoff Reedy,

1

Fattorizza gli usi ripetuti di nomi di operatori lunghi

Se stai già utilizzando un <<>>begindizionario, c'è un sovraccarico costante di /?{}4 caratteri per ridefinizione. Quindi un operatore di lunghezza n ripetuta N volte produrrà una variazione del conteggio dei caratteri di
(4 + n ) - ( N * ( n - 1)).

Impostando questa formula su 0 si ottiene l'equazione del punto di pareggio . Da questo possiamo risolvere per ogni variabile in termini di altra, dando
n = - ( N - 4) / (1 - N ) e
N = (4 + n ) / ( n - 1).

No, possiamo rispondere a domande come "Per quanti usi di 'stampa' vale la pena abbreviare?" n = 5, quindi N = 9/4. Prendi il soffitto, poiché non puoi chiamare la stampa in modo efficace 1/4 volte. Quindi, 3. 3 usi. E senza dubbio,

print print print
/P{print}p p p

(supponendo che tu abbia già pagato l'overhead di <<>>beginattivare la definizione, ovviamente).

Naturalmente, i token binari rendono questo tipo di moot, dandoti i primi 255 nomi dalla tabella dei nomi di sistema come 2 byte: 0x92, 0x ??. E i token binari sono anche auto-delimitazione, non richiedono spazi bianchi prima o dopo, poiché il bit alto del primo byte è al di fuori dell'intervallo ascii.


1

Token binari

Per lo zip-up finale di un programma PostScript, quella frontiera finale sono i token binari che consentono di rimuovere completamente i nomi di operatori lunghi, a costo di non avere più un programma ASCII-clean.

Quindi a partire da un blocco compatto di codice PostScript

[/T[70{R 0 rlineto}48{}49{}43{A rotate}45{A neg rotate}91{currentdict
end[/.[currentpoint matrix currentmatrix]cvx>>begin begin}93{. setmatrix
moveto currentdict end end begin}>>/S{dup B eq{T begin exch{load exec}forall
end}{exch{load exch 1 add S}forall}ifelse 1 sub }>>begin moveto 0 S stroke

Cerchiamo tutti i nomi sul retro del PLRM (Appendice F, pagg. 795-797)

appearance
in
vim    dec  meaning

<92>   146  'executable system name' binary token prefix
^A     1    add
^M     13   begin
^^     30   currentdict
'      39   currentmatrix
(      40   currentpoint
2      50   cvx
8      56   dup
9      57   end
=      61   eq  !)
>      62   exch
?      63   exec
I      73   forall
U      85   ifelse
d      100  load
h      104  matrix
k      107  moveto
n      110  neg
<85>   133  rlineto
<88>   136  rotate
§      167 stroke
©      169 sub

Quindi digitarli come prefissi da un 146byte (decimale). vim help per l'immissione di byte arbitrari

Quindi in vim, il file condensato può essere digitato direttamente, quindi:

[/ T [70 {R 0 ^V146 ^V133} 48 {} 49 {} 43 {A ^V146 ^V136} 45 {A ^V146 ^V110 ^V146 ^V136} 91 { ^V146 ^V30 ^V146 ^V57 [/. [ ^V146 ^V40 ^V146 ^V104 ^V146 ^V39] ^V146 ^V50 >> ^V146 ^V13 ^V146 ^V13} 93 {. ^V146 ^V156 ^V146 ^V107 ^V146 ^V30 ^V146 ^V57 ^V146 ^V57 ^V146 ^V13} >> / S { ^V146 ^V56 B ^V146 ^V61 {T ^V146 ^V13 ^V146 ^V62 { ^V146 ^V100 ^V146 ^V63}^V146 ^V73 ^V146 ^V57} { ^V146 ^V62 { ^V146 ^V100 ^V146 ^V62

... devi inserire uno spazio qui per terminare il ^V-62 e iniziare il 1, ma puoi eseguire il backup ed eliminarlo in seguito ...

1 ^V146 ^V1S} ^V146 ^V73} ^V146 ^V85

... ^Vdevi inserire uno spazio qui per terminare il -85 e avviare il 1, ma puoi eseguire il backup ed eliminarlo in seguito ...

1 ^V146 ^V169} >> ^V146 ^V13 ^V146 ^V107

... la terza cifra del codice a 3 cifre termina l'immissione dei byte, quindi quanto segue 0è normale, convenientemente ...

0 S ^V146 ^V167

Che apparirà così sullo schermo (in vim):

[/T[70{R 0<92><85>}48{}49{}43{A<92><88>}45{A<92>n<92><88>}
91{<92>^^<92>9[/.[<92>(<92>h<92>']<92>2>>
<92>^M<92>^M}93{.<92><9c><92>k<92>^^<92>9<92>9<92>^M}
>>/S{<92>8B<92>={T<92>^M<92>>{<92>d<92>?}<92>I<92>9}{<92>>
{<92>d<92>>1<92>^AS}<92>I}<92>U1<92>©}>><92>^M
<92>k0 S<92>§

Questo spesso può essere omesso del tutto se l'obiettivo è solo quello di mostrare un'immagine. Ghostscript dipinge la maggior parte delle cose sullo schermo senza bisogno showpage.

¡    161   showpage

[ Questo in realtà non funziona. Ghostscript mi ​​sta dando undefinede syntaxerrorper questi token. Forse c'è qualche modalità che devo abilitare. ]


Forse è qualcosa su questo programma. Il compattatore online non piace.
Luser droog

1

Cambia i tiri negativi in ​​positivi

I tiri negativi possono sempre essere cambiati in tiri positivi .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

Qual è più efficiente 3 -1 rollo 3 2 roll? Nel mio modello mentale, il primo dovrebbe essere più efficiente perché richiede solo una mossa. Il mio modello mentale è corretto?
bacia la mia ascella il

Onestamente, non ne sono sicuro. Ecco la mia implementazione , in cui tutti i tiri negativi vengono convertiti in positivi come primo passo. Penso che richiederebbe comunque almeno 2 mosse (sposta il 3o valore in alto , sposta 3 valori in basso ) con un'implementazione flat-array dello stack. Ma il mio stack è segmentato, quindi l'accesso passa attraverso le chiamate di funzione per gestire i segmenti; quindi ci sono sicuramente modi più efficaci di implementare di quanto io abbia fatto. ... Una cosa che vedo ora: dovrei controllare lo stackunderflow al di fuori dei loop.
Luser droog,

1
Il file di origine è stato spostato dal mio ultimo commento. Ecco la mia implementazione del rollgestore.
Luser droog,

0

Usa la mia libreria G.

https://github.com/luser-dr00g/G

È un file di testo. Nessuna estensione, per caricare la sintassi più breve possibile.

Permette questo programma Triangolo Sierpinksi da 203 caratteri

[48(0-1+0+1-0)49(11)43(+)45(-)/s{dup
0 eq{exch{[48{1 0 rlineto}49 1 index
43{240 rotate}45{120 rotate}>>exch
get exec}forall}{exch{load
exch 1 sub s}forall}ifelse 1 add}>>begin
9 9 moveto(0-1-1)9 s fill

da riscrivere in 151 byte come

3(G)run $
{A - B + A + B - A}
{B B}

{A - B - B}7{[ex{du w{(>K?\2u)$}if}fora]}rep
cvx[/A{3 0 rl}/B 1 in/-{120 rot}/+{-120 rot}>>b
100 200(k?B9)$ showp

file di lavoro con commenti

L'uso della funzione abbreviata per i nomi dei sistemi 1(G)runrimuove completamente l'onere dei nomi di operatori lunghi. Il nome di un operatore deve essere abbastanza lungo da distinguerlo dagli altri.

Così

  • add diventa ad
  • mul diventa mu
  • index diventa i
  • ecc. ecc.

Utilizzare l' appendice F PLRM per la tabella standard dei nomi degli operatori.

E la funzione di Operator Strings è disponibile anche se i nomi abbreviati non sono selezionati. La libreria vuota ha un "livello base" selezionato aggiungendo semplicemente(G)run senza ulteriori decorazioni.

Il livello base include una nuova funzione .che accetta il codice intero per un operatore (la stessa Appendice F menzionata sopra) e lo esegue.

La nuova funzione $scorre attraverso una stringa e chiama .ciascuna. Quindi il codice ascii seleziona direttamente l'operatore per numero.

Una nuova funzione @consente di raggiungere la parte inferiore della tabella nell'Appendice F trattando il carattere dello spazio (Ascii 0x20) come 0.

Una nuova funzione #ti consente di accedere più in alto alla tabella aggiungendo prima 95 (0x5F) in modo che il carattere spaziale 0x20 sia trattato come 127 (0x7F), il codice immediatamente successivo all'ultimo carattere ASCII stampabile~ 126 (0x7E).

Due nuove funzioni !consentono di accedere a una struttura profondamente annidata di matrici e / o dicts con una matrice di indici di indici / chiavi, anziché espressioni noiose di molti get(e put) operatori.

(G)run 7 caratteri acquista il livello base.

1(G)run 8 caratteri acquistano E nomi di sistema abbreviati.

3(G)run $9 caratteri iniziano immediatamente un blocco di procedura implicita scansionando le righe di origine fino alla riga vuota successiva e definendo la prima riga come una procedura chiamata A, la riga successiva viene definita come una procedura chiamata B, ecc. Ciò dovrebbe rimuovere la maggior parte delle defs necessarie per la definizione un sacco di cose, senza la necessità di avvolgerle in un dizionario, né di dare loro nomi espliciti.

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.