문자열을 인코딩하기 위해 자신을 치환하는 프로그램 (퀸-변형)


16

다음 80 자 라인을 인쇄하는 프로그램을 작성하십시오.

codegolf.stackexchange.com의이 프로그램은 자체를 변경하여 문자열을 인코딩합니다.

그런 다음 한 줄의 입력을 받아 들인 다음 다시 정렬 할 수 있는 코드 포인트를 사용하여 소스 코드를 인쇄합니다 (아무 추가되지 않고 삭제되지 않음). 해당 코드가 실행될 때 인쇄 된 줄이 가장 최근에 입력 된 줄을 제외하고는 같은 일이 발생해야합니다.

Perl 스타일 정규식 ^[A-Za-z0-9. ]{80}$은 모든 입력 줄과 일치합니다. 추가 가정을 할 수 없습니다.

제출 점수는 소스 코드 의 코드 포인트 수가 94 미만 입니다. 낮을수록 좋습니다.

코드는 quine에서 허용 할 수없는 작업 ( 예 : 파일 읽기)을 수행해서는 안됩니다 . 특히, 음수 점수를받은 제출물은 93으로 속임수를 써야합니다! 64 80 미만 입니다.

2014-04-21 추가 : 프로그램의 전체 소스 코드는 코드 포인트를 세는 문자 인코딩 형식이어야합니다. 예를 들어, UTF-8 후행 바이트 범위 (80..BF)에서 연속 80 바이트를 사용할 수 없으며 각각 단일 U + FFFD REPLACEMENT CHARACTER (또는 코드 포인트가 아닌)로 계산할 수 없습니다.

또한 인코딩을 통해 여러 방법으로 코드 포인트 ( 예 : SCSU ) 를 인코딩 할 수있는 경우, 프로그램과 해당 프로그램이 직접 또는 간접적으로 생성하는 모든 프로그램 중 하나만 사용해야합니다 (또는 적어도 코드 전체에서 동등하게 처리되어야 함). ).


귀하의 질문을 다시 읽은 후에, 내 답변이 귀하가 생각한 것을 정확하게 수행하는지 확실하지 않습니다. 새 문자열을 프로그램에 파이핑 할 수 있습니까? 아니면 대화식 프롬프트를 시작해야합니까?
Dennis

@Dennis : 그렇기 때문에 귀하의 답변이 받아 들여지지 않습니다. 대신 "[...]에서이 프로그램을 인쇄 하기 전에 입력을 읽습니다 ."
PleaseStand

그것이 제가 의미 한 바입니다. 나는 그것을 잘 표현하지 못했습니다. GolfScript 인터프리터는 스크립트 실행을 시작하기 전에 파이프 된 모든 것을 읽습니다. 이를 피할 수있는 유일한 방법은 프롬프트를 시작하여 배관을 불가능하게하는 것입니다.
Dennis

안녕하세요, 저는 JavaScript로 이것을 시도하고 있습니다. <script> 태그 사이의 텍스트를 읽지 않고 퀴네를 만드는 것이 불가능한 것 같습니까? 소스 코드를 바꾸는 목적은 무엇입니까? 당신은 '아마도 재정렬'이라고 말합니다; 이것은 필요할 때만 퍼 미트를 의미합니까?
bacchusbeale

답변:


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$=.@^}/]"'".@+\+\'.~'}.~

작동 원리

우리는 문자열을 인코딩하기 위해 치환 될 94 가지 문자를 선택하여 시작합니다. 94 자이면 작동하지만 골프 목적으로 다음을 선택합니다.

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

이 문자들의 배열을“&”라고합시다.

입력 라인은 항상 81 문자 (LF 포함)를 포함합니다. 이러한 문자는 모두 "&"의 처음 65 자에 있습니다. 이것이 상위 128 바이트의 문자를 선택하는 유일한 이유입니다.

문자열의 각 문자를“&”의 색인으로 바꾸므로 LF는 0이되고 공백은 1이됩니다.

획득 한 81 개의 숫자는 단일 기본 65 숫자의 숫자로 간주됩니다. 이 번호를“N”이라고합시다.

이제“&”의 모든 가능한 순열을 열거하고 위의 숫자에 해당하는 순열을 검색합니다. 이것은 다음과 같은 방식으로 달성됩니다.

  1. c = 1및을 설정하십시오 A = [].
  2. 앞에 추가 N % c하십시오 A.
  3. N = N / c및을 설정하십시오 c = c + 1.
  4. 인 경우 c < 952로 돌아갑니다.
  5. i = 0및을 설정하십시오 s = "".
  6. charcter를 검색하여 &[A[i]]“s”에 추가하고“&”에서 제거하십시오.
  7. 설정하십시오 i = i + 1.
  8. 만약 i < 946 가서 다시.

위에서 설명한대로 문자열을 인코딩하고 디코딩하는 코드 블록“E”및“D”가 있다고 가정합니다.

이제 질문의 요구 사항을 준수하는 코드 블록에 대한 래퍼가 필요합니다.

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

이것은 다음을 수행합니다.

  • {…}.~블록을 정의하고 복제하여 두 번째 사본을 실행합니다. 첫 번째 사본은 스택에 남아 있습니다.

  • \.$ 인코딩 된 문자열을 블록과 교체하고 정렬 된 문자를 사용하여 인코딩 된 문자열의 복사본을 만듭니다.

  • [{}/]:&; 문자열을 위에서 배열로 변환하여“&”에 저장 한 후 버립니다.

  • D puts 인코딩 된 문자열을 디코딩하고 결과를 인쇄합니다.

  • '"#{`head -1`}"'~head -1쉘에서 실행 하여 한 줄의 입력을 읽습니다 .

  • E "'".@+\+ 문자열을 인코딩하고 앞에 작은 따옴표를 붙입니다.

  • \'.~'인코딩 된 문자열과 블록을 바꾸고 문자열을 추가합니다 '.~'.

  • 블록이 실행 된 후 GolfScript는 스택의 내용 (인코딩 된 문자열, 블록, '.~')을 인쇄하고 종료합니다.

