방사선 강화 퀸 방사선 경화 퀴네 는 하나의 문자를

아시다시피, 방사선 경화 퀴네 는 하나의 문자를 제거하고 여전히 사전 수정 된 원본을 인쇄 할 수있는 퀴니입니다. 문제는 대부분이 하나의 문자 만 제거 할 수 있다는 것입니다. 그렇지 않으면 모든 것이 무너집니다. 이것은 이것이 나오는 곳입니다. 당신의 목표는 가능한 한 많은 캐릭터를 제거 할 수있는 방사선 경화 퀴니를 만드는 것입니다. 규칙을 준수하는 모든 언어가 좋습니다.

규칙

  • 프로그램은 1 자 이상이어야합니다
  • 사용되는 언어는 완전해야합니다 (따라서 HQ9 +와 같은 언어는 자격이 없음)
  • 일반 퀴인에 적용되는 다른 모든 규칙도 여기에 적용됩니다.
  • 가장과 해결책은 program_length^(2/n)있는 어떤 정확히 세트 n여전히 원래 소스 코드의 승리를 인쇄하는 동안 문자를 제거 할 수 있습니다.


답변

Perl, 1116 1124 바이트, n = 3, 점수 = 1124 ^ (2/3) 또는 약 108.1

업데이트 : 이제 이것이 무차별 대입을 통해 n = 3에서 작동한다는 것을 확인했습니다 (2 일이 걸렸습니다). 이 복잡한 프로그램을 사용하면 손으로 방사선 저항을 확인하기가 어렵습니다 (이전 버전에서는 실수가 발생하여 바이트 수가 증가했습니다). 최종 업데이트

보이지 않는 곳에서 stderr를 리디렉션하는 것이 좋습니다. 이 프로그램은 문자를 삭제 하지 않아도 의심스러운 구문에 대한 경고를 생성 합니다.

프로그램이 단축 될 수 있습니다. 이 작업은 상당히 고통스럽기 때문에 가능한 미세 최적화를 놓치기 쉽습니다. 나는 프로그램 의 정말 어려운 부분 이기 때문에 가능한 많은 삭제 가능한 문자를 최대한 많이 목표로 삼고 있었고 , 타이 브레이크는 목표로하기 좋은 것이지만 내가 넣지 않은 것으로 취급했습니다. 우발적으로 방사선 저항을 깨뜨리기가 매우 쉽다는 근거로 최적화에 대한 우스운 노력.

프로그램

참고 : _의 네 가지 발생 직전에 리터럴 제어 문자 (ASCII 31)가 -+있습니다. StackOverflow에 복사하여 붙여 넣은 것으로 생각하지 않으므로 프로그램을 실행하기 전에 다시 추가해야합니다.

eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;
eval+<eval+<eval+<eval+(q(FoPqOlengthFoBBPP181XXVVVVJJJKKKNdoWchopJFtPDevalMODx4KNFrPIPA-MN-TUV-ZPINFsPIFoPqOI.Fo.IQNevalFoINevalIFsPZyI.Fr.IT-UPINsayDFtJqJFsKPZyPT-UFWrYrKD.DEEEEQDx6NsayDNDforB1..4YforB1..4NexitQNevalFo)=~y=A-Z=-+;-AZz-~=r)####>####>####>####>####>####>
;
;
;
;

설명

이 프로그램은 서로 분명히 연결된 4 개의 동일한 작은 프로그램으로 구성되어 있습니다. 기본 아이디어는 프로그램의 각 사본이 실행하기에 너무 심하게 손상되었는지 여부를 확인한다는 것입니다. 만일 그렇다면, 경고를 뿌릴 수있는 것 외에는 아무 것도하지 않고 다음 사본을 실행시킵니다; 삭제되지 않았거나 삭제 된 문자가 프로그램 작동에 아무런 영향을 미치지 않는 문자 인 경우, 프로그램의 전체 소스 코드를 인쇄하는 기발한 작업을 수행합니다. 각 부분에 전체 소스 코드의 인코딩이 포함되어 있음)을 종료 한 다음 종료합니다 (다른 손상되지 않은 복사본이 소스 코드를 다시 인쇄하지 못하도록하여 너무 많은 텍스트를 인쇄하여 quine을 망칠 수 없음).

각 부분은 기능적으로 독립적 인 두 부분으로 구성됩니다. 외부 래퍼 및 일부 내부 코드 따라서 별도로 고려할 수 있습니다.

외부 포장지

외부 래퍼는 기본적으로 eval<+eval<+eval< ... >####>####...>###(반드시 세미콜론과 줄 바꿈이 많은 목적을 가지고 있어야합니다. 세미콜론 또는 그 이전 줄 바꿈에 관계없이 프로그램의 일부가 분리되어 유지되도록하는 것입니다) ). 이것은 매우 단순 해 보이지만 여러 가지면에서 미묘하고이 과제에 대해 Perl을 선택한 이유입니다.

