Chương trình cho phép chính nó mã hóa một chuỗi (biến thể quine)


16

Viết chương trình in dòng 80 ký tự sau:

Chương trình này từ codegolf.stackexchange.com tự cho phép mã hóa một chuỗi.

sau đó chấp nhận một dòng đầu vào, sau đó in mã nguồn của nó với các điểm mã có thể được sắp xếp lại (không thêm và không xóa). Khi mã đó được thực thi, điều tương tự phải xảy ra, ngoại trừ dòng in sẽ là dòng đầu vào gần đây nhất.

Regex kiểu Perl ^[A-Za-z0-9. ]{80}$sẽ khớp với bất kỳ dòng đầu vào nào. Bạn không thể thực hiện bất kỳ giả định bổ sung.

Điểm của bài nộp là số điểm mã trong mã nguồn ít hơn 94 . Thấp hơn là tốt hơn.

Mã không được làm bất cứ điều gì không thể chấp nhận được trong một quine ( ví dụ đọc tệp). Đặc biệt, bất kỳ bài nộp nào có điểm âm phải được gian lận bằng cách nào đó, như 93! nhỏ hơn 64 80 .

Đã thêm 2014-04-21: Toàn bộ mã nguồn của chương trình của bạn phải được định dạng tốt trong mã hóa ký tự, theo đó bạn đếm các điểm mã. Ví dụ: bạn không thể sử dụng 80 byte liên tiếp trong phạm vi byte theo dõi UTF-8 (80..BF) và tính từng byte như một TÍNH NĂNG THAY THẾ U + FFFD duy nhất (hoặc tệ hơn, vì hoàn toàn không phải là điểm mã).

Ngoài ra, nếu mã hóa cho phép nhiều cách mã hóa một điểm mã ( ví dụ SCSU ), chương trình của bạn, cũng như tất cả các chương trình do nó trực tiếp hoặc gián tiếp tạo ra, chỉ phải sử dụng một trong số chúng (hoặc ít nhất là tất cả phải được xử lý tương đương trong toàn bộ mã ).


Sau khi đọc lại câu hỏi của bạn, tôi không chắc câu trả lời của tôi có thực hiện chính xác những gì bạn đã nghĩ không. Việc đặt chuỗi mới vào chương trình có ổn không hay nó phải khởi chạy một dấu nhắc tương tác?
Dennis

@Dennis: Đó không phải là lý do tại sao câu trả lời của bạn không được chấp nhận. Thay vào đó, nó đọc đầu vào trước khi in "Chương trình này từ [...]".
Xin vui lòng

Đó là những gì tôi muốn nói, tôi chỉ không thể hiện nó tốt. Trình thông dịch GolfScript đọc mọi thứ được dẫn đến trước khi bắt đầu thực thi tập lệnh. Cách duy nhất để tránh điều này là khởi chạy một dấu nhắc, điều này làm cho đường ống không thể.
Dennis

Xin chào, tôi đang thử điều này trong JavaScript. Có vẻ như không thể thực hiện một câu hỏi mà không đọc văn bản giữa các thẻ <script>? Mục đích của việc hoán vị mã nguồn là gì? Bạn nói 'có thể sắp xếp lại'; điều này có nghĩa là hoán vị chỉ khi cần thiết?
bacchusbeale

Câu trả lời:


5

GolfScript, 231 162 131

'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~

Làm thế nào nó hoạt động

Chúng tôi bắt đầu bằng cách chọn 94 ký tự khác nhau sẽ được hoán vị để mã hóa một chuỗi. Bất kỳ 94 ký tự nào cũng hoạt động, nhưng chúng tôi chọn các mục sau cho mục đích chơi gôn:

\n .0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
àáâãäåçèéêëìíîïðñòóôõöøùúûüýÿ

Chúng ta hãy gọi mảng của các nhân vật này là & &.

