Lời khuyên cho việc chơi golf trong Postcript?


14

Là một trong những ngôn ngữ ít phổ biến hơn, thật khó để tìm thấy tài liệu về sự tiên phong của tin tặc postcript. Vì vậy, những khám phá nào mà những người chơi golf ở đây đã thực hiện để khai thác mô hình ngăn xếp (hoặc các tính năng khác) để vượt qua tính dài dòng vốn có của Postcript?


Tìm thấy một số trang bên ngoài: sites.google.com.vn/site/codegolfingtips/Postscript
luser droog

Câu trả lời:


3

Bộ giải mã nhúng

Một chương trình Postcript có khả năng (?) Duy nhất để đọc văn bản chương trình của chính nó dưới dạng dữ liệu. Việc này thường được sử dụng bởi các imagenhà điều hành mà nhận được một thu thập dữ liệu-thủ tục như đầu vào, và thủ tục này thường sử dụng currentfiletiếp theo readline, readstringhoặc readhexstring. Nhưng nhìn theo một cách khác, imagechỉ là một toán tử vòng lặp khác, vì vậy bất kỳ vòng lặp nào cũng có thể đọc trước . Một ví dụ là trình giả lập máy in dòng từ Sách Xanh.

Sử dụng tokentoán tử gọi trình quét trên một tệp hoặc chuỗi, kéo ra một số hoặc dấu cách- (hoặc nói cách khác-: xem câu trả lời khác) tên giới hạn.

Một trình thông dịch PS đơn giản trong PS:

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

Bộ giải mã chuỗi toán tử nhị phân

Vì dường như tôi không thể làm cho mã thông báo nhị phân thô hoạt động cho mình (xem câu trả lời khác), tôi đã sử dụng ý tưởng "giải mã nhúng" để khai thác cơ chế mã thông báo nhị phân để đóng gói mã thành chuỗi 8 bit, sau đó thao tác và phân tích các lệnh từ chuỗi khi đang bay .

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

Quy .trình lấy một số từ ngăn xếp và chèn nó làm byte thứ hai trong chuỗi hai byte, byte đầu tiên là byte tiền tố cho mã thông báo nhị phân, chỉ định tên hệ thống thực thi. Chúng tôi lưu một byte trong chuỗi hình lục giác bằng cách sử dụng quy tắc của máy quét rằng số lượng nibble lẻ trong chuỗi đó được đệm thêm 0 nibble, vì vậy 3 nibble tạo ra chuỗi 2 byte. Chuỗi sau đó được đánh dấu thực thi và được gọi bằng cách execgọi trình quét, tạo ra tên hệ thống thực thi mong muốn, sau đó tải tên và thực thi toán tử. Việc $này thực hiện trên mỗi byte của một chuỗi trên ngăn xếp, sử dụng .thủ tục hai lần , một lần làm thân vòng lặp và sau đó để thực hiện toán tử lặp foralltheo số.

Nhỏ gọn hơn, các thủ tục này trông như thế này:

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

Vì vậy, 55 ký tự mua chuỗi mã thông báo nhị phân. Hoặc, đối với 6 (có thể là 7, nếu bạn chấm dứt ký tự bằng dấu cách), bạn có thể tải thư viện G(G)runđịnh nghĩa .$như trên (+ một vài thứ khác để mở rộng phạm vi mã có thể truy cập ascii).

Minh họa thêm trong câu trả lời ô chữ của tôi .


1
Trên thực tế, nếu phần tái bút ở dạng được mã hóa, thì điều này đòi hỏi bạn phải hết sức cẩn thận trong việc so sánh các công cụ. Cụ thể, nếu bạn đang xem xét các nhà khai thác, bạn phải phân tích nó dưới dạng mã thông báo và sau đó so sánh tên của mã thông báo với giá trị đích.
AJMansfield

2

Khi tạo đầu ra đồ họa và đầu ra giao diện điều khiển không quan trọng, hãy sử dụng =thay vì pop.


