Postscript'te golf oynamak için ipuçları?


14

Daha az popüler dillerden biri olarak, postscript hackery'nin avant garde hakkında literatür bulmak zordur. Peki, burada golfçüler, Postscript'in doğal ayrıntı düzeyini aşmak için yığın modelinden (veya diğer özelliklerden) yararlanmak için hangi keşifleri yaptı?


Yanıtlar:


3

Gömülü Kod Çözücü

Bir Postscript programının kendi program metnini veri olarak okuyabilmesi için eşsiz (?) Bir yeteneği vardır. Bu, normal olarak kullandığı imagebir alan operatör veri toplama-prosedürü girdi olarak alır ve bu işlem çoğu zaman kullanır currentfileve ardından readline, readstringya da readhexstring. Ancak başka bir şekilde görüldüğü gibi image, sadece başka bir döngü operatörüdür, böylece herhangi bir döngü önceden okuyabilir . Bir örnek, Yeşil Kitap'tan satır yazıcı öykünücüsüdür.

tokenOperatörün kullanılması, tarayıcıyı bir dosya veya dizgide çağırır, bir numara veya boşluk- (veya başka bir şekilde-: diğer cevaba bakın) -aydedilmiş bir ad çıkarır.

PS'de basit bir PS yorumlayıcısı:

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

İkili Operatör Dize Kod Çözücü

Benim için çalışmak için ham ikili belirteçleri elde edemediğim için (diğer cevaba bakın), kodu 8 bit dizelere paketlemek için ikili belirteç mekanizmasından yararlanmak için "katıştırılmış kod çözme" fikrini kullandım ve sonra komutları anında dizeden yönetin ve ayrıştırın .

/.{
    <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

.Prosedür iki baytlık bir dize yığını ve ikinci bayt olarak ekler bunu bir sayıyı alır, yürütülebilir bir sistem adı belirten ikili bir belirteci önek bayt, olmak ilk baytı. Onaltılık dizgideki bir baytı, onaltılık dizideki tek sayıdaki nibble'ların fazladan 0 bir parça ile doldurulduğunu, bu nedenle 3 adet altı adet 2 baytlık bir dize ürettiğini bir kural kullanarak kaydederiz. Daha sonra dize çalıştırılabilir olarak işaretlenir ve exectarayıcıyı çağırır, istenen yürütülebilir sistem adını üretir ve adı yükler ve işleci yürütür. $Kullanılarak, yığında bir dizi her bayt yapar .prosedür iki kez döngü operatör yürütülecek sonra bir kez döngü gövdesi olarak, ve forallsayısına göre.

Daha kompakt bir şekilde, bu prosedürler şöyle görünür:

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

Yani, 55 karakter ikili simge dizeleri satın alır. Ya da, karakter (bir boşluk ile sona belki 7) 6, yüklemek için G kütüphanesi ile (G)runolan tanımlar .ve $yukarıdaki gibi (birkaç başka + ASCII-ulaşılabilir kodları aralığını genişletmek için).

Daha fazla benim bulmaca cevap resimli .


1
Aslında, postscript kodlanmış bir formdaysa, bu şeyleri karşılaştırırken çok dikkatli olmanızı gerektirir. Eğer operatörler bakıyorsanız Özellikle, sen gerekir bir belirteç olarak ayrıştırmak ve sonra jetonun karşılaştırmak adını hedef değere.
AJMansfield

2

Grafiksel çıktı üreten ve konsol çıkış önemli değil zaman kullanmak =yerine pop.


2

Altıgenleri ASCII85 ile değiştirin

Muhtemelen eski haberler, ama yeni öğrendim. :)

Bunu bir kodlama filtresi ve kes ve yapıştır ile etkileşimli olarak postscript yorumlayıcısını kullanarak yapabilirsiniz. Ama dcbunu "elle" yapmak için nasıl kullanılacağını göstereceğim .

İşte bir onaltılı dize. 4 baytlık parçalara ayırdık.

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

DC'yi başlatırken, bunları 32 bit (işaretsiz) big-endian-byte-order numaraları olarak giriyoruz. Sonra mod -off base-85 basamak (0'a ulaşana kadar 5 olmalıdır).

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

Son parçayı doldurmak, 00 00ondalık değerlerle doldurur, doldurduğumuz aynı bayt sayısını atlar.

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

Yazdırılabilir ASCII ve puf aralığına geçmek için 33 ekleyin! ASCII85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
kod çözme: Postscript: is: f # V? Hata %%%! 'eğlenceli' demeli! Bir yere vidalandım. :)

Sarın <~... ~>ve Seviye-2 Postscript, onaltılıktan daha ucuz 8 bit verilere erişebilir.