Dòng đầu vào sẽ luôn chứa 81 ký tự (bao gồm cả LF). Tất cả những nhân vật đó đều có mặt trong 65 ký tự đầu tiên của & &. Đây là lý do duy nhất để chọn các ký tự trong 128 byte trên.

Chúng tôi thay thế từng ký tự của chuỗi bằng chỉ mục của nó trong Trò chơi & Trực tiếp, do đó, LF trở thành 0, không gian trở thành 1, v.v.

Chúng tôi xem xét 81 số thu được là các chữ số của một số cơ sở 65. Hãy gọi số này là N NÔNG.

Bây giờ, chúng tôi liệt kê tất cả các hoán vị có thể có của & & và lấy ra hoán vị tương ứng với số từ trên. Điều này đạt được theo cách sau:

  1. Đặt c = 1A = [].
  2. Chuẩn bị N % cđể A.
  3. Đặt N = N / cc = c + 1.
  4. Nếu c < 95, quay trở lại 2.
  5. Đặt i = 0s = "".
  6. Truy xuất charcter &[A[i]], nối nó vào và s và xóa nó khỏi từ & &.
  7. Đặt i = i + 1.
  8. Nếu i < 94quay lại 6.

Giả sử chúng ta có các khối mã, hoàng tử và phong độ, mã hóa và giải mã một chuỗi như đã giải thích ở trên.

Bây giờ, chúng ta cần một trình bao bọc cho các khối mã tuân thủ các yêu cầu của câu hỏi:

'encoded string'{\.$[{}/]:&; D puts '"#{`head -1`}"'~ E "'".@+\+\'.~'}.~

Điều này thực hiện như sau:

  • {…}.~định nghĩa một khối, sao chép nó và thực hiện bản sao thứ hai. Bản sao đầu tiên sẽ vẫn còn trên ngăn xếp.

  • \.$ hoán đổi chuỗi được mã hóa với khối và tạo một bản sao của chuỗi được mã hóa, với các ký tự được sắp xếp.

  • [{}/]:&; chuyển đổi chuỗi từ trên xuống thành một mảng, lưu chuỗi đó vào trong & & loại bỏ nó.

  • D puts giải mã chuỗi được mã hóa và in kết quả.

  • '"#{`head -1`}"'~đọc một dòng đầu vào bằng cách thực hiện head -1trong trình bao.

  • E "'".@+\+ mã hóa chuỗi và thêm vào và thêm một trích dẫn.

  • \'.~'hoán đổi chuỗi được mã hóa và khối và nối thêm chuỗi '.~'.

  • Sau khi khối được thực thi, GolfScript sẽ in nội dung của ngăn xếp (chuỗi được mã hóa, khối, '.~') và thoát.

Có thể định nghĩa như thế này

{&?}%        # Replace each character by its index in “&”.
);           # Remove the last integer from the array, since it corresponds to the LF.
65base       # Convert the array to an integer “N” by considering it a base 65 number.
[            #
  94,        # For each integer “c” in 0 … 93:
  {          #
    )        # Increment “c”.
    1$1$%    # Push “N % c”.
    @@/      # Rotate “N % c” below “N” and “c” and divide the first by the latter.
  }/;        # Discard “N”.
]            # Collect the results of “N % c” in an array “A”.
-1%          # Reverse “A”.
&\           # Push “&” and swap it with “A”.
[            #
  {          # For each “j” in “A”:
    1$=.[]+  # Push “&[j] [&[j]]”.
    @^       # Rotate “&” on top of “[&[j]]” and take their symmetric difference.
  }/         #
]            # Collect the charcters into an array.

Bạn có thể định nghĩa như thế này

0&           # Push 0 (initial value of the accumulator “A”) and “&”.
@            # Rotate the encoded string on top of “&”.
{            # For each character “c” of the encoded string:
    @2$,*    # Rotate “A” on top of the stack and multiply it by the length of “&”.
    2$2$?+   # Get the index of “c” in “&” and add it to “A”.
    @@^      # Rotate “A” below “&” and “c” and take their symmetric difference.
}/;          # Discard “&”.
65base       # Convert “A” into the array of its digits in base 65.
{&=}%        # Replace each digit by the corresponding character in “&”.
''+          # Convert the resulting array into a string.