"E"는 다음과 같이 정의 할 수 있습니다.

{&?}%        # 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.

"D"는 다음과 같이 정의 할 수 있습니다.

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.

마지막 골프 :

  • 교체 \.$[{}/]:&;0&@와 함께 0@.$[{}/]:&\두 개의 문자를 저장합니다.

  • {;65base}:b한 문자를 저장 하는 기능 을 정의하십시오 .

  • 문자열에서 후행 LF와 LF를 제외한 모든 공백을 제거하십시오.

$ # 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.


좀 더 자세히 설명해 주시겠습니까?
Dennis

1

펄, 1428 1099

여기에는 1193 개의 ASCII 문자 (960 개의 순열 이진수 포함)가 있습니다. 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

내 첫 디자인

Dennis에서 바이너리로 전환하라는 제안을 받기 전에 내 프로그램은 8 진수를 순열했습니다.

첫 번째 디자인은 각 문자열을 문자 당 2 자리로 160 개의 8 진수로 인코딩합니다. 이 인코딩에는 100 8 = 64 개의 다른 문자가 있습니다. 8 진법은 8 개의 다른 숫자를 가지고 있습니다. 프로그램에는 각 자릿수마다 160 개의 사본이 있어야하므로 8 × 160 = 1280 자리를 바꿉니다.

160 자리 숫자를 유지 $s하고 다른 1120 자리 숫자를에 유지 $t합니다. 나는 quine 아닌 프로그램을 시작하지만에만 할당을 인쇄 $s하고 $t다음 실행을 위해. 이거 야:

$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))빈 변수 목록에 대한 할당입니다. PerlMonks컨텍스트 자습서 에서이 트릭을 가져 옵니다 . 일치 연산자에 컨텍스트를 강제로 나열합니다 =~. 스칼라 컨텍스트에서 일치는 true 또는 false이며 $i++ while ($s =~ /$_/g)일치를 계산 하는 루프가 필요합니다 . 목록 컨텍스트에서 $s =~ /$_/g일치하는 목록입니다. 이 목록을 빼기의 스칼라 컨텍스트에 넣으므로 Perl은 목록 요소를 계산합니다.

quine 을 만들기 위해 Rosetta Code$_=q{print"\$_=q{$_};eval"};evalPerl quines에서 양식 을 가져옵니다 . 이것은 문자열 q{...}을 할당 한 $_다음을 호출 eval하므로 문자열에 코드를 넣고 실행할 수도 있습니다. 내 프로그램은 내가 지난 라인에 세 번째 랩 quine하게 $_=q{하고 };eval, 내 마지막 변경 printprint "\$s = '$s';\n\$t = '$t';\n\$_=q{$_};eval".

마지막으로 첫 번째 과제를 $t주석 으로 변경하고 추가 문자를 제거 하여 프로그램을 골프화 합니다.

여기에는 1522 개의 ASCII 문자 (1280 개의 순열 된 8 진수 포함)가 있습니다.
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

이진으로 전환

이 의견에서 Dennis는 960 개의 순열 된 이진수가 1280 개의 8 진수보다 적다는 것을 알았습니다. 그래서 저는 각 밑변에 대한 순열 자리수를 2에서 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) 

x 축을 기준으로 한 그래프, y 축에서 치환 된 자릿수를 나타내는 그래프

기수 8은 로컬 최소값이지만 기수 2와 3과 4는 960 개의 순열 자리에서 최상의 기수를 위해 묶습니다. 코드 골프의 경우 Perl은 기본 2에 대한 변환이 있으므로 기본 2가 가장 좋습니다.

1280 개의 8 진수를 960 개의 이진수로 바꾸면 320자가 절약됩니다.

8 진수에서 2 진수로 코드를 전환하려면 8자가 필요합니다

  • 변경 octoct'0b'.$_비용 7.
  • 변경 /../g/.{6}/g비용이.
  • "%02o""% 06b"로 변경 하면 비용이 0입니다.
  • 변경 160480비용이 0.
  • 변경 0..7하려면 0,11을 절약 할 수 있습니다.

나는 Perl 골프 팁을 배웠다 . 14자를 저장합니다.

  • 변경 'A'..'Z','a'..'z','0'..'9'A..Z,a..z,0..9사용 barewords 및 노출 수는 12 개 문자를 저장합니다.
  • 변경 "\n"하려면 $/2 개 문자를 저장합니다.

#$t주석을 파일 끝 으로 이동하여 3자를 저장 합니다. 주석을 끝내는 줄 바꿈과 \nquine 의 리터럴 을 제거합니다 .

이 변경 사항은 총 329자를 저장하고 점수를 1428에서 1099로 줄입니다.


1
8 진수 대신 이진수를 사용하려면 "960"개의 치환 가능한 문자 만 필요합니다.
Dennis

@Dennis 팁 주셔서 감사합니다! 바이너리로 전환했습니다 (312 자 절약). 여기있는 동안 나는 17 명의 캐릭터를 더 멀리 떨어 뜨렸다.
kernigh
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.