เคล็ดลับในการเล่นกอล์ฟใน Postscript?


14

ในฐานะที่เป็นหนึ่งในภาษาที่ได้รับความนิยมน้อยมันเป็นเรื่องยากที่จะหาวรรณกรรมเกี่ยวกับกลุ่มแฮ็กเกอร์ที่มีคำลงท้าย ดังนั้นการค้นพบสิ่งที่นักกอล์ฟได้ทำที่นี่เพื่อใช้ประโยชน์จากแบบจำลองสแต็ก (หรือคุณสมบัติอื่น ๆ ) เพื่อเอาชนะความฟุ้งซ่านโดยธรรมชาติของ Postscript?


พบหน้าภายนอกบางแห่ง: sites.google.com/site/codegolfingtips/Postscript
luser droog

คำตอบ:


3

ตัวถอดรหัสแบบฝัง

โปรแกรม Postscript มีความสามารถพิเศษ (?) ในการอ่านข้อความของโปรแกรมเป็นข้อมูล นี้จะใช้ตามปกติโดยimageผู้ประกอบการที่ได้รับการเก็บข้อมูลขั้นตอนเป็น input และขั้นตอนนี้มักจะใช้currentfileตามด้วยreadline, หรือreadstring readhexstringแต่เห็นวิธีอื่นimageเป็นเพียงตัวดำเนินการวนซ้ำดังนั้นการวนซ้ำใด ๆ สามารถอ่านล่วงหน้าได้ ตัวอย่างคืออีมูเลเตอร์เครื่องพิมพ์บรรทัดจาก Green Book

การใช้tokenโอเปอเรเตอร์จะเรียกใช้สแกนเนอร์ในไฟล์หรือสตริงดึงหมายเลขหรือพื้นที่ - (หรือมิฉะนั้น -: ดูคำตอบอื่น ๆ ) - ชื่อที่ถูก จำกัด

ตัวแปล PS อย่างง่ายใน PS:

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

ตัวถอดรหัสสตริงของตัวดำเนินการไบนารี

เนื่องจากฉันไม่สามารถรับโทเค็นไบนารีแบบดิบให้ทำงานได้สำหรับฉัน (ดูคำตอบอื่น) ฉันจึงใช้แนวคิด "การถอดรหัสแบบฝังตัว" เพื่อใช้ประโยชน์จากกลไกโทเค็นแบบไบนารีเพื่อแพ็คโค้ดลงในสตริง 8 บิตจากนั้น จัดการและแยกคำสั่งจากสายการบิน

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

.ขั้นตอนจะใช้เวลาเป็นจำนวนมากจากสแต็คและแทรกเป็นไบต์ที่สองในสตริงสองไบต์ไบต์แรกเป็นคำนำหน้าไบต์สำหรับโทเค็นไบนารีระบุชื่อระบบปฏิบัติการ เราบันทึกไบต์ใน hexstring โดยใช้กฎของสแกนเนอร์ที่จำนวน nibbles ใน hexstring จะถูกเพิ่มด้วย 0 nibble พิเศษดังนั้น 3 nibbles hex จึงสร้างสตริงที่ 2 ไบต์ จากนั้นสตริงจะถูกทำเครื่องหมายว่าสามารถเรียกทำงานได้และเรียกใช้execซึ่งเรียกใช้สแกนเนอร์สร้างชื่อระบบปฏิบัติการที่ต้องการจากนั้นโหลดชื่อและเรียกใช้งานตัวดำเนินการ สิ่ง$นี้ทำในแต่ละไบต์ของสตริงบนสแต็กใช้.โพรซีเดอร์สองครั้งหนึ่งครั้งเป็นตัวลูปและจากนั้นจะดำเนินการตัวดำเนินการลูปforallตามหมายเลข

ขนาดกะทัดรัดยิ่งขึ้นขั้นตอนเหล่านี้มีลักษณะดังนี้:

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