먼저 래퍼가 프로그램의 손상되지 않은 복사본에서 어떻게 작동하는지 봅시다. eval내장 함수로 구문 분석하여 하나의 인수를 사용합니다. 논쟁이 예상되기 때문에 +여기에 단항 +이 있습니다 (지금까지 Perl 골퍼에게 매우 친숙 할 것입니다. 놀랍게도 종종 유용합니다). 우리는 여전히 인수를 기대하고 있습니다 (우리는 단항 연산자를 보았습니다). <다음에 오는 것은 <>연산자 의 시작으로 해석됩니다 (접두사 또는 접두사 인수를 취하지 않으므로 피연산자 위치에서 사용할 수 있습니다).

<>상당히 이상한 연산자입니다. 일반적으로 파일 핸들을 읽고 파일 핸들 이름을 꺾쇠 괄호 안에 넣 습니다. 또는 표현식이 파일 핸들 이름으로 유효하지 않은 경우 표현식이 기본적으로 사용됩니다 (기본적으로 UNIX 쉘이 사용자가 입력 한 텍스트를 일련의 명령 행 인수로 변환하는 데 사용하는 것과 동일한 프로세스, 실제로는 이전 버전의 Perl이 사용됨) 이것에 대한 쉘이지만 요즘 Perl은 내부적으로 globbing을 처리합니다. 따라서 의도 된 용도는의 행을 따라 있으며 <*.c>일반적으로와 같은 목록을 반환합니다 ("foo.c", "bar.c"). 스칼라 컨텍스트에서 (예 :eval), 처음 실행될 때 찾은 첫 번째 항목 만 반환하고 (첫 번째 인수와 동일) 절대 발생하지 않는 가상의 미래 실행에 대해서는 다른 항목을 반환합니다.

이제 쉘은 종종 명령 행 인수를 처리합니다. -r인수가없는 것과 같은 것을 주면 해당 이름의 파일이 있는지 여부에 관계없이 프로그램에 그대로 전달됩니다. 펄은 같은 방식으로 동작하므로, 쉘과 펄에 특수한 문자가없는 <것과 일치하는 것 사이에 문자가없는 한 >, 이것을 문자 그대로 리터럴처럼 사용할 수 있습니다. 따옴표와 같은 연산자에 대한 Perl의 파서는 이해가 안되는이와 같은 상황에서도 대괄호를 일치시키는 강박적인 경향이 있으므로 <>안전하게 중첩 할 수 있습니다 (이 프로그램이 가능한 발견). 이러한 중첩 된 모든의 가장 큰 단점은 <>의 내용을 탈출이다<>거의 불가능하다. 각각에 2 개의 <>이스케이프 처리 가있는 것처럼 보이 므로 3 개의 내부에서 무언가를 피하려면 63 개의 백 슬래시가 선행되어야합니다. 나는이 문제에서 코드 크기가 단지 이차적 인 고려 사항이라고 생각했지만, 내 점수에 이런 종류의 페널티를 지불 할 가치는 거의 없었으므로, 문제의 문자를 사용하지 않고 나머지 프로그램을 작성하기로 결정했습니다.