2

Thay thế hexstrings bằng ASCII85

Có lẽ là tin cũ, nhưng tôi chỉ học nó. :)

Bạn có thể làm điều đó bằng cách sử dụng trình thông dịch postcript tương tác với bộ lọc mã hóa và cắt và dán. Nhưng tôi sẽ chỉ cho bạn cách sử dụng dcđể làm điều đó "bằng tay".

Vì vậy, đây là một chuỗi hex. Chúng tôi chia nó thành các đoạn 4 byte.

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

Kích hoạt tính năng dc, chúng tôi nhập vào những số này dưới dạng số thứ tự byte lớn 32 bit (không dấu). Sau đó, mod -off cơ sở-85 chữ số (nên có 5 cho đến khi bạn về 0).

0> đ
16i
95206ED8
Ai
d85% n85 /
82
d85% n85 /
83
d85% n85 /
82
d85% n85 /
78
d85% n85 /
47
d85% n85 /
0                    

Việc đệm đoạn cuối cùng với 00 00, sản lượng (thập phân), bỏ qua cùng số byte mà chúng ta đã đệm.

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

Thêm 33 để chuyển sang phạm vi có thể in của ASCII và gặp sự cố! ASCII85.

80 111 115 116 115 99 114 105 112 116 58 105 115 58 102 35 86 63
giải mã thành: Postcript: is: f # V? %%%Giáo sư! nên nói 'vui'! Tôi vặn vít ở đâu đó. :)

Gói nó trong <~... ~>và Postcript cấp 2 có thể truy cập dữ liệu 8 bit, rẻ hơn hex.


2