ดังนั้น 55 chars ซื้อสตริงโทเค็นไบนารี หรือสำหรับ 6 (อาจจะ 7 ถ้าคุณบอกเลิกด้วยช่องว่าง) ตัวอักษรคุณสามารถโหลดห้องสมุด Gกับ(G)runที่กำหนด.และ$ข้างต้น (+ บางคนอื่น ๆ ที่จะขยายช่วงของรหัส ascii-สามารถเข้าถึงได้) ที่

ภาพประกอบต่อไปในของฉันคำตอบปริศนาอักษรไขว้


1
ที่จริงแล้วถ้า postscript อยู่ในรูปแบบการเข้ารหัสคุณจะต้องระมัดระวังเป็นพิเศษเกี่ยวกับการเปรียบเทียบสิ่งของ หากคุณกำลังดูโอเปอเรเตอร์คุณจะต้องวิเคราะห์มันเป็นโทเค็นแล้วเปรียบเทียบชื่อโทเค็นกับค่าเป้าหมาย
AJMansfield


2

แทนที่ hexstrings ด้วย ASCII85

อาจเป็นข่าวเก่า แต่ฉันเพิ่งเรียนรู้ :)

คุณสามารถทำได้โดยใช้ล่าม postscript โต้ตอบกับตัวกรองการเข้ารหัสและการตัดและวาง แต่ฉันจะแสดงให้เห็นว่าจะใช้dcมันอย่างไร "ด้วยมือ"

ดังนั้นนี่คือสตริงฐานสิบหก เราแบ่งมันเป็น 4 ไบต์

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

เมื่อยิงขึ้น dc เราป้อนข้อมูลเหล่านี้เป็นหมายเลขลำดับ 32 บิต (ไม่มีลายเซ็น) big-endian-byte จากนั้นmod -off base-85 ดิจิต (ควรมี 5 จนกว่าคุณจะได้รับถึง 0)

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

การเติมก้อนสุดท้ายด้วย00 00, ให้ผล (ทศนิยม), ละเว้นจำนวนไบต์เดียวกันกับที่เราเพิ่ม

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

เพิ่ม 33 เพื่อเปลี่ยนเป็นช่วงที่พิมพ์ได้ของ ASCII และกะเทย! ASCII85

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
ซึ่งถอดรหัสเป็น: Postscript: คือ: f # V? %%% Oops! ควรพูดว่า 'สนุก'! ฉันเมาที่ไหนสักแห่ง :)

ห่อไว้ใน<~... ~>และ Postscript ระดับ 2 สามารถเข้าถึงข้อมูล 8 บิตราคาถูกกว่าฐานสิบหก


2