래퍼의 일부가 삭제되면 어떻게됩니까?

  • 단어의 삭제는 eval그것이로 전환하는 원인 bareword는 어떤 의미로, 문자열을. Perl은 이것을 좋아하지 않지만 인용 부호로 묶인 것처럼 처리합니다. 따라서 다음과 같이 eal<+eval<+...해석됩니다"eal" < +eval<+.... 기본적으로 많이 중첩 된 에바 (어쨌든 사용하지 않는)의 결과를 가져 와서 정수로 변환하고 무의미한 비교를 수행하기 때문에 프로그램 작동에는 영향을 미치지 않습니다. (이러한 종류의 상황은 정상적인 상황에서 유용한 것은 아니기 때문에 경고 스팸이 많이 발생합니다. 우리는이를 사용하여 삭제를 흡수합니다.) 이렇게하면 필요한 여는 꺾쇠 괄호 수가 변경됩니다 (열기 괄호 때문에) 이제는 비교 연산자로 해석되고 있지만 마지막에 주석 체인은 문자열이 중첩 된 횟수에 관계없이 안전하게 종료되도록합니다. (여기에 #엄격히 필요한 것보다 더 많은 표시가 있습니다. 프로그램을 압축하기 위해 작성했던 것처럼 작성했습니다.
  • A는 경우 <삭제됩니다, 코드는 이제 구문 분석합니다 eval(eval<...>). 보조, 외부는 eval우리는 그들이 전혀 정상적으로 돌아 오면 (프로그램 등 실제 효과가 아무것도 반환하지 평가하고있는 프로그램은, 그것은 일반적으로 NULL 문자열 또는 bareword는 때문에, 아무런 효과가 없습니다, 더 일반적으로 그들은을 통해 반환 예외 eval는 null 문자열을 반환하거나 exit전혀 반환하지 않도록 사용 합니다).
  • a +가 삭제되면 인접한 코드가 손상되지 않은 경우 즉시 영향을 미치지 않습니다. 단항 +은 프로그램에 영향을 미치지 않습니다. (원본 +이 존재 하는 이유는 손상을 복구하는 데 도움 이되므로 관계 연산자가 아닌 <단항으로 해석 되는 상황의 수가 증가하므로 <>유효하지 않은 프로그램을 생성하려면 삭제가 더 필요합니다.)

랩퍼 가 충분히 삭제되면 손상 될 있지만 구문 분석되지 않는 항목을 생성하려면 일련의 삭제를 수행해야합니다. 네 번의 삭제로 다음을 수행 할 수 있습니다.

eal<evl<eval+<...

Perl에서 관계 연산자 <는 비 연관 적이므로 구문 오류 (와 동일한 구문 오류 1<2<3)가 발생합니다. 따라서 작성된 프로그램의 한도는 n = 3입니다. 더 많은 단항을 추가 +하는 것은 그것을 늘리는 유망한 방법처럼 보이지만 래퍼 내부가 손상 될 가능성이 높아짐에 따라 새 버전의 프로그램이 작동하는 것이 매우 어려울 수 있음을 확인합니다.

랩퍼가 중요한 이유는 evalPerl에서 구문 오류를 컴파일하려고 할 때 발생하는 예외와 같은 예외를 포착하기 때문입니다. 이 때문에 eval문자열 리터럴이며, 문자열의 컴파일은 런타임에 발생하고, 문자 그대로 컴파일하지 않을 경우, 결과 예외가 잡힐. 이로 인해 eval널 문자열이 리턴되고 오류 표시기가 설정 $@되지만, 우리는 결코 어느 것도 확인하지 않습니다 (반환 된 널 버전의 프로그램에서 리턴 된 널 문자열을 실행하는 경우는 제외). 결정적으로 이것은 내부 코드에 문제가 발생하면래퍼는 구문 오류를 일으킨 다음 래퍼는 코드가 아무것도하지 않게합니다 (그리고 프로그램은 손상되지 않은 자체 사본을 찾기 위해 계속 실행됩니다). 따라서 내부 코드는 래퍼만큼 방사선에 강하지 않아도됩니다. 우리가 걱정하는 것은 손상되면 프로그램의 손상되지 않은 버전과 동일하게 작동하거나 그렇지 않으면 충돌 ( eval예외를 포착하고 계속할 수 있음)하거나 아무것도 인쇄하지 않고 정상적으로 종료된다는 것입니다.

포장지 내부

래퍼 내부의 코드는 기본적으로 다음과 같습니다 (다시 말해서 _스택 교환이 바로 앞에 표시되지 않는 Control 이 있습니다 -+).

eval+(q(...)=~y=A-Z=-+;-AZz-~=r)

(우리가 사용할 수없는이 코드는 글로브 안전 문자로 완전히 작성된 것입니다, 그 목적은 음역과 문자열 리터럴 평가를 통해 가능 실제 프로그램을 작성할 수 있도록 문장 부호의 새로운 문자를 추가하는 것입니다 '또는 "우리의 인용 등 마크는하지만 q()또한) 펄의 문자열을 형성 할 수있는 유효한 방법입니다. (인쇄 할 수없는 문자의 이유는 프로그램에서 문자 공간 문자없이 문자를 공백 문자로 음역해야하기 때문입니다. 따라서 ASCII 31에서 시작하여 범위를 형성하고 해당 범위의 두 번째 요소로 공백을 잡습니다.) 음역을 통해 일부 캐릭터를 제작하는 경우 분명히 음역을하기 위해 캐릭터를 희생해야합니다 .대문자는 그다지 유용하지 않으며 문장 부호에 액세스 할 수없는 것보다 대문자를 쓰는 것이 훨씬 쉽습니다.

glob의 결과로 사용할 수있는 문장 부호 알파벳은 다음과 같습니다 (위 줄은 인코딩을, 아래 줄은 인코딩하는 문자를 나타냅니다).

BCDEFGHIJKLMNOPQRSTUVWXYZ
 ! "# $ % & '() * +; <=>? @ AZz {|} ~

가장 주목할만한 점은 글로 안전하지 않지만 공백 문자와 함께 Perl 프로그램을 작성하는 데 유용한 문장 부호가 많이 있습니다. 또한 문자 그대로의 문자를 대문자로 된 두, 저장 A하고 Z(인코딩되지 자체에 만에를 T하고 U있기 때문에, A상위뿐만 아니라 낮은 범위의 끝점으로 필요했다) 이렇게하면 새로운 인코딩 된 문자 집합을 사용하여 음역 명령을 작성할 수 있습니다 (대문자는 그다지 유용하지 않지만 대문자 변경을 지정하는 데 유용합니다). 우리가 사용할 수 없었던 가장 눈에 띄는 문자는 [, \]이지만 필요하지 않습니다 (출력에 줄 바꿈이 필요할 때 암시 적 줄 바꿈을 사용하여 생성했습니다.say쓰지 말고 \n; chr 10또한 작동했지만 더 장황합니다).

평소와 같이 래퍼 내부가 문자열 리터럴 외부에서 손상되면 어떻게 될지 걱정해야합니다. 손상 eval되면 실행되는 것이 방지됩니다. 우린 괜찮아 따옴표가 손상되면 문자열 내부가 유효한 Perl이 아니기 때문에 래퍼가 그것을 붙잡을 것입니다. 따라서 문자열에서 많은 빼기를 사용하면 유효한 Perl을 만들 수 있다고해도 아무것도하지 않습니다. 허용되는 결과입니다). 이 구문 오류가 아닌 경우 일반적으로 원인이 평가되는 문자열을 난도질 것, 음역에 손상 구문 오류가 될; 나는 이것이 깨지는 경우가 100 % 확실하지 않다. 그러나 나는 그것을 확실하게하기 위해 무차별 강제하고있다.

인코딩 된 프로그램

문자열 리터럴 내부를 살펴보고 내가 사용한 인코딩을 되돌리고 공백을 추가하여 더 읽기 쉽게 만들면 다음 -+과 같이 A됩니다.

$o=q<
  length$o  ==181 || zzzz((()));
  do {
    chop ($t = "eval+<"x4);
    $r = '=-+;-AZz-~=';
    $s = '$o=q<' . $o . '>;eval$o';
    eval '$s=~y' . $r . 'A-Z=';
    say "$t(q($s)=~y=A-Z${r}r)" . "####>"x6;
    say ";" for 1..4
  } for 1..4;
  exit>;
eval $o

Quies에 익숙한 사람들은이 일반적인 구조를 인식 할 것입니다. 가장 중요한 부분은 처음에 $ o가 손상되지 않았 음을 확인합니다. 문자가 삭제 된 경우, 길이가 일치하지 않습니다 181우리가 실행할 수 있도록, zzzz((()))이 때문에 타의 추종을 불허 괄호에 구문 오류가 아닌 경우, 이는 당신이 때문에 없음, 모든 세 개의 문자를 삭제하더라도 런타임 오류 것, zzzz, zzz, zz, 그리고 z함수이며,이 삭제가 아닌 다른 함수로 분석 방지 할 수있는 방법이 없습니다 (((와 obvous 구문 오류의 원인은. 수표 자체도 손상에 영향을받지 않습니다. 가 ||손상 될 수 |있지만이 발생합니다 zzzz((()))무조건 실행하는 전화를; 변수 또는 상수를 손상 시키면 다음 중 하나를 비교하기 때문에 불일치가 발생합니다 0.180, 179, 178의 숫자의 어떤 부분 집합에 평등 181; 1 =을 제거 하면 구문 분석 오류가 발생하고 2 =는 필연적으로 LHS가 정수 0 또는 널 문자열로 평가되게하며, 둘 다 거짓입니다.

업데이트 :이 검사는 이전 버전의 프로그램에서 약간 잘못되었으므로 문제를 해결하기 위해 편집해야했습니다. 이전 버전은 디코딩 후 다음과 같습니다.

length$o==179||zzzz((()))

이를 위해 처음 세 문장 부호를 삭제하는 것이 가능했습니다.

lengtho179||zzz((()))

lengtho179간결한 말은 진실하기 때문에 점검을 어기는 것입니다. B공백 문자를 인코딩하는 두 개의 문자 를 추가 하여이 문제를 해결했습니다 . 최신 버전의 quine은 다음을 수행합니다.

length$o  ==181||zzzz((()))

이제 구문 오류없이 =부호와 부호 를 숨길 수 없습니다 $. (난의 길이가 있기 때문에 두 개의 공간이 아닌 하나를 추가했다 180문자 그대로 둘 것 0정수 비교 성공한 bareword는, 제로.이 상황에서 악용 될 수있는 소스로 문자를) 최종 업데이트

길이 검사가 통과되면 최소한 문자 삭제 측면에서 사본이 손상되지 않았 음을 알 수 있습니다. 따라서 사본이 간단합니다 (손상된 디코딩 테이블로 인한 구두점 대체는이 검사에서 포착되지 않습니다) 그러나 나는 해독 테이블 에서만 3 번의 삭제 가 퀴인을 깨뜨리지 않는다는 것을 무차별 강제를 통해 이미 확인했습니다 . 아마도 대부분 구문 오류가 발생합니다. 우리는 $o이미 변수를 가지고 있으므로 외부 래퍼를 하드 코딩하면됩니다 (약간의 압축 정도; 질문 의 부분을 완전히 생략하지는 않았습니다 ). 한 가지 요령은 대부분의 인코딩 테이블을$r; 내부 래퍼의 인코딩 테이블 섹션을 생성하기 위해 문자 그대로 인쇄하거나 그 주위에 코드를 연결 eval하고 디코딩 프로세스를 역으로 실행하기 위해 ( $ o 의 인코딩 된 버전이 무엇인지 파악할 수 있습니다 ) 이 시점에서 디코딩 된 버전 만 사용할 수 있습니다.

마지막으로, 우리가 완전한 사본이어서 전체 원본 프로그램을 출력 할 수 있다면 exit다른 사본도 프로그램을 인쇄하려고 시도하는 것을 막기 위해 호출 합니다.

확인 스크립트

아주 예쁘지는 않지만 누군가가 물었 기 때문에 게시했습니다. 나는 다양한 설정으로 여러 번 실행했습니다 (일반적으로 변경 $min하고 $max관심있는 다양한 영역을 확인하기 위해). 완전 자동화 된 프로세스가 아니 었습니다. 다른 곳의 CPU로드로 인해 실행이 중지되는 경향이 있습니다. 이 일이 발생했을 때, 나는 $min그 첫 번째 값으로 $x완전히 변경 되지 않았고 스크립트를 계속 실행했습니다 (그래서 범위의 모든 프로그램이 결국 확인되었는지 확인하십시오). 다른 사본에서 삭제하면 더 이상 할 수 없다는 것이 명백하기 때문에 프로그램의 첫 번째 사본에서만 삭제를 확인했습니다.

use 5.010;
use IPC::Run qw/run/;
undef $/;
my $program = <>;
my $min = 1;
my $max = (length $program) / 4 - 3;
for my $x ($min .. $max) {
    for my $y ($x .. $max) {
        for my $z ($y .. $max) {
            print "$x, $y, $z\n";
            my $p = $program;
            substr $p, $x, 1, "";
            substr $p, $y, 1, "";
            substr $p, $z, 1, "";
            alarm 4;
            run [$^X, '-M5.010'], '<', \$p, '>', \my $out, '2>', \my $err;
            if ($out ne $program) {
                print "Failed deleting at $x, $y, $z\n";
                print "Output: {{{\n$out}}}\n";
                exit;
            }
        }
    }
}

say "All OK!";

답변

Befunge-98 , 884, n = 14, 점수 ≈ 2.636

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx"""""""""""""""fffffffffffffff'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''000000000000000\\\\\\\\\\\\\\\'''''''''''''''fffffffffffffff\\\\\\\\\\\\\\\111111111111111---------------:::::::::::::::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!000000000000000aaaaaaaaaaaaaaa---------------bbbbbbbbbbbbbbb---------------***************jjjjjjjjjjjjjjj$$$$$$$$$$$$$$$'''''''''''''''+++++++++++++++kkkkkkkkkkkkkkk,,,,,,,,,,,,,,,333333333333333kkkkkkkkkkkkkkk$$$$$$$$$$$$$$$000000000000000{{{{{{{{{{{{{{{'''''''''''''''888888888888888uuuuuuuuuuuuuuu'''''''''''''''!!!!!!!!!!!!!!!111111111111111+++++++++++++++'''''''''''''''xxxxxxxxxxxxxxx###############;;;;;;;;;;;;;;;:::::::::::::::!!!!!!!!!!!!!!!kkkkkkkkkkkkkkk@@@@@@@@@@@@@@@dddddddddddddddkkkkkkkkkkkkkkk:::::::::::::::eeeeeeeeeeeeeeekkkkkkkkkkkkkkk,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;

온라인으로 사용해보십시오!

정확히 14자를 제거 할 때뿐만 아니라 최대 14자를 제거해도 작동하지 않습니다 .

n = 14매우 임의적 인 선택처럼 보일 수도 있지만 실제로 사용한 기술은 실제로 1에서 14까지의 방사선 경화 명령에만 사용할 수 있지만 그 이상으로 쉽게 사용할 수는 없습니다 (가능하지만 방법은 없습니다). order-1 quine은 73 바이트에 불과합니다 (더 크게 적용되지 않는 일부 골프 트릭을 사용하더라도 n).

200 20 xx""''ÈÈ..aa22**..33kk$$00{{''!!uu''!!11++''xx##;;::!!kk@@::,,,,;;

설명

내가 작업 때 이 답변 난에 명령 포인터의 델타를 설정할 수 있다는 발견 (2,0)다음 코드와 방사선 – 경화 조건 :

20020xx

이것이 작동하는 이유는 해당 답변을 참조하십시오. 나는 이것을 손으로 약간만 들으면서 이것을 발견했지만, 이것은 여러 문자를 제거 할 때 견고한 패턴이 있는지에 대한 의문을 제기했다. 그래서 나는 짧은 Mathematica 스크립트를 작성하여 무차별 대입으로 검색했습니다.

n = 14;
m = 4;
Print @ FromDigits @ {
      m + 1, 0,
      ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
      m + 1, 0
} & /@ Select[
   Range[0, 2^(n - 4) - 1],
   AllTrue[
     Subsets[{
         m + 1, 0,
         ## & @@ ((m + 1) IntegerDigits[#, 2, n - 4]),
         m + 1, 0
       },
       {n - m, n - 1}
     ] //. {a___, _, m + 1} | {a___, 0, _} :> {a},
     MatchQ@{___, m + 1, 0}
  ] &
];

이것은 매우 빠르게 패턴을 드러냈다. 최대의 제거를 위해 작동하는 해당 조각 얻으려면 n문자를, 당신이 사용할 수있는 (m0x){n}m0m입니다 n+1x중 하나입니다 m또는 0. 따라서 다음 두 문자는 최대 2자를 제거하는 데 효과적입니다.

30030030
30030330
30330030
30330330

나는 이것을 증명할 수 있다고 확신하지만, 단순히 n최대까지 확인 했습니다 7. 물론 이것은 n+1하나의 숫자로 나타낼 수 있는 한만 작동하며 Befunge 98에서 가장 큰 숫자 f는 15를 나타냅니다. 이것이 나의 접근 방식이로 제한되는 이유 n = 14입니다. 누군가 델타를 더 크게 설정하는 방법을 찾으면 n+1이 방사선 경화 퀴니의 순서를 무한정 늘릴 수 있습니다.

실제 코드를 보자. 기본적으로 두 부분이 있습니다. 먼저 (15,0)방금 언급 한대로 델타를 설정했습니다 .

f00f00f00f00f00f00f00f00f00f00f00f00f00f00f0xxxxxxxxxxxxxxx

나머지 코드는 각 명령을 15 번 반복하여 소스를 인쇄합니다. 반복을 제거하면 다음과 같습니다.

"f'0\'0\'f\1-:!!0a-b-*j$'+k,3k$0{'8u'!1+'x#;:!k@dk:ek,;

",이 문자열 모드를 시작 주위에 포장 한 후 다시 스택과 끝 문자열 모드에 (자신을 제외한) 모든 문자를 밀어 : 표준 2D quining 기술이다. 에 걸쳐 있기 때문에, 이것은 우리가 하반기의 모든 코드 포인트를 얻을 수 있습니다,하지만 우리에게 전반에서 유용 아무것도 얻을 실패 f00f00...f0비트, 그것은 단지가 될 수있는 두 문자 (기록 할 것이다 f또는 0문자가 삭제됩니다에 따라 ). 그러나이 부분은 15 번 반복되는 문자로 구성되지 않으므로 어쨌든 별도로 인쇄해야합니다.

보다 편리하게 수정되지 않은 quine에서 앞에있는 문자열의 길이 "-1 (mod 15)입니다. 이렇게하면 제거하는 문자 수 (최대 14 개)에 관계없이 기록 된 문자 는 항상 3 (1 x과 2 f및 1 0)이됩니다. 이것은 실제로 최대 14의 모든 방사선 주문에 해당됩니다.

이제 f00f00...f0부품 을 인쇄하여 시작합니다 .

f'0\'0\'f\1-:!!0a-b-*j$'+k,

f          Push 15, a loop counter.
'0\'0\'f\  Put "00f" underneath the loop counter.
1-         Decrement the loop counter.
:!!        Copy it, and turn it into a 1 if it's positive.
0a-b-      Push -21.
*          Multiply by 0 if the loop counter is zero, or by 1 otherwise.
j          Jump that many steps. If the value was 0, this is a no-op and
           the loop ends. Otherwise, this brings us back after the f.
$          Pop the loop counter (which is now 0).
'+k,       Print the top of the stack 43 times, which gives us all of
           the "f00f00...f0" and leaves one "0" on top of the stack.

다음은 3k$단순히 프로그램 시작 부분에서 0푸시 한 세 문자뿐만 아니라이를 버립니다 ". 이제 스택에는 삭제 된 문자에 따라 "원본 뒤의 일부 쓰레기와 뒤에있는 문자 만 포함 f00f00...f0됩니다.

이제 남은 문자를 포함하여 스택의 상단을 뒤집고 각각을 15 번 인쇄해야합니다.

0{     Start a new, empty stack. This pushes two zeros onto the original stack.
'8u    Move the top 56 values from the original stack to the new one, which
       is the 54 characters after the " as well as those two zeros. This is
       implemented as pop-push loop, so it reverses the order of those elements.
'!1+   Push a " by incrementing a !.
'x     Push an x. Now we've got all the characters that are repeated 15 times.
#;     Enter a loop. This is a standard technique for Befunge-98: the ; is
       a bit like a comment character, that ignores everything until the next
       ;, but we jump over the first one with #, so that from now on only
       the code inside will be executed (over and over).
  :!     Copy the top of the stack, and compute logical NOT (1 if 0, 0 otherwise).
  k@     Terminate the program that many times (i.e. when the top of the
         stack is zero).
  dk:    Make 14 copies of the top of the stack.
  ek,    Print 15 characters from the top of the stack.
;

그리고 그게 다야. 🙂


답변

자바 스크립트 (ES6), 927 바이트, n = 1, 점수 = 859329

참고 : 이것을 실행하기 위해 브라우저 콘솔과 같은 REPL을 사용하지 마십시오.

이것은 코드 길이가 중요하기 전에 작성되었으므로 아직 골프를 치지 않았습니다.

이것은 매우 어려웠으며 철저한 설명이 필요합니다. 이 도전을 조금 더 탐구 한 후에 나중에 쓸 것입니다!

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

참고 : 후행 줄 바꿈이 있습니다

기본적으로 첫 번째 줄은 setTimeout올바른 ‘잘못된 철자’의 이름 을 유효한 함수 로 바꾸도록 신중하게 구성되어 있으므로 문자 중 하나에서 문자를 제거 setTimeout하면 코드가 오류가 발생하지 않고 비판 버전이 실행될 수 있습니다. 또한 첫 번째 줄에서 한 문자를 제거해도 오류가없고 나머지 코드는 영향을받지 않도록 실행될 수 있습니다.

두 번째와 세 번째 블록은 정확히 같습니다. 하나가 완료되면 다른 하나는 _quine을 복제하지 않도록 변수를 설정합니다 . 이러한 블록 중 하나가 오류를 발생시키는 경우 다른 블록이를 사용하여 비동기 적으로 호출 되었기 때문에 다른 블록에 영향을 미치지 않습니다 setTimeout. 에러는 _설정되지 않으므로 다른 블록은 성공적으로 종료됩니다. 기본 코드는 문자열로되어 있으며, 제거되지 않았는지 확인하기 위해 각 블록의 길이를 확인합니다.

템플릿 문자열의 끝에 주석이있는 다음 줄의 템플릿 문자열은 템플릿 문자열을 구성하는 백틱 중 하나가 제거되면 코드에서 오류가 발생하지 않도록 보호합니다. 종료 백틱이 제거되면 주석에서 백틱으로 템플릿 문자열이 끝납니다. 시작 백틱이 제거되면 setTimeout이 할당되지 않은 함수 (no-op)로 평가되고 코드는 setTimeout없이 정상적으로 실행됩니다. 다른 주석으로 끝 백틱이 무효화됩니다.

그게 뭐야? 시도해보고 싶습니까? 더 말하지 마!

전체 페이지 모드를 권장합니다.

입력 상자를 무시하십시오.이 스 니펫은 입력을받지 않습니다.

코드에서 한 문자를 제거하십시오!

믿지 않습니까? 정상적인 코드는 여전히 작동하지만 (Quine하지는 않습니다 …) 다음과 같이 해보십시오 console.log(5)!

참고 : REPL 기능을 비활성화하려면 스 니펫을 약간 수정해야 하므로이 답변에 대해서만 여러 출력 기능을 제거했습니다.

etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;
setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`

setTimeout
`c="function f(){x=String.fromCharCode(96);n=String.fromCharCode(10);q=String.fromCharCode(34);y='etTimeout=stTimeout=seTimeout=setimeout=setTmeout=setTieout=setTimout=setTimeut=setTimeot=setTimeou=unescape=>42;'+n;z='setTimeout'+n+x+'c='+q+f+';f();_=1'+q+';if(window._);else if(c.length>339)eval(c)//'+x+'///'+x+n+n;console.log(y+z+z)};f();_=1";if(window._);else if(c.length>339)eval(c)//`///`
<!--                               Try the test suite below!                              --><strong id="bytecount" style="display:inline; font-size:32px; font-family:Helvetica"></strong><strong id="bytediff" style="display:inline; margin-left:10px; font-size:32px; font-family:Helvetica; color:lightgray"></strong><br><br><pre style="margin:0">Code:</pre><textarea id="textbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><pre style="margin:0">Input:</pre><textarea id="inputbox" style="margin-top:5px; margin-bottom:5px"></textarea><br><button id="testbtn">Test!</button><button id="resetbtn">Reset</button><br><p><strong id="origheader" style="font-family:Helvetica; display:none">Original Code Output:</strong><p><div id="origoutput" style="margin-left:15px"></div><p><strong id="newheader" style="font-family:Helvetica; display:none">New Code Output:</strong><p><div id="newoutput" style="margin-left:15px"></div><script type="text/javascript" id="golfsnippet">var bytecount=document.getElementById("bytecount");var bytediff=document.getElementById("bytediff");var textbox=document.getElementById("textbox");var inputbox=document.getElementById("inputbox");var testbtn=document.getElementById("testbtn");var resetbtn=document.getElementById("resetbtn");var origheader=document.getElementById("origheader");var newheader=document.getElementById("newheader");var origoutput=document.getElementById("origoutput");var newoutput=document.getElementById("newoutput");textbox.style.width=inputbox.style.width=window.innerWidth-50+"px";var _originalCode=null;function getOriginalCode(){if(_originalCode!=null)return _originalCode;var allScripts=document.getElementsByTagName("script");for(var i=0;i<allScripts.length;i++){var script=allScripts[i];if(script.id!="golfsnippet"){originalCode=script.textContent.trim();return originalCode}}}function getNewCode(){return textbox.value.trim()}function getInput(){try{var inputText=inputbox.value.trim();var input=eval("["+inputText+"]");return input}catch(e){return null}}function setTextbox(s){textbox.value=s;onTextboxChange()}function setOutput(output,s){output.innerHTML=s}function addOutput(output,data){output.innerHTML='<pre style="background-color:'+(data.type=="err"?"lightcoral":"lightgray")+'">'+escape(data.content)+"</pre>"}function getByteCount(s){return(new Blob([s],{encoding:"UTF-8",type:"text/plain;charset=UTF-8"})).size}function onTextboxChange(){var newLength=getByteCount(getNewCode());var oldLength=getByteCount(getOriginalCode());bytecount.innerHTML=newLength+" bytes";var diff=newLength-oldLength;if(diff>0){bytediff.innerHTML="(+"+diff+")";bytediff.style.color="lightcoral"}else if(diff<0){bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgreen"}else{bytediff.innerHTML="("+diff+")";bytediff.style.color="lightgray"}}function onTestBtn(evt){origheader.style.display="inline";newheader.style.display="inline";setOutput(newoutput,"");setOutput(origoutput,"");var input=getInput();if(input===null){addOutput(origoutput,{type:"err",content:"Input is malformed. Using no input."});addOutput(newoutput,{type:"err",content:"Input is malformed. Using no input."});input=[]}doInterpret(getNewCode(),input,function(data){addOutput(newoutput,data)});doInterpret(getOriginalCode(),input,function(data){addOutput(origoutput,data)});evt.stopPropagation();return false}function onResetBtn(evt){setTextbox(getOriginalCode());origheader.style.display="none";newheader.style.display="none";setOutput(origoutput,"");setOutput(newoutput,"")}function escape(s){return s.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.alert=function(){};window.prompt=function(){};function doInterpret(code,input,cb){var workerCode=interpret.toString()+";function stdout(s){ self.postMessage( {'type': 'out', 'content': s} ); }"+" function stderr(s){ self.postMessage( {'type': 'err', 'content': s} ); }"+" function kill(){ self.close(); }"+" self.addEventListener('message', function(msg){ interpret(msg.data.code, msg.data.input); });";var interpreter=new Worker(URL.createObjectURL(new Blob([workerCode])));interpreter.addEventListener("message",function(msg){cb(msg.data)});interpreter.postMessage({"code":code,"input":input});setTimeout(function(){interpreter.terminate()},1E4)}setTimeout(function(){getOriginalCode();textbox.addEventListener("input",onTextboxChange);testbtn.addEventListener("click",onTestBtn);resetbtn.addEventListener("click",onResetBtn);setTextbox(getOriginalCode())},100);function interpret(code,input){_=undefined;window={};alert=function(s){stdout(s)};window.alert=alert;console.log=alert;prompt=function(s){if(input.length<1)stderr("not enough input");else{var nextInput=input[0];input=input.slice(1);return nextInput.toString()}};window.prompt=prompt;(function(){try{_=undefined;eval(code);if(typeof evalResult=="disabled_function_evaluation"){var callResult=evalResult.apply(this,input);if(typeof callResult!="undefined")stdout(callResult)}}catch(e){stderr(e.message)}})()};</script>

더 나은 설명이 곧 나옵니다. 그동안 댓글 / 질문 / 비평이있는 채팅 @jrich에서 저를 ping 해주십시오.