2

İşte bir quickie: [...>>beginanahtar kelimeyi ortadan kaldırmak için çoklu tanımları sarın def(nb. İle [aynıdır <<).

 def def
[>>begin

Unutmayın: daha fazlaüçiki ... birlikte akın ! ;)


Kural "ikiden fazla" olmamalı mı? Karşılaştırma /a 1 def/b 2 def/c 3 defile <</a 1/b 2/c 3>>begin. Def için daha fazla alana ihtiyacımız var.
Thomas W.

Vay. Ben de öyle değildi. Evet, hesaplamanın iyileştirilmesi gerekiyor.
luser droog

Aslında, bu olmalı[/a 1/b 2/c 3>>begin
Thomas W.

yüz hurma. . . .
luser droog

1
Kendini sınırlayan bir belirteçle sona eren bir şeyi adlandırıyorsanız bu geçerli olmayabilir. Gelen /a{pop 2 mul}defveya \b[2 3]def, defsadece 3 karakter değil, 4. maliyeti
AJMansfield

2

En postscript operatörleri sözdizimsel tanımlayıcıları (ve bu nedenle uzay (veya otherwise- olmalı) ayrılmış), isimler olmakla birlikte [, ], <<ve >>kendi kendini sınırlayan ve tarayıcı yer müdahale olmadan bunları algılar. Aynı nedenle, bu adlara normal /literalsözdizimi ile başvuramazsınız (ör. /[İki simge: boş bir değişmez ad ()cvn cvlitve [eşdeğer yürütülebilir ad ([)cvn cvx exec).

İsimle belirtilemeyen bu isimleri yeniden tanımlamak için, sözlükte anahtar olarak kullanıldığında örtük olarak isimlere dönüştürülen dizeleri kullanabiliriz (uygun!).

Bu örnekte, bu işleçlerin aritmetik yapmak için kötüye kullanılması gösterilmektedir.

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

Ayrıca <<ve [(ve mark) hepsi aynı anlama gelir.


Kendi postscript tercümanım xpost da sağ kıvırcık ayracı bazı kısıtlamalarla sunuyor. tartışma


2
Ayrıca, /önceki jetonu sonlandırır, böylece ondan önce bir alana ihtiyacınız olmaz.
Geoff Reedy

1

Uzun operatör adlarının tekrarlanan kullanım faktörleri

Zaten bir <<>>beginsözlük kullanıyorsanız , /?{}yeniden tanımlama başına 4 karakterlik sabit bir ek yük vardır . Böylece, N kez tekrarlanan n uzunluğunda bir operatör, (4 + n ) - ( N * ( n - 1)) karakter sayısında bir değişiklik verecektir .

Bu formülü 0'a ayarlamak başabaş noktasının denklemini verir . Bundan
n = - ( N - 4) / (1 - N ) ve
N = (4 + n ) / ( n - 1) elde ederek her bir değişken için diğeri açısından çözebiliriz .

Hayır, "'print' kelimesinin kaç kullanımının kısaltılmasına değer?" Gibi soruları yanıtlayabiliriz. n = 5, yani N = 9/4. Baskıyı 1/4 kez etkili bir şekilde arayamayacağınız için tavanı alın. Yani, 3,3 kullanır. Ve gerçekten,

print print print
/P{print}p p p

( <<>>beginelbette tanımı etkinleştirmek için ek yükü ödediğinizi varsayarsak ).

Tabii ki, ikili belirteçler bu tür bir tartışma yapar ve size sistem adı tablosundaki ilk 255 adı 2 bayt olarak verir: 0x92, 0x ??. Ve ikili tokenler de kendini sınırlar, önce veya sonra boşluk gerektirmez, çünkü ilk baytın yüksek biti ascii aralığının dışındadır.


1

İkili Jetonlar

Nihai için zip-up PostScript programının son sınır olduğunu ikili belirteçleri artık ASCII temiz programına sahip pahasına, tamamen uzun operatör isimleri kaldırmanızı sağlar.

Sıkıştırılmış bir postscript kodu bloğundan başlayarak

[/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

PLRM'nin arkasındaki tüm isimlere bakıyoruz (Ek F, s. 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

Ve sonra bunları 146(ondalık) byte önekiyle yazın. keyfi bayt girmek için yardım vim

Daha sonra vim'de, yoğunlaştırılmış dosya doğrudan yazılabilir, bu nedenle:

[/ 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

... ^V-62'yi sonlandırmak ve 1'i başlatmak için buraya bir boşluk girmelisiniz , ancak daha sonra yedekleyip silebilirsiniz ...

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

... ^V-85'i sonlandırmak ve 1'i başlatmak için buraya bir boşluk girmelisiniz , ancak daha sonra yedekleyip silebilirsiniz ...

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

... 3 basamaklı kodun 3. basamağı bayt girişini sonlandırır, böylece 0burada normal, uygun şekilde ...

0 S ^V146 ^V167

Ekranda şöyle görünecek (vim cinsinden):

[/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>§

Amaç sadece bir resim göstermekse, bu tamamen atlanabilir. Ghostscript birçok şeyi ekrana gerek kalmadan boyar showpage.

¡    161   showpage

[ Bu aslında işe yaramıyor. Ghostscript bana undefinedve syntaxerrorbu jetonları veriyor . Belki de etkinleştirmem gereken bir mod var . ]


Belki bu programla ilgili bir şey . Online kompaktör de buna benzer değildir.
luser droog

1

Negatif ruloları pozitif olarak değiştirin

Negatif rulolar her zaman pozitif rulolara değiştirilebilir .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

Hangisi daha verimlidir 3 -1 rollya 3 2 roll? Zihinsel modelimde, birincisi daha etkili olmalı çünkü sadece bir hamle gerektiriyor. Zihinsel modelim doğru mu?
koltuk

Dürüst olmak gerekirse, emin değilim. İşte benim uygulaması tüm olumsuz rulo ilk adım olarak olumlu dönüştürülür. Ben hala en az 2 hareket (3. değeri yukarı taşımak, 3 değerleri aşağı taşımak ) yığın düz dizi uygulaması ile gerekli olacağını düşünüyorum . Ancak yığınım bölümlere ayrıldı, böylece erişim bölümleri yönetmek için işlev çağrılarından geçiyor; bu yüzden uygulamak için yaptığımdan daha etkili yollar var. ... Şimdi gördüğüm bir şey: Döngülerin dışında yığın akışını kontrol etmeliyim .
luser droog

1
Kaynak dosya son yorumumdan beri taşındı. İşte benim uygulaması var bir rolloperatör.
luser droog

0

G kitaplığımı kullan

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

Bir metin dosyası. Yüklemek için mümkün olan en kısa sözdizimi için uzantı yok.

Bu 203 karakterlik Sierpinksi Üçgen programına izin verir

[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

151 bayt olarak yeniden yazılacak

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

yorumlarla çalışma dosyası

Kısaltılmış sistem adları özelliğini kullanarak, 1(G)runuzun operatör adlarının yükünü tamamen ortadan kaldırır. Bir operatör adının yalnızca diğerlerinden ayırt edilebilmesi için yeterince uzun olması gerekir.

Yani

  • add olur ad
  • mul olur mu
  • index olur i
  • vs vs.

Standart operatör adları tablosu için PLRM Ek F'yi kullanın .

Kısaltılmış adlar seçilmemiş olsa bile Operatör Dizeleri özelliği kullanılabilir. Çıplak kütüphanede, (G)runbaşka süslemeler olmadan basitçe seçilen bir "taban seviyesi" vardır .

Temel seviye, .bir operatör için tamsayı kodunu kabul eden (yukarıda belirtilen aynı Ek F) yeni bir fonksiyon içerir ve onu çalıştırır.

Yeni işlev $bir dize üzerinden yinelenir ve .her birini çağırır . Böylece ascii kodu operatörü numaraya göre doğrudan seçer.

Yeni bir işlev @, boşluk karakterine (Ascii 0x20) 0 olarak davranarak Ek F'deki tablonun altına inmenizi sağlar.

Yeni bir işlev #önce 95 (0x5F) ekleyerek tabloya daha fazla erişmenizi sağlar, böylece 0x20 boşluk karakteri 127 (0x7F) olarak ele alınır, son yazdırılabilir ascii karakteri ~126'dan (0x7E) sonraki kod .

İki yeni işlev , birçok (ve ) operatörün sıkıcı ifadelerinden ziyade, dizin ve anahtarların !bir dizi diziniyle derinden iç içe dizilerin ve / veya dikmelerin yapısına erişmenizi sağlar .getput

(G)run 7 karakter taban seviyesini satın alır.

1(G)run 8 karakter satın alır VE sistem adlarını kısaltır.

3(G)run $9 karakter hemen başlar blok örtülü-prosedürü tarama kaynakları hatları sonraki boş satır ve adı verilen bir işlem olarak birinci çizgi tanımlaması kadar A, bir sonraki hat olarak adlandırılan bir yöntem olarak tanımlanır Ben Bu çıkarmak gerekir, vb deftanımlamak için gerekli olan s bunları bir sözlüğe sarmaya gerek kalmadan ve hatta açıkça ad vermeden birçok şey.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.