Chơi golf cuối cùng:

  • Thay thế \.$[{}/]:&;0&@bằng 0@.$[{}/]:&\để lưu hai ký tự.

  • Xác định hàm {;65base}:bđể lưu một ký tự.

  • Xóa tất cả các khoảng trắng, ngoại trừ dấu vết LF và LF trong chuỗi.

Thí dụ

$ # Create GolfScript file using base64 to avoid encoding issues.
$ base64 > permute.gs -d <<< JzHg4jT/YVZvNUf5cFpCdGlYT/xyc/NO7k1tV+VLSGMwOUpk8frqeXrtRUPkWe9oRFUg4+FJRvU26TjyUuxqVHYyM/hudfBMd3hmU2v0YutBZWxx/S7n6FBRCvb7ZzcnezBALiRbe30vXTomXHtAMiQsKjIkMiQ/K0BAXn0vezs2NWJhc2V9OmJ+eyY9fSUnJytwdXRzJyIje2BoZWFkIC0xYH0iJ357Jj99JSliWzk0LHspMSQxJCVAQC99LztdLTElJlxbezEkPS5AXn0vXSInIi5AK1wrXCcufid9Ln4K
$
$ # Set locale to en_US (or any other where one character is one byte).
$ LANG=en_US
$
$ # Go back and forth between two different strings.
$ # Second and sixth line are user input, not output from the script.
$
$ golfscript permute.gs | tee >(tail -n+2 > tmp.gs) && golfscript tmp.gs && rm tmp.gs
This program from codegolf.stackexchange.com permutes itself to encode a string.
Permuting source code code points to encode a string is a certain quine variant.
'18äJoS3sgV9qdçëxm0ÿKMNe5íPî.Htn2ciâIuøbRZéð4AwB7áìUüöôWõèûfñåLàóDrhQlO6
pTaýzòkùYCyFêïãG júEvX'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
Permuting source code code points to encode a string is a certain quine variant.
This program from codegolf.stackexchange.com permutes itself to encode a string.
'1àâ4ÿaVo5GùpZBtiXOürsóNîMmWåKHc09JdñúêyzíECäYïhDU ãáIFõ6é8òRìjTv23ønuðLwxfSkôbëAelqý.çèPQ
öûg7'{0@.$[{}/]:&\{@2$,*2$2$?+@@^}/{;65base}:b~{&=}%''+puts'"#{`head -1`}"'~{&?}%)b[94,{)1$1$%@@/}/;]-1%&\[{1$=.@^}/]"'".@+\+\'.~'}.~
$
$ # Sort all characters from the original source code and hash them.
$ fold -1 permute.gs | sort | md5sum
b5d978c81df5354fcda8662cf89a9784  -
$
$ # Sort all characters from the second output (modified source code) and hash them.
$ golfscript permute.gs | tail -n+2 | fold -1 | sort | md5sum
Permuting source code code points to encode a string is a certain quine variant.
b5d978c81df5354fcda8662cf89a9784  -
$
$ # The hashes match, so the characters of the modified source code are a permutation
$ # of the character of the original one.

224 trừ 94 là 130.
mbomb007

Bạn có thể giải thích?
Dennis

1

Perl, 1428 1099

Điều này có 1193 ký tự ASCII (bao gồm 960 chữ số nhị phân được hoán vị). 1193 - 94 = 1099