ต่อไปนี้เป็น quickie: ตัดคำจำกัดความหลายคำ[...>>beginเพื่อกำจัดคำหลักdef(nb. [เหมือนกับ<<)

 def def
[>>begin

ดังนั้นอย่าลืม: มากกว่าสามสอง ... แห่กัน ! ;)


กฎไม่ควรเป็น "มากกว่าสอง" หรือไม่? เปรียบเทียบกับ/a 1 def/b 2 def/c 3 def <</a 1/b 2/c 3>>beginเราต้องการพื้นที่เพิ่มเติมสำหรับ def
โธมัสดับเบิลยู.

ว้าว. ฉันไม่ได้คิดอย่างนั้น ใช่การคำนวณจำเป็นต้องได้รับการปรับปรุง
luser droog

ที่จริงแล้วควรเป็น[/a 1/b 2/c 3>>begin
Thomas W.

ใบหน้าปาล์ม . . .
luser droog

1
สิ่งนี้อาจใช้ไม่ได้หากคุณกำลังตั้งชื่อสิ่งที่สิ้นสุดในโทเค็นที่คั่นด้วยตนเอง ใน/a{pop 2 mul}defหรือ\b[2 3]defที่defค่าใช้จ่ายเพียง 3 ตัวอักษรไม่ 4.
AJMansfield

2

ในขณะที่ผู้ประกอบการส่วนใหญ่เป็นคำลงท้าย syntactically ตัวระบุ (และดังนั้นจึงต้องเนื้อที่ (หรือ otherwise-) คั่น), ชื่อ[, ], <<และ>>เป็นตัว delimiting และสแกนเนอร์จะตรวจสอบได้โดยไม่ต้องแทรกแซงพื้นที่ ด้วยเหตุผลเดียวกันคุณไม่สามารถอ้างถึงชื่อเหล่านี้ด้วย/literalไวยากรณ์ปกติ(เช่น/[เป็นโทเค็นสองรายการ: ชื่อตัวอักษรที่ว่างเปล่าเทียบเท่ากับ()cvn cvlitและชื่อปฏิบัติการที่[เทียบเท่า([)cvn cvx exec)

เพื่อที่จะกำหนดชื่อเหล่านี้ใหม่ซึ่งไม่สามารถพูดถึงด้วยชื่อเราสามารถใช้สตริงที่ถูกแปลงเป็นชื่อโดยนัยเมื่อใช้เป็นคีย์ในพจนานุกรม (สะดวก!)

ตัวอย่างนี้แสดงการใช้โอเปอเรเตอร์เหล่านี้ในทางที่ผิดเพื่อทำการคำนวณ

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

นอกจากนี้<<และ[(และmark) ทั้งหมดหมายถึงสิ่งเดียวกัน


ล่าม PostScript ของฉันเองxpostยังทำให้วงเล็บปีกกาหยิกขวาพร้อมกับข้อ จำกัด บางอย่าง อภิปรายผล


2
นอกจากนี้/จบโทเค็นก่อนหน้าเพื่อให้คุณไม่จำเป็นต้องมีช่องว่างก่อน
Geoff Reedy

1

การใช้ชื่อผู้ดำเนินการแบบยาวซ้ำซ้อน

หากคุณใช้<<>>beginพจนานุกรมอยู่แล้วมีค่าใช้จ่ายคงที่/?{}4 ตัวอักษรต่อการกำหนดค่าใหม่ ดังนั้นโอเปอเรเตอร์ของความยาวnซ้ำแล้วซ้ำอีกครั้งNจะให้การเปลี่ยนจำนวนตัวอักษรของ
(4 + n ) - ( N * ( n - 1))

การตั้งสูตรนี้เท่ากับ 0 ให้สมการของการทำลายแม้กระทั่งจุด จากนี้เราสามารถแก้ปัญหาสำหรับแต่ละตัวแปรในแง่ของอื่น ๆ ให้ผลตอบแทน
n = - ( N - 4) / (1 - N ) และ
N = (4 + n ) / ( n - 1)

ไม่เราสามารถตอบคำถามเช่น "การใช้ 'การพิมพ์' มีประโยชน์ต่อการใช้อักษรย่อกี่ครั้ง? n = 5 ดังนั้นN = 9/4 ใช้เพดานเนื่องจากคุณไม่สามารถเรียกพิมพ์ 1/4 ครั้งได้อย่างมีประสิทธิภาพ ดังนั้น 3 3 ใช้ และแน่นอน

print print print
/P{print}p p p

(สมมติว่าคุณจ่ายค่าโสหุ้ย<<>>beginไปแล้วเพื่อเปิดใช้งานคำจำกัดความของหลักสูตร)

แน่นอนว่าโทเค็นไบนารีทำให้การทำแบบนี้ทำให้คุณมี 255 ชื่อแรกจากตารางชื่อระบบเป็น 2 ไบต์: 0x92, 0x ?? และโทเค็นไบนารี่ก็ยังสามารถกำหนดเองได้โดยไม่ต้องมีช่องว่างก่อนหรือหลังเนื่องจากบิตแรกของไบต์สูงอยู่นอกช่วงแอสทู


1

โทเค็นไบนารี

สำหรับzip-up ที่ดีที่สุดของโปรแกรม PostScript ที่ชายแดนสุดท้ายเป็นโทเค็นไบนารีซึ่งช่วยให้คุณสามารถลบชื่อตัวดำเนินการที่ยาวได้อย่างสมบูรณ์โดยไม่มีค่าใช้จ่ายที่จะต้องมีโปรแกรม ASCII-clean อีกต่อไป

ดังนั้นเริ่มต้นด้วยการบีบอัดบล็อกรหัส ป.ล.

[/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 (ภาคผนวก F, pp. 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

จากนั้นพิมพ์คำนำหน้าด้วย146ไบต์ (ทศนิยม) เป็นกลุ่มช่วยสำหรับการป้อนไบต์โดยพลการ

จากนั้นเป็นกลุ่มไฟล์แบบย่อสามารถพิมพ์ได้โดยตรงดังนั้น:

[/ 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 และเริ่มต้น 1 แต่คุณสามารถสำรองและลบได้ในภายหลัง ...

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

... ต้องป้อนช่องว่างที่นี่เพื่อยกเลิก^V-85 และเริ่ม 1 แต่คุณสามารถสำรองและลบในภายหลัง ...

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

... หลักที่ 3 ของรหัส 3 หลักยุติการเข้าไบต์ดังนั้นสิ่งต่อไปนี้0เป็นเรื่องปกติสะดวก ...

0 S ^V146 ^V167

ซึ่งจะมีลักษณะเช่นนี้บนหน้าจอ (เป็นกลุ่ม):

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

คนนี้มักถูกมองข้ามไปอย่างสิ้นเชิงหากเป้าหมายเพียงเพื่อแสดงรูปภาพ Ghostscript showpageวาดสิ่งที่มากที่สุดที่หน้าจอโดยไม่จำเป็น

¡    161   showpage

[ อันนี้ใช้งานไม่ได้จริง ๆ Ghostscript ให้ฉันundefinedและsyntaxerrorโทเค็นเหล่านี้ อาจมีบางโหมดที่ฉันต้องเปิดใช้งาน ]


บางทีมันอาจจะเป็นสิ่งที่เกี่ยวกับการนี้โปรแกรม อัดออนไลน์ไม่ชอบมันอย่างใดอย่างหนึ่ง
luser droog

1

เปลี่ยนม้วนเชิงลบเป็นบวก

ม้วนเชิงลบสามารถเปลี่ยนเป็นม้วนบวกได้เสมอ

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

ซึ่งมีประสิทธิภาพมากขึ้น3 -1 rollหรือ3 2 roll? ในแบบจำลองจิตของฉันอดีตควรมีประสิทธิภาพมากขึ้นเพราะใช้เวลาเพียงหนึ่งย้าย แบบจำลองทางจิตของฉันถูกต้องหรือไม่
จูบรักแร้ของฉัน

พูดตามตรงฉันไม่แน่ใจ นี่คือการดำเนินการของฉันที่ม้วนเชิงลบทั้งหมดจะถูกแปลงเป็นบวกตามขั้นตอนแรก ฉันคิดว่ามันจะยังคงต้องมีอย่างน้อย 2 ย้าย (ย้ายค่าที่ 3 ขึ้นไปย้าย 3 ค่าลง ) ด้วยการใช้แบนด์อาร์เรย์ของกอง แต่สแต็กของฉันถูกแบ่งกลุ่มดังนั้นการเข้าถึงผ่านการเรียกใช้ฟังก์ชันเพื่อจัดการกลุ่ม ดังนั้นจึงมีวิธีการใช้งานที่มีประสิทธิภาพมากกว่าที่ฉันเคยทำ ... สิ่งหนึ่งที่ฉันเห็นในตอนนี้: ฉันควรตรวจสอบสแต็คเดอร์โฟลว์ด้านนอกลูป
luser droog

1
ไฟล์ต้นฉบับย้ายมาตั้งแต่ความคิดเห็นล่าสุดของฉัน นี่คือการดำเนินการของrollผู้ประกอบการของฉัน
luser droog

0

ใช้ห้องสมุด G ของฉัน

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

มันเป็นไฟล์ข้อความ ไม่มีส่วนขยายสำหรับไวยากรณ์ที่สั้นที่สุดที่เป็นไปได้ในการโหลด

อนุญาตให้โปรแกรมสามเหลี่ยม Sierpinksi 203-char นี้

[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 bytes เป็น

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

workfile พร้อมความคิดเห็น

การใช้คุณสมบัติชื่อระบบย่อนั้น1(G)runจะช่วยลดภาระของชื่อผู้ดำเนินการที่มีความยาวได้อย่างสมบูรณ์ ชื่อโอเปอเรเตอร์ต้องยาวพอที่จะแยกความแตกต่างจากชื่ออื่นเท่านั้น

ดังนั้น

  • add กลายเป็น ad
  • mul กลายเป็น mu
  • index กลายเป็น i
  • ฯลฯ

ใช้PLRMภาคผนวก F สำหรับตารางชื่อผู้ดำเนินการมาตรฐาน

และคุณสมบัติของ Operator Strings จะสามารถใช้งานได้แม้ว่าจะไม่ได้เลือกชื่อย่อ ไลบรารีเปล่ามีการเลือก "ระดับฐาน" โดยเพิ่มอย่างง่าย ๆ(G)runโดยไม่มีการตกแต่งเพิ่มเติม

ระดับฐานรวมถึงฟังก์ชั่นใหม่ .ที่ยอมรับรหัสจำนวนเต็มสำหรับผู้ประกอบการ (ภาคผนวก F เดียวกันที่กล่าวถึงข้างต้น) และดำเนินการมัน

ฟังก์ชั่นใหม่$วนซ้ำผ่านสตริงและการเรียก.แต่ละอัน ดังนั้นรหัส ascii จะเลือกผู้ให้บริการโดยตรงตามหมายเลข

ฟังก์ชั่นใหม่ @ช่วยให้คุณเอื้อมถึงด้านล่างของตารางในภาคผนวก F โดยปฏิบัติกับอักขระช่องว่าง (Ascii 0x20) เป็น 0

ฟังก์ชั่นใหม่#ช่วยให้คุณสามารถเข้าถึงเพิ่มเติมในตารางได้โดยการเพิ่ม 95 (0x5F) ก่อนดังนั้น space char 0x20 จะถือว่าเป็น 127 (0x7F) ซึ่งเป็นรหัสถัดไปหลังจากตัวอักษร ascii สุดท้ายที่พิมพ์ได้~ 126 (0x7E)

ฟังก์ชั่นใหม่สองฟังก์ชั่นใหม่!ช่วยให้คุณเข้าถึงโครงสร้างของอาร์เรย์และ / หรือ dicts ที่ลึกล้ำด้วยอาร์เรย์ดัชนีของดัชนี / คีย์มากกว่าการแสดงออกที่น่าเบื่อของผู้ประกอบการget(และput) หลายคน

(G)run 7 ตัวอักษรซื้อระดับฐาน

1(G)run 8 ตัวอักษรซื้อและชื่อระบบย่อ

3(G)run $9 ตัวอักษรเริ่มต้นทันทีบรรทัดการสแกนบล็อกโดยนัยจนกระทั่งบรรทัดว่างถัดไปและกำหนดบรรทัดแรกเป็นโพรซีเดอร์ที่เรียกว่าAบรรทัดถัดไปจะถูกกำหนดเป็นโพรซีเดอร์ที่เรียกว่าBเป็นต้นซึ่งควรลบส่วนที่defจำเป็นสำหรับการกำหนด มีสิ่งต่าง ๆ มากมายโดยไม่จำเป็นต้องห่อไว้ในพจนานุกรมหรือแม้แต่ตั้งชื่อให้พวกเขาอย่างชัดเจน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.