Đây là một quickie: bọc nhiều định nghĩa [...>>beginđể loại bỏ từ khóa def(nb. Giống [như <<).

 def def
[>>begin

Hãy nhớ rằng: nhiều hơnsố bahai ... đàn lại với nhau ! ;)


Không phải quy tắc là "nhiều hơn hai" sao? So sánh /a 1 def/b 2 def/c 3 defvới <</a 1/b 2/c 3>>begin. Chúng ta cần nhiều không gian hơn cho def.
Thomas W.

Ồ Tôi đã không mặc dù điều đó. Có, tính toán cần cải thiện.
kẻ lừa đảo người lái xe

Trên thực tế, điều này nên là[/a 1/b 2/c 3>>begin
Thomas W.

mặt cọ. . . .
kẻ lừa đảo rủ rê

1
Điều này có thể không áp dụng nếu bạn đặt tên một cái gì đó chấm dứt trên mã thông báo tự phân định. Trong /a{pop 2 mul}defhoặc \b[2 3]def, defchỉ có 3 ký tự, không phải 4.
AJMansfield 16/2/2015

2

Trong khi hầu hết các nhà khai thác postscript là cú pháp định danh (và do đó phải space- (hoặc otherwise-) phân cách), tên [, ], <<, và >>đang tự phân chia ranh giới và máy quét sẽ phát hiện chúng mà không cần can thiệp vũ trụ. Vì lý do tương tự, bạn không thể tham chiếu các tên này bằng /literalcú pháp thông thường (ví dụ: /[hai mã thông báo: một tên bằng chữ trống tương đương ()cvn cvlitvà tên thực thi [tương đương ([)cvn cvx exec).

Để xác định lại các tên này, không thể được đề cập theo tên, chúng ta có thể sử dụng các chuỗi được chuyển đổi hoàn toàn thành tên khi được sử dụng làm khóa trong từ điển (thuận tiện!).

Ví dụ này minh họa việc lạm dụng các toán tử này để thực hiện số học.

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

Ngoài ra <<[(và mark) tất cả có nghĩa là điều tương tự.


Trình thông dịch postcript của riêng tôi, xpost , cũng làm cho dấu ngoặc nhọn phải có sẵn với một số hạn chế. thảo luận


2
Ngoài ra, /kết thúc mã thông báo trước đó để bạn không cần một khoảng trống trước nó.
Geoff Reedy

1

Sử dụng lặp lại các yếu tố của tên nhà khai thác dài

Nếu bạn đang sử dụng <<>>begintừ điển, có /?{}4 ký tự không đổi trên mỗi định nghĩa lại. Vì vậy, một toán tử có độ dài n lặp lại N lần sẽ mang lại sự thay đổi số lượng ký tự là
(4 + n ) - ( N * ( n - 1)).

Thiết công thức này bằng 0 cho các phương trình của break-thậm chí điểm. Từ đó, chúng ta có thể giải từng biến theo các biến khác, thu được
n = - ( N - 4) / (1 - N ) và
N = (4 + n ) / ( n - 1).

Không, chúng tôi có thể trả lời các câu hỏi như, "Có bao nhiêu cách sử dụng 'in' có đáng để viết tắt không?" n = 5, nên N = 9/4. Hãy giữ trần, vì bạn không thể gọi in 1/4 lần một cách hiệu quả. Vậy, 3. 3 công dụng. Và thực sự,

print print print
/P{print}p p p

(tất nhiên là giả sử bạn đã trả chi phí <<>>beginđể kích hoạt định nghĩa).

Tất nhiên, mã thông báo nhị phân tạo ra loại mô phỏng này, cung cấp cho bạn 255 tên đầu tiên từ bảng tên hệ thống là 2 byte: 0x92, 0x ??. Và mã thông báo nhị phân cũng tự phân định, không yêu cầu khoảng trắng trước hoặc sau, vì bit cao của byte đầu tiên nằm ngoài phạm vi ascii.


1

Mã thông báo nhị phân

Đối với chương trình nén cuối cùng của chương trình PostScript, biên giới cuối cùng là mã thông báo nhị phân cho phép bạn xóa hoàn toàn tên toán tử dài, với chi phí không còn có chương trình xóa ASCII.

Vì vậy, bắt đầu với một khối mã postcript được nén

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

Chúng tôi tìm kiếm tất cả các tên ở mặt sau của PLRM (Phụ lục F, trang 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

Và sau đó nhập chúng vào tiền tố bởi một 146byte (thập phân). vim trợ giúp để nhập byte tùy ý

Sau đó, trong vim, tệp cô đặc có thể được nhập trực tiếp, vì vậy:

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

... bạn phải nhập một khoảng ^Vtrắng ở đây để chấm dứt -62 và bắt đầu 1, nhưng bạn có thể sao lưu và xóa nó sau ...

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

... phải nhập một khoảng trắng ở đây để chấm dứt ^V-85 và bắt đầu 1, nhưng bạn có thể sao lưu và xóa nó sau ...

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

... Chữ số thứ 3 của mã 3 chữ số chấm dứt mục nhập byte, vì vậy, 0đây là bình thường, thuận tiện ...

0 S ^V146 ^V167

Mà sẽ trông như thế này trên màn hình (trong 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>§

Điều này thường có thể được bỏ qua hoàn toàn nếu mục đích chỉ là để hiển thị một hình ảnh. Ghostscript vẽ hầu hết mọi thứ lên màn hình mà không cần showpage.

¡    161   showpage

[ Điều này thực sự không hoạt động. Ghostscript đang cho tôi undefinedsyntaxerrorcho các mã thông báo này. Có lẽ có một số chế độ tôi cần kích hoạt. ]


Có lẽ đó là một cái gì đó về chương trình này . Máy đầm trực tuyến cũng không thích nó.
kẻ lừa đảo kẻ lừa đảo

1

Thay đổi cuộn âm thành dương

Cuộn âm luôn có thể được thay đổi thành cuộn dương .

3 -1 roll
3 2 roll

5 -2 roll
5 3 roll

Cái nào hiệu quả hơn 3 -1 rollhay 3 2 roll? Trong mô hình tinh thần của tôi, trước đây nên hiệu quả hơn bởi vì nó chỉ cần một động tác. Là mô hình tinh thần của tôi đúng?
hôn vào nách của tôi

Thành thật mà nói, tôi không chắc chắn. Đây là triển khai của tôi , trong đó tất cả các cuộn âm được chuyển thành tích cực như bước đầu tiên. Tôi nghĩ rằng nó vẫn sẽ cần ít nhất 2 lần di chuyển (di chuyển giá trị thứ 3 lên , di chuyển 3 giá trị xuống ) với việc triển khai mảng phẳng của ngăn xếp. Nhưng ngăn xếp của tôi được phân đoạn để truy cập đi qua các lệnh gọi hàm để quản lý các phân đoạn; Vì vậy, chắc chắn có nhiều cách hiệu quả hơn để thực hiện hơn tôi đã làm. ... Một điều tôi thấy bây giờ: Tôi nên kiểm tra stackunderflow bên ngoài các vòng lặp.
luser droog 17/214

1
Các tập tin nguồn đã di chuyển kể từ bình luận cuối cùng của tôi. Đây là triển khai của tôi của các rollnhà điều hành.
luser droog 26/215

0

Sử dụng thư viện G của tôi

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

Đó là một tập tin văn bản. Không có phần mở rộng, cho cú pháp ngắn nhất có thể để tải nó.

Nó cho phép chương trình Tam giác Sierpinksi 203-char này

[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

được viết lại thành 151 byte như

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

làm việc với ý kiến

Sử dụng tính năng tên hệ thống viết tắt, 1(G)runloại bỏ hoàn toàn gánh nặng của tên nhà khai thác dài. Một tên nhà khai thác chỉ cần đủ dài để phân biệt với các tên khác.

Vì thế

  • add trở thành ad
  • mul trở thành mu
  • index trở thành i
  • Vân vân.

Sử dụng Phụ lục F PLRM cho bảng tiêu chuẩn của tên nhà khai thác.

Và tính năng của Chuỗi toán tử khả dụng ngay cả khi tên viết tắt không được chọn. Thư viện trần có "mức cơ sở" được chọn bằng cách thêm đơn giản (G)runmà không cần trang trí thêm.

Mức cơ sở bao gồm một hàm mới .chấp nhận mã số nguyên cho một toán tử (cùng Phụ lục F được đề cập ở trên) và thực thi nó.

Hàm mới $lặp qua một chuỗi và gọi .từng chuỗi . Vì vậy, mã ascii trực tiếp chọn toán tử theo số.

Một chức năng mới @cho phép bạn tiếp cận đến cuối bảng trong Phụ lục F bằng cách coi ký tự khoảng trắng (Ascii 0x20) là 0.

Một chức năng mới #cho phép bạn tiếp cận sâu hơn vào bảng bằng cách thêm 95 (0x5F) trước tiên để không gian char 0x20 được coi là 127 (0x7F), mã tiếp theo sau ký tự ascii có thể in cuối cùng ~126 (0x7E).

Hai hàm mới !cho phép bạn truy cập cấu trúc của các mảng và / hoặc dicts lồng nhau với một mảng chỉ mục của các chỉ mục / khóa, thay vì các biểu thức tẻ nhạt của nhiều toán tử get(và put).

(G)run 7 ký tự mua cấp cơ sở.

1(G)run 8 ký tự mua tên hệ thống VÀ viết tắt.

3(G)run $9 ký tự ngay lập tức bắt đầu một dòng nguồn quét quy trình ngầm cho đến dòng trống tiếp theo và xác định dòng đầu tiên là một thủ tục được gọi A, dòng tiếp theo được định nghĩa là một thủ tục được gọi B, v.v. Điều này sẽ loại bỏ hầu hết các defs cần thiết để xác định rất nhiều thứ, mà không cần phải bọc chúng trong một cuốn từ điển, thậm chí không rõ ràng đặt tên cho chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.