$s='010011100001100010101100111111101001101011101000100000101011011010100110111111011111101011101000100110111111011100101000011101011110100000101000100101011111111110101100101101011010011100100100011110110001011100100001011010100111100000011110111110011100101000100110111111101001011110101011100110101110101101011110101100111111100010101101101100011110100101011111111111101101101000111111011110100111011100101000011101011110111111011010111111101100101101101011100010100111100000111110';$_=q{$i=join'',A..Z,a..z,0..9,'. ';print map({substr$i,oct'0b'.$_,1}$s=~/.{6}/g),$/;chop($s=<>);$s=join'',map{sprintf"%06b",index$i,$_}$s=~/./g;$t=join'',map{$_ x(480-(()=$s=~/$_/g))}0,1;print"\$s='$s';\$_=q{$_};eval#$t"};eval#000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Thiết kế đầu tiên của tôi

Trước khi tôi nhận được đề nghị từ Dennis để chuyển sang nhị phân, chương trình của tôi đã hoán vị các chữ số bát phân.

Thiết kế đầu tiên của tôi mã hóa mỗi chuỗi bằng 160 chữ số bát phân, với 2 chữ số cho mỗi ký tự. Mã hóa này có 100 8 = 64 ký tự khác nhau. Hệ thống bát phân có 8 chữ số khác nhau. Chương trình phải có 160 bản sao của mỗi chữ số, vì vậy nó cho phép 8 × 160 = 1280 chữ số.

Tôi giữ 160 chữ số $svà 1120 chữ số khác $t. Tôi bắt đầu với một chương trình không phải là một quine, mà chỉ in các bài tập đến $s$tcho lần chạy tiếp theo. Đây là nó:

$s = '2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';
$t = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777';

# $i = character map of 64 characters, such that:
#  substr($i, $_, 1) is the character at index $_
#  index($i, $_) is the index of character $_
$i = join '', 'A'..'Z', 'a'..'z', '0'..'9', '. ';

# Decode $s from octal, print.
#  1. ($s =~ /../g) splits $s into a list of pairs of octal digits.
#  2. map() takes each $_ from this list.
#  3. oct() converts $_ from an octal string to a number.
#  4. substr() on $i converts number to character.
#  5. print() outputs the characters from map() and a final "\n".
print map({ substr $i, oct, 1 } $s =~ /../g), "\n";

# Read new $s, encode to octal.
#  1. ($s = <>) reads a line.
#  2. chop($s) removes the last character of $s, the "\n".
#  3. ($s =~ /./g) splits $s into characters.
#  4. map() encodes each character $_ as a pair of octal digits.
#  5. join() concatenates the pairs from map().
chop($s = <>);
$s = join '', map { sprintf "%02o", index $i, $_ } $s =~ /./g;

# Make new $t.
#  1. map() takes each $_ from 0 to 7.
#  2. $_ x (160 - (() = $s =~ /$_/g)) makes a string where $_ repeats
#     160 times, minus the number of times that $_ appears in $s.
#  3. join() concatentates the strings from map().
$t = join '', map { $_ x (160 - (() = $s =~ /$_/g)) } 0..7;

# Print the new assignments for $s and $t.  This is not yet a quine,
# because it does not print the rest of the program.
print "\$s = '$s';\n\$t = '$t';\n";

(() = $s =~ /$_/g))là một sự gán cho một danh sách trống của các biến. Tôi thực hiện thủ thuật này từ hướng dẫn ngữ cảnh tại PerlMonks . Nó buộc liệt kê bối cảnh trên toán tử khớp =~. Trong bối cảnh vô hướng, trận đấu sẽ đúng hoặc sai và tôi sẽ cần một vòng lặp $i++ while ($s =~ /$_/g)để đếm các trận đấu. Trong bối cảnh danh sách, $s =~ /$_/glà một danh sách các trận đấu. Tôi đặt danh sách này trong ngữ cảnh vô hướng của phép trừ, vì vậy Perl đếm các phần tử danh sách.

Để tạo ra một quine, tôi lấy mẫu $_=q{print"\$_=q{$_};eval"};evaltừ các quines Perl tại Rosetta Code . Điều này một chuyển nhượng một chuỗi q{...}đến $_và sau đó gọi eval, vì vậy tôi có thể có mã của tôi trong một chuỗi và cũng chạy nó. Chương trình của tôi sẽ trở thành một Quine khi tôi quấn thứ ba của tôi để dòng cuối cùng trong $_=q{};evalvà thay đổi của tôi cuối cùng printđể print "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

Cuối cùng, tôi đánh golf chương trình của mình bằng cách thay đổi nhiệm vụ đầu tiên $tthành nhận xét và bằng cách xóa các ký tự phụ.

Điều này có 1522 ký tự ASCII (bao gồm 1280 chữ số bát phân được hoán vị).
1522 - 94 = 1428

$s='2341425477515350405332467737535046773450353640504537765455323444366134413247403676345046775136534656553654774255543645377755507736473450353677327754555342474076';#0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
$_=q{$i=join'','A'..'Z','a'..'z','0'..'9','. ';print map({substr$i,oct,1}$s=~/../g),"\n";chop($s=<>);$s=join'',map{sprintf"%02o",index$i,$_}$s=~/./g;$t=join'',map{$_ x(160-(()=$s=~/$_/g))}0..7;print"\$s='$s';#$t\n\$_=q{$_};eval"};eval

Việc chuyển sang nhị phân

Trong các bình luận, Dennis nhận thấy rằng 960 chữ số nhị phân được hoán vị sẽ nhỏ hơn 1280 chữ số bát phân. Vì vậy, tôi đã vẽ đồ thị số chữ số hoán vị cho mỗi cơ sở từ 2 đến 16.

Maxima 5.29.1 http://maxima.sourceforge.net
using Lisp ECL 13.5.1
...
(%i36) n : floor(x);
(%o36)                             floor(x)
...
(%i41) plot2d(n * ceiling(log(64) / log(n)) * 80, [x, 2, 16],
              [xlabel, "base"], [ylabel, "number of permuted digits"]);
(%o41) 

biểu đồ với cơ sở trên trục x, số chữ số được hoán vị trên trục y

Mặc dù cơ sở 8 là mức tối thiểu cục bộ, cơ sở 2 và 3 và 4 cho cơ sở tốt nhất, ở mức 960 chữ số được hoán vị. Đối với mã golf, cơ sở 2 là tốt nhất vì Perl có chuyển đổi cho cơ sở 2.

Thay thế 1280 chữ số bát phân bằng 960 chữ số nhị phân tiết kiệm 320 ký tự.

Chuyển đổi mã từ bát phân sang nhị phân có giá 8 ký tự:

  • Thay đổi octthành oct'0b'.$_chi phí 7.
  • Thay đổi /../gthành /.{6}/gchi phí 2.
  • Thay đổi "%02o"thành "% 06b" `chi phí 0.
  • Thay đổi 160thành 480chi phí 0.
  • Thay đổi 0..7để 0,1tiết kiệm 1.

Tôi đã học được một số mẹo chơi gôn Perl . Họ lưu 14 ký tự:

  • Thay đổi 'A'..'Z','a'..'z','0'..'9'thành A..Z,a..z,0..9, sử dụng barewords và số trần, lưu 12 ký tự.
  • Thay đổi "\n"để $/lưu 2 ký tự.

Tôi lưu 3 ký tự bằng cách di chuyển #$tbình luận đến cuối tập tin. Điều này loại bỏ dòng mới kết thúc bình luận, và một nghĩa đen \ntrong quine.

Những thay đổi này lưu tổng cộng 329 ký tự và giảm điểm của tôi từ 1428 xuống còn 1099.


1
Sử dụng nhị phân thay vì chữ số bát phân sẽ yêu cầu "chỉ" 960 ký tự cho phép.
Dennis

@Dennis Cảm ơn vì tiền boa! Tôi đã thực hiện chuyển đổi sang nhị phân (lưu 312 ký tự). Trong khi ở đây, tôi đã đánh gôn thêm 17 nhân vật.
hạt nhân
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.