튜링 완성도를위한 가장 희귀 한 문자


107

요약:

특정 언어에 대해 귀하의 언어가 Turing-Complete 가 될 수있는 가장 작은 고유 문자는 무엇입니까?

도전:

선택한 모든 언어에 대해 언어가 Turing-Complete가 될 수있는 가장 작은 문자 하위 세트를 찾으십시오. 원하는 문자 세트를 여러 번 재사용 할 수 있습니다.


예 :

  • 자바 스크립트 : +!()[]( http://www.jsfuck.com )

  • Brainfuck : +<>[](랩핑 셀 크기를 가정)

  • 파이썬 2 : ()+1cehrx(와 같은 스크립트로 제작 exec(chr(1+1+1)+chr(1)))

채점 :

이 과제는 바이트가 아닌 문자 로 점수가 매겨 집니다. 예를 들어, 예제의 점수는 6, 5 및 9입니다.


노트:

  • 이 과제는 귀하의 언어 만 Turing-Complete이어야한다는 점에서 다른 언어와 차별화됩니다 (언어의 모든 기능을 사용할 수있는 것은 아닙니다).

  • 가능하지만 사용 된 문자를 줄이지 않고 답변을 게시하지 마십시오. 예 : 8 자의 Brainfuck (다른 모든 문자는 기본적으로 주석이므로)

  • 서브셋이 Turing-Complete 인 이유에 대해 최소한 간단한 설명을 제공해야합니다.


90
단항 1 문자 한숨
데니스

4
@Dennis 흥미로운 숫자 이론 문제를 위해 내장 된 Jelly 나 05AB1E와 다르지 않습니다. 이 과제는 여전히 타르타르 트로 설계되지 않은 모든 언어에서 흥미롭고 사소한 최적화 문제처럼 보입니다.
마틴 엔더

7
@MartinEnder Java 나 C와 같은 언어로 답변을보고 싶습니다.
Julian Lachniet

9
솔루션이 언어의 모든 유효한 문자 인 esolang에 솔루션을 게시하지 마십시오. 모욕적이거나 영리하지 않습니다.
Pavel

20
@Pavel 흥미 롭거나 영리하지 않다는 것은 그것이 공표되어서는 안된다는 것을 의미 할 수도 있지만 반드시 게시해서는 안된다는 것을 의미합니다.
Dennis

답변:


77

하스켈, 4 자

()=;

함께 ()=우리는 S, K 및 I. 하나에 의해 분리되어야하는 정의가 정의 할 수있는 ;또는 NL을.

우리 (==)는 S로 정의 합니다 (두 번째 줄은 더 읽기 쉬운 버전을 나타냄).

((=====)==(======))(=======)=(=====)(=======)((======)(=======))
( a     == b      ) c       = a      c       ( b       c       )

(===) 물어보기:

(=====)===(======)=(=====)
 a     === b      = a

그리고 (====)나는 :

(====)(=====)=(=====)
(====) a     = a 

다행히 (==), (===), (====), 등 유효한 기능 / 매개 변수 이름입니다.

@ ais523이 지적했듯이 SKI는 Haskell과 같은 강력한 유형의 언어로는 충분하지 않으므로 고정 소수점 결합기를 추가해야합니다 (=====).

(=====)(======)=(======)((=====)(======))
(=====) f      = f      ((=====) f      )

17
이 구조는 직접 작동하지 않습니다. SKI는 Haskell과 같은 강력한 형식의 언어로 완성되지 않습니다. 그러나 동일한 기술을 사용 fix하여을 정의 할 수 있으며 SKI + fix 강력한 유형의 언어로도 튜링 완료됩니다.

아, 그래서 당신은 각 프로그램의 시작 부분에 그 정의를 접두사로 사용합니까?
PyRulez

@PyRulez : 그렇습니다. 우리의 기본값에 따라 주어진 문자 세트로 함수를 구성하는 것으로 충분하다고 가정합니다. 전체 프로그램이 필요하지 않습니다.
nimi

1
(==)기본 평등 연산자
자랑스러운 Haskeller

@proudhaskeller : 그렇습니다. 실제로 프로그래밍하고 싶다면 이름을 바꾸는 것이 좋을 것입니다 (==). 그러나 위의 코드는 튜링 완료의 증거입니다.
nimi

61

자바 스크립트 (ES6), 5 자

도움을 주신 @ETHproductions와 @ATaco에게 감사드립니다. 이것은 그룹 프로젝트였으며, 원래의 아이디어는 내 것이었지만 많은 세부 사항들이 그들의 것입니다. 이 JavaScript 서브셋이 여기서 개발 된 채팅 토론을 참조 하십시오 .

[]+=`

꽤 잘한다는 설립있어 어떤 자바 스크립트 프로그램은 문자 (작성 할 수 있습니다 []()+!)하지만, 5 개 문자는 충분하지 않습니다 . 그러나 이것은 임의의 JavaScript를 작성하는 데 어려움이 없습니다. Turing-complete 언어를 작성하는 데 어려움이 있으며 Turing-complete 언어가 DOM 또는 대화식 I / O에 액세스 할 필요가 없다는 사실을 사용하면 필요한 모든 기능을 갖춘 프로그램을 작성할 수 있습니다 eval또는 이에 상응 하는 기능이 없어도

기본 부트 스트랩

JavaScript는 유형 이 매우 유연합니다. 예를 들어 []빈 배열이지만 +[]0이며 []+[]null 문자열입니다. 특히이 문자 ​​세트로 0을 생성 할 수 있다는 사실은 그룹화에 대한 괄호 효과를 시뮬레이션 할 수있게합니다. (a)로 쓸 수 있습니다 [a][+[]]. 이러한 종류의 트릭을 사용하여 +[]다음을 사용하여 다양한 문자를 생성 할 수 있습니다 .

  • [][+[]]is undefined(빈 배열의 첫 번째 요소 임); 그래서
  • []+[][+[]]이다 "undefined"(의 스트링 화 undefined); 그래서
  • [[]+[][+[]]]입니다 ["undefined"](배열에 래핑). 그래서
  • [[]+[][+[]]][+[]]이다 "undefined"(첫번째 요소); 그래서
  • [[]+[][+[]]][+[]][+[]]입니다 "u"(첫 번째 문자).

u가장 쉬운 캐릭터 중 하나이지만 유사한 기술을 사용하여 다양한 다른 캐릭터를 만들 수 있습니다. 같은 링크는 이전과 같이 우리에게로 액세스 다음 문자 목록을 제공합니다 +[](이 경우와 같은 목록을 +[]()제외하고, ,이 / 우선 순위를 그룹화 이외의 목적을 위해 괄호를 사용하는 유일한 건축 때문에) :

0123456789acdefinotuvyIN (){}.

우리는 문자 세트 중 매우 많은 유용한 단어의 철자 수 (이것은 우리가 생산할 수있는 문자의 집합입니다 기억 문자열 우리는 어떤 종류의없이이를 실행하지 않는다 eval). 따라서 다른 인물이 필요합니다. 우리는 =나중에 유용하게 사용될 것이기 때문에를 사용할 것입니다. 그러나 당분간은 비교 연산자의 철자를 위해 사용할 것 ==입니다. 이를 통해 문자열을 생성하고 색인을 생성 할 수있는 falseand 를 생성 하고 문자열에 포함 할 수있는 문자를 true즉시 추가 lrs할 수 있습니다.

지금까지 우리가 할 수 없었던 철자를 가능하게하는 가장 중요한 단어는 constructor입니다. 이제 JavaScript에는 다음과 같은 속성 액세스 구문이 있습니다.

object.property

그러나 다음과 같이 쓸 수도 있습니다.

object["property"]

문자열 리터럴 대신 계산 된 속성을 사용하는 데 방해가되는 것은 없습니다. 따라서 우리는 라인을 따라 무언가를 할 수 있습니다

object["c"+"o"+"n"+"s"+"t"+"r"+"u"+"c"+"t"+"o"+"r"]

(전술 한 바와 같이 생성 된 문자, 코드가 빠르게 얻을 매우 ! 긴); object.constructor이는 임의의 객체 생성자에 액세스 할 수 있도록하는 것과 같습니다 .

우리가 할 수있는 몇 가지 트릭이 있습니다. 평범한 것에서 환상적인 것까지 :

  • 객체의 생성자는 함수입니다. 특히 이름이 있으며 해당 이름은 함수의 문자열 화의 일부입니다. 예를 들어, [[]+[]][+[]]["constructor"]이름이 String 인 문자열의 생성자를 구한 다음 문자열을 사용하여 대문자를 얻을 수 S있습니다. 이렇게하면 알파벳이 약간 확장되고 나중에 새로운 문자가 필요합니다.
  • 모든 배열은 동일한 생성자를가집니다. []["constructor"] == []["constructor"]입니다 true(와 달리 [] == [], false 임). 이것은 사소한 것처럼 보이지만 값을 지속적으로 저장하는 방법을 제공하기 때문에 매우 중요합니다. 생성자에 임의의 속성을 설정하고 나중에 다시 읽을 수 있습니다. (이것은 우리가 =생성 true하고 다른 방법 중 하나가 아닌 특히 사용하는 이유 중 하나입니다 false.) 예를 들어, 우리는 평가 [[]["constructor"]["a"]=[]]하고 나중에 []["constructor"]["a"]저장된 배열과 동일한 배열 을 읽고 다시 가져올 수 있습니다.

    이는 임의의 양의 데이터를 저장하고 검색하는 기능인 Turing-completeness에 필요한 요구 사항 중 하나를 충족시킵니다 . 생성자 속성 저장소에서 값을 가져 와서 요소가 2 개인 배열을 사용하여 cons 셀을 만든 다음 해당 값 중 하나 대신 다시 저장하여 메모리에 임의로 큰 데이터 구조를 구축 할 수 있습니다. 원하는 데이터에 액세스 할 수있을 때까지 데이터를 하나씩 분해하여이 저장소에 액세스 할 수 있습니다. 읽기는 파괴적이지만 데이터를 저장할 장소가 둘 이상 있기 때문에 받아 들일 수 있으므로 데이터를 읽을 때 복사 한 다음 사본을 원래 위치에 다시 배치 할 수 있습니다.

  • 그것은 우리가 함수의 생성자를 얻을 수있게한다 (우리가 제한된 알파벳으로 접근 할 수있는 많은 함수들이있다; []["find"]즉 Array.find가 가장 쉽게 접근 가능하지만 다른 것들이있다). 왜 유용한가요? 실제로 생성자의 의도 된 목적으로 사용하고 함수를 구성 할 수 있습니다! 불행히도, 문자 세트를 사용하면 함수 생성자에 계산 된 문자열을 전달할 수 없습니다. 그러나를 사용 `하면 문자열 리터럴 (예 :)을 전달할 수 있습니다 []["find"]["constructor"]`function body goes here`. 즉,를 사용하여 해당 동작을 완전히 표현할 수있는 한 실행시 모든 동작으로 함수 유형의 사용자 정의 값을 정의 할 수 있습니다 []+=. 예를 들어, []["find"]["constructor"]`[]+[]`널 문자열을 계산하여 버리고 종료하는 상당히 지루한 함수입니다. 기능은 유용하지 않지만 더 복잡한 기능이 있습니다. 함수가 매개 변수 또는 반환 값을 사용할 수는 없지만 생성자 속성 저장소를 사용하여 한 함수에서 다른 함수로 통신 할 수 있으므로 실제로는 문제가되지 않습니다. 또 다른 제한 사항은 `함수 본문에서 사용할 수 없다는 것 입니다.

    이제 우리는 커스텀 함수를 정의 할 수 있지만,이 시점에서 우리를 방해하는 것은 우리가 함수를 호출 하는 데 어려움이 있다는 것입니다. 프로그램의 최상위 레벨에서로 함수 ``를 호출 할 수 있지만 최상위 레벨에서만 함수를 호출 할 수 있다고해서 어떠한 종류의 루프도 수행 할 수 없습니다. 오히려 서로를 호출 할 수있는 기능이 필요합니다.

    우리는 다소 멋진 트릭으로 이것을 달성합니다. S앞서 생성 한 자본 을 기억 하십니까? 그것은 우리에게 철자를 알려줍니다 "toString". 우리는 그것을 부르지 않을 것입니다. 추가 []하여 문자열로 변환 할 수 있습니다. 대신에 우리는 그것을 대체 할 것입니다. 생성자 스토리지를 사용하여 지속되는 영구 배열을 정의 할 수 있습니다. 그런 다음 생성 된 함수를 배열의 toString메서드에 할당하면 해당 할당도 그대로 적용됩니다. 이제 우리가해야 할 일은 +[]배열에서 간단 하고 갑자기 사용자 정의 함수가 실행됩니다. 이것은 우리가 문자를 사용할 수 있음을 의미+=[]함수를 호출하기 때문에 함수가 서로 호출하거나 스스로 호출 할 수 있습니다. 이것은 우리에게 재귀를 제공하고, 우리에게 루프를 제공하고, 갑자기 Turing-completeness에 필요한 모든 것을 갖습니다.

Turing-completeness를 제공하는 일련의 기능과 그 구현 방법은 다음과 같습니다.

  • 무제한 스토리지 : 생성자 스토리지의 중첩 배열
  • 제어 흐름 : if및 재귀를 사용하여 구현됩니다 .
    • if: 부울을 숫자로 변환하고 2 요소 배열로 색인화합니다. 한 요소는 then문자열 화 된 경우에 대한 함수를 실행하고 다른 요소는 else문자열 화 된 경우에 대한 함수를 실행합니다
    • 재귀 : 생성자 저장소의 적절한 요소를 문자열 화
  • 명령 순서 : [a]+[b]+[c]평가하여 a, b그리고 c왼쪽에서 오른쪽으로 (적어도 내가 체크 브라우저)

불행히도 이것은 상당히 비현실적입니다. 문자열이 첫 번째 원칙에서 문자별로 구성되어야한다는 점을 감안할 때 엄청나게 클뿐만 아니라 I / O를 수행 할 수있는 방법도 없습니다 ( Turing-complete 일 필요 는 없음 ). 그러나 종료되면 나중에 생성자 저장소를 수동으로 살펴볼 수 있으므로 프로그램을 디버깅하는 것이 불가능하지 않으며 완전히 의사 소통되지 않습니다.


16
이것이 이름이 없으면 J5h * t를 제안합니다.
CalculatorFeline

1
좋은 예제 프로그램은 무엇입니까? 프라임 테스트? 안녕 세상?
CalculatorFeline

3
내, 이것은 너무 왓이다 ... 좋은 공포 영화처럼 맛있는 답변.
반 시계 회전을 중단

4
Angular1의 toString()의존성 주입에 대한 사용이 함수를 사용하는 가장 창의적인 방법 이라고 생각했습니다 . 이제 마음이 바뀌 었습니다.
Sunny Pun

1
다음은 예입니다 : pastebin.com/QGbjmB5Y
Esolanging Fruit

55

단항 , 1 자

0

성격의 선택은 실제로 중요하지 않습니다. 프로그램의 길이는 프로그램이 변환되는 brainfuck 프로그램을 정의합니다. 사양은 0문자를 요구하지만 대부분의 트랜스 필러는이를 확인하지 않는 것 같습니다.


44
우리는 아마도 스펙을 검증하는 트랜스 파일러와 관련된 문제를 공개해야합니다. 이것은 매우 심각한 문제입니다.
캡틴 맨

5
나는 기절했다. 농담인지 20 분이 걸렸습니다.
피터 A. 슈나이더

3
@ PeterA.Schneider 일부 인터넷 검색은 결과적으로 0의 문자열이 실제 상황에서 본 것 중 가장 큰 숫자 일 수 있지만 실제 컴퓨터에서는 절대 구현할 수는 없지만 이론적으로 누군가가 이런 식으로 퀴인을 실제로 구현했음을 알 수 있습니다.
대런 링거

12
그 0의 문자열은 실제로 어떤 맥락에서 보아도 가장 작은 숫자입니다.
Matthew 읽기

1
LOL, 글쎄, 당신이 부가적인 정체성으로 당신의 유일한 상징을 정의하는 것과 같은 바보 같은 일을한다면 ... : p
Darren Ringer

37

vim, 9 8 7 6 자

<C-v><esc>1@ad

다음과 같이 임의의 vimscript 프로그램을 빌드하고 실행할 수 있습니다.

  1. 시퀀스 aa<C-v><C-v>1<esc>dd@1<esc>dddd를 사용하여 <C-a>레지스터 를 얻습니다 1.

  2. 을 사용하여 삽입 모드로 들어간 a다음을 삽입하면 a나중에 매크로에 삽입 모드를 다시 입력하는 데 사용됩니다.

  3. 원하는 vimscript 프로그램의 각 문자에 대해

    1. 사용 <C-v><C-v>1<esc>리터럴 순서를 삽입 <C-v>1,

    2. 사용하는 @1(어느 <C-a><cr>한 최종가 <cr>증가하도록 필요한만큼 인해 마지막 행에 존재하는 무 조작 없음) 1원하는 문자의 ASCII 값에 도달 할 때까지이

    3. 로 삽입 모드를 다시 입력하십시오 a.

  4. 1레지스터 에서 줄을 삭제합니다 (마지막 줄 바꿈 과 함께) <esc>dd.

  5. 을 사용하여 결과를 vim 키 스트로크로 실행 한 @1다음 <esc>dd이전 단계에서 후행 줄 바꿈으로 입력 한 줄을 삭제하십시오.

  6. 로 임의의 바이트 시퀀스를 실행하십시오 dd@1. 로 시작하면 :vimscript 코드로 해석되며에서 개행 문자로 인해 실행됩니다 dd.

나는 이것이 최소한의 문자 세트라고 확신하지는 않지만 Turing-complete임을 증명하는 것은 매우 쉽습니다.


2
당신은 할 수 없습니다 i<C-v>1<ESC>작성 <C-a>하고 dd사용 할 수 있도록 @1임의의 숫자를 증가과 사용하지 않아도 될 <C-a>?
암소 qua

4
와우,이 대답은 믿어지지 않습니다! +1!
DJMcMayhem

@KritixiLithos 그것은 약간의 구조 조정 후 작동하게됩니다. 감사합니다!
Doorknob

2
@ mbomb007 사실 ... 흥미로운 구현 세부 사항으로 인해 <C-v>10\ n 대신 NUL을 삽입합니다 (묻지 마십시오). 어쨌든 Turing-completeness와 관련하여 중요하지 않습니다.
Doorknob


33

펄, 5 자

<>^es

다른 스크립팅 언어와 마찬가지로 아이디어는 eval임의의 문자열입니다. 그러나 문자 세트에는 따옴표 나 연결 연산자가 포함되어 있지 않으므로 임의의 문자열을 구성하는 것이 훨씬 복잡합니다. 주 eval^"처리하는 것이 훨씬 간단 할 수 있지만, 한 번 더 문자가있다.

우리의 주요 도구입니다 s<^><CODE>eeevals있는 CODE다음 출력을 evals. 더 많은 e효과를 기대할 수 있습니다.

우리 <>는 그렇지 않은 경우를 제외하고 glob 연산자 인을 사용하여 문자열을 얻 습니다. 첫 번째 문자는 <( <<연산자 처럼 보일 수 없음 ), 꺾쇠 괄호는 균형을 유지해야하며, 문자가 아닌 문자가 하나 이상 있어야합니다 (그렇지 않으면 readline 연산자로 해석 됨).

이러한 문자열을 함께 조정하면 ^B^V^S(*-/9;<>HJMOY[`\^begqstv가비지가있는 것을 허용하는 한 (문자 중 첫 세 개는 제어 문자 임) 문자 조합을 얻을 수 있습니다 .

예를 들어 get을 원한다고 가정하십시오 "v99". 얻을 수있는 한 가지 방법 v99"><<" ^ "e>>" ^ "see" ^ "^^^"에 대한 제약으로 인해 해당 문자열을 나타낼 수 없습니다 <>. 대신 다음을 사용합니다.

<^<<^>><>>^<^^^^^<>>^<^^^^^^e>^<^^^^^^^>^<^^^^^e>^<^^^^e^>^<e^^es>^<^ee^^>^<^<^^^^^>>^<^<>^^^^>^<^^^^^^^e>^<^^^^^^^^>

위의 Y9;v99;결과는 평가할 때 평문과 동일한 결과 v99(즉, ASCII 코드 99의 문자)를 산출합니다 .

따라서 전체 ^B^V^S(*-/9;<>HJMOY[`\^begqstv문자 세트를 사용하여 임의의 문자열을 생성 한 다음 위와 같이 변환하고 s<><CODE>eeee실행하도록 고정 시킬 수 있습니다. 불행하게도,이 문자셋은 연결을 수행하는 명백한 방법없이 여전히 매우 제한적입니다.

그러나 다행히도 별이 포함되어 있습니다. 이것은 우리 *b가 문자열로 평가할 수 있도록합니다 "*main::b". 그런 다음 *b^<^B[MMH^V^SY>(^ B, ^ V 및 ^ S는 리터럴 제어 문자입니다)는 (6, $&);다시 평가할 때 Perl의 일치 변수 값을 반환합니다 $&. 이를 통해 제한된 형태의 연결을 사용할 수 있습니다. 반복적으로을 $_사용하여 앞에 붙일 수 있고 eval s<^><THINGS>e을 사용할 s<\H*><*b^<^B[MMH^V^SY>>eee수 있습니다 $_( \H수평 공백 이외의 문자와 일치합니다. 문자 대신 문자 대신 점을 사용합니다).

를 사용하면 9-/모든 숫자를 쉽게 생성 할 수 있습니다. 숫자, v및 연결을 사용하여 임의의 문자를 생성 할 수 있습니다 (vXXX는 ASCII 코드 XXX의 문자를 생성 함). 그리고 그것들을 연결하여 임의의 문자열을 생성 할 수 있습니다. 우리가 할 수있는 것처럼 보입니다.

완전한 예를 작성해 봅시다. 자체 PID를 인쇄하는 프로그램을 원한다고 가정하십시오. 우리는 자연적인 프로그램으로 시작합니다 :

say$$

우리는 그것을 v-notation으로 변환합니다 :

s<><v115.v97.v121.v36.v36>ee

우리는 이것을 사용하여 다시 작성합니다 ^B^V^S(*-/9;<>HJMOY[`\^begqstv(공백은 가독성을위한 것이며 출력에 영향을 미치지 않습니다)

s<^><
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><9*9-9-9-9-9-9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-99/-9-99/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><99-9/9-9/9>e;
    s<^><v>;
    s<v\H\H><*b^<^B[MMH^V^SY>>eee;
    s<^><999/9-9/-9-9/-9-9/-9-9/-9>e;
    s<^><v>;
    s<v\H\H\H><*b^<^B[MMH^V^SY>>eee;
    s<\H*><*b^<^B[MMH^V^SY>>eee;
>eee;

마지막으로, 우리는 위의 프로그램을 변환 <>^es: 페이스트 빈 . 슬프게도 이것은 Perl과 충돌 Excessively long <> operator하지만 기술적 인 한계 일 뿐이므로 고려해서는 안됩니다.

휴, 그것은 꽤 여행이었다. 누군가가 일을 더 간단하게 만드는 5 문자 세트를 생각해내는 것이 정말 흥미로울 것입니다.

편집 : 약간 다른 접근 방식을 사용하면에 길이 제한을 피할 수 있습니다 <>. 다음을 사용하는 완전 기능적인 brainfuck 인터프리터 <>^es: 온라인으로 사용해보십시오! . <>^es트랜스 파일러에 대한 자동화 된 Perl : pastebin .


1
문자가 두 개의 그룹으로 나뉘어지기 때문에 인코딩은 2 차 폭발을 일으 킵니다. 하나는 짝수의 기본 문자를 xor 's로만 생성 할 수 있고 다른 하나는 홀수로만 생성 할 수 있습니다. 그들 사이를 바꿀 때마다 다른 glob를 추가하십시오. 프로그램을 더 짧은 평가 가능한 조각 ^또는 다른 기본 캐릭터로 묶을 수 있습니까?
Ørjan Johansen 2016 년

@ ØrjanJohansen Yep, 잘 알았습니다. 지금 해결책을 찾고 있습니다.
Grimy

축소 된 예제를 TIO 링크로 만들 수 있습니다 . 온라인으로 사용해보십시오!
Ørjan Johansen 2016 년

7
요청 :이 "약간 다른 접근법"을 설명하십시오
CalculatorFeline

32

파이썬 2, 7 자

exc="%\n

모든 Python 2 프로그램은이 7자를 사용하여 인코딩 할 수 있습니다 ( \n줄 바꿈).

임의의 문자열 생성

대체 %문자열을 단일 문자열에 반복적으로 적용하여 연결을 수행 할 수 있습니다 . 예를 들어, 경우 a=1, b=2, c=3, "%d%%d%%%%d" % a % b % c우리에게 문자열을 줄 것이다 "123". 다행히의 편지는 exec우리에게 액세스 권한을 부여 %x하고 %c기본적으로있는 hex()chr(). 을 사용 %c하면 문자를 나타내는 필요한 숫자가있는 한 모든 문자열을 구성 할 수 있습니다. 그런 다음 exec키워드를 사용하여이 문자열을 파이썬 코드로 실행할 수 있습니다 .

숫자 만들기

우리는 비교 ( )를 사용 하여 박쥐에 접근 0하고 1바로 얻을 수 있습니다 ==. 연결된 숫자와 모듈로의 조합을 통해 ASCII로 43표시 +되는 숫자를 구성 할 수 있습니다. 이를 통해 코드에 필요한 숫자를 구성 할 수 있습니다.

함께 모으기

이 설명에서 몇 가지 세부 사항은 생략했습니다. 이러한 제약 조건 하의 프로그램을 작성하는 방법을 이해하는 데 필수적인 것은 아닙니다. 아래는 필자가 작성한 파이썬 2 프로그램으로 모든 파이썬 프로그램을 기능적으로 동등한 버전으로 변환하여 7 자만 사용합니다. 사용 된 기술에 의해 영감 K에 의해 무정부 골프에 제출. 생성 된 프로그램의 크기를 적절한 한계 내로 유지하기 위해 몇 가지 간단한 트릭도 사용됩니다.

import sys

var = {
    43: 'e',
    'prog': 'x', # the program will be stored in this variable
    'template': 'c',
    0: 'ee',
    1: 'ex',
    2: 'ec',
    4: 'xe',
    8: 'xx',
    16: 'xc',
    32: 'ce',
    64: 'cc',
    'data': 'cx', # source program will be encoded here
}

unpacker = 'exec"".join(chr(eval(c))for c in {}.split())'.format(var['data'])

source = sys.stdin.read()
charset = sorted(list(set(source+unpacker)))
codepoints = map(ord, charset)

output = (
    # create template for joining multiple characters
    '{}="%c%%c%%%%c%%%%%%%%c"\n'.format(var['template']) +

    # create 1
    '{0}={1}=={1}\n'.format(var[1], var['template']) +

    # create 0
    '{}={}==""\n'.format(var[0], var['template']) +

    # create 3
    # store it at var[43] temporarily
    (
        'exec"{0}=%x%%x"%{2}%{2}\n' +
        'exec"{0}%%%%%%%%=%x%%x%%%%x"%{1}%{2}%{1}\n'
    ).format(var[43], var[0], var[1]) +

    # create 4
    # this step overwrites the value stored at var[0]
    (
        'exec"{1}=%x%%x"%{0}%{1}\n' +
        'exec"{1}%%%%=%x%%x"%{2}%{0}\n'
    ).format(var[43], var[0], var[1]) +

    # create 43
    'exec"{0}=%x%%x"%{1}%{0}\n'.format(var[43], var[0])
)

# create powers of 2
for i in [2, 4, 8, 16, 32, 64]:
    output += 'exec"{0}={1}%c{1}"%{2}\n'.format(var[i], var[i/2], var[43])

for i, c in enumerate(codepoints):
    # skip if already aliased
    if c in var:
        continue

    # generate a new name for this variable
    var_name = ''
    if i < 27:
        for _ in range(3):
            var_name += 'exc'[i%3]
            i /= 3
    else:
        i -= 27
        for _ in range(4):
            var_name += 'exc'[i%3]
            i /= 3
    var[c] = var_name

    # decompose code point into powers of two
    rem = c
    pows = []
    while rem:
        pows.append(rem&-rem)
        rem -= rem&-rem

    # define this variable
    front = 'exec"{}={}'.format(var[c], var[pows.pop()])
    back = '"'
    for i, p in enumerate(pows):
        front += '%'*(2**i) + 'c' + var[p]
        back += '%' + var[43]
    output += front + back + '\n'

# initialise the unpacker
output += 'exec"""{}=""\n"""\n'.format(var['prog'])
i = 0
length = len(unpacker)
while i < length:
    if (length-i) % 4 == 0:
        # concat 4 characters at a time
        w, x, y, z = [var[ord(unpacker[i+j])] for j in range(4)]
        output += 'exec"{}%c={}%%{}%%{}%%{}%%{}"%{}\n'.format(var['prog'], 
                    var['template'], w, x, y, z, var[43])
        i += 4
    else:
        output += 'exec"""{}%c="%%c"%%{}"""%{}\n'.format(var['prog'],
                    var[ord(unpacker[i])], var[43])
        i += 1

# encode source data
output += var['data'] + '="""'
output += '\n'.join(var[ord(c)] for c in source)
output += '"""\n'

# execute the program
output += 'exec"exec%c{}"%{}'.format(var['prog'], var[32])

print output

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


입력 프로그램이 이미 필요한 문자 세트로 제한되어 있는지 확인하기 위해 검사를 추가 할 수 있으며, 그렇다면 고양이 만 가능합니다.
mbomb007

26

Mathematica, 5 4 자

I[]

개인용 유니 코드 문자로 , Function명명 된 인수를 사용하여 명명되지 않은 함수의 리터럴을 작성할 수 있는 연산자 역할을합니다 . 캐릭터는 Mathematica에서 와 비슷하게 보이 므로 명확성을 위해이 답변의 나머지 부분에 해당 문자를 사용할 것 입니다.

이러한 사용하여, 우리는을 구현할 수 있습니다 S, K그리고 I콤비 조합 적 논리 :

I -> II↦II
K -> II↦III↦II
S -> II↦III↦IIII↦II[IIII][III[IIII]]

이것들에 대한 하나의 구문 문제는 우선 순위가 매우 낮아서 이러한 결합 자에 인수를 전달하려고 할 때 문제가 될 것입니다. 일반적으로 C와 같은 괄호 로 결합자를 래핑하여 문제를 해결 (C)하지만 괄호는 없습니다. 그러나, 우리는 사용할 수 있습니다 I[]포장 C우리는 그것을 나중에 사용할 수 있습니다 충분히 높은 우선 순위가 다른 마법 :

I[C][[I[[]]I]]

마지막으로, 응용 프로그램 작성 A x y z( A위 그림과 같이 "괄호에"연결자입니다, 그리고 x, y, z또는 괄호에되지 않을 수도 있고, 더 큰 표현 될 수있다), 우리는 쓸 수 있습니다 :

A[x][y][z]

그것은 괄호와 동등한 것이 실제로 어떻게 작동하는지에 대한 질문을 남깁니다. 나는 그것을 생각해 낸 순서대로 대략적으로 설명하려고 노력할 것입니다.

따라서 구문 적으로 그룹화하는 것은 대괄호 []입니다. 괄호는 Mathematica에서 두 가지 방식으로 나타납니다. 함수 호출 f[x]또는 인덱싱 연산자 f[[i]](실제로는 속기 Part[f, i])입니다. 특히 이는 유효한 구문 도 [C]아니고 그 의미도 아닙니다 [[C]]. 우리는 그 앞에 무언가가 필요합니다. 그것은 이론적으로 무엇이든 될 수 있습니다. 우리 I가 이미 사용하고 있다면 I[C]예를 들어 얻을 수 있습니다 . I단항 함수가 아니기 때문에 (평가되지 않음) 평가되지 않은 상태로 남아 있습니다 .

그러나 이제 C다시 추출 할 방법이 필요 합니다. 그렇지 않으면 인수 x를 전달하려고 할 때 실제로 평가되지 않기 때문 입니다.

여기서는 목록뿐만 아니라 f[[i]]임의의 표현식에 사용할 수있는 편리한 위치입니다 f. 그 f자체가 형태 라고 가정하면 head[val1,...,valn], f[[0]]주고 head, f[[1]]주고 val1, f[[-1]]주고받는 valn것입니다. 그래서 우리는 중 하나를 얻을 필요가 1또는 -1을 추출 C하거나 때문에, 다시 I[C][[1]]또는 I[C][[-1]]평가 C.

우리 는와 같은 임의의 정의되지 않은 기호에서 얻을 있지만 그렇게하려면 나누기 위해 다른 문자가 필요합니다 ( undefined 제공 ). 곱셈은 우리가 어떤 추가 문자 (원칙적으로)없이 수행 할 수있는 유일한 산술 연산, 그래서 우리가 제공하는 최대 곱한 수있는 몇 가지 값이 필요 이상 . 이것이 내가 식별자를 위해 특별히 선택한 이유 입니다. 그 자체로 가상 단위에 대한 Mathematica의 내장 기호 이기 때문 입니다.1xx/x1x-11II

그러나 그것은 하나의 마지막 문제를 남깁니다 : 우리는 실제로 어떻게 I스스로를 곱 합니까? 우리는 단지 II하나의 기호로 해석되기 때문에 쓸 수 없습니다 . a) 값을 변경하지 않고 b) 새로운 문자를 사용하지 않고 이러한 토큰을 분리해야합니다.

마술의 마지막 비트는 문서화되지 않은 행동의 일부입니다 : f[[]](또는 동등하게 Part[f]) 유효한 구문이며 f자체를 반환 합니다. 그래서 그 대신 곱으로 I하여 I, 우리는 곱 I[[]]에 의해 I. 대괄호를 삽입하면 Mathematica는 이후에 새 토큰을 찾고 필요 I[[]]I-1따라 평가 합니다. 그리고 그것이 우리가 끝나는 방법입니다 I[C][[I[[]]I]].

우리는 사용할 수 없었습니다 I[]. 이것은 함수의 인수없는 호출 I이지만 이전 I에 말한 것처럼 함수가 아니므로 평가되지 않은 상태로 유지됩니다.


훌륭한 답변입니다.
패트릭 스티븐스

23

파이썬 2, 8 자

exc'%~-0

이 문자들은 형식 ​​문자열과를 사용하여 모든 파이썬 프로그램의 번역 / 실행을 허용합니다 exec. Turing-completeness를 위해 프로그램을 번역 할 필요는 없지만 TC를 만드는 가장 적은 문자입니다. 너무 강력하다는 것은 보너스 일뿐입니다.

큰 따옴표와 0 이외의 한 자리 수도 사용할 수 있습니다. (지금은 그것에 대해 생각, 1당신이 사용할 수 있기 때문에 확실히, 짧은 프로그램의 결과로, 더 나은 것 1, 11그리고 111뿐만 아니라.)

프로그램은 다음과 같습니다 print.

exec'%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c'%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0%-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~0

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

기본 프로그램에는

exec''

x프로그램에 추가 된 각 문자 에는 (char-count)가 필요합니다.

  • % - 2**(n-1)
  • c - 1
  • - - ord(x)*2
  • ~ - ord(x)*2
  • 0 - 1

이에 대한 예외는 인코딩 대신 프로그램을 더 짧게 만들기 위해 특정 최적화 / 바로 가기를 수행 할 수 있다는 것입니다 (예 : 48 대신 %'0'문자 0사용 -~등).

실용 (AKA golfing) : 추가 핸디캡 캐릭터를 사용하지 않고이 과제 를 해결하기 위해이 전술을 사용했습니다.

캐릭터리스트와 엔코더 프로그램에 대한 크레딧 : here

결과 프로그램 크기에 대한 하한값을 찾는 방법에 대한 정보는 이 주석을 참조하십시오 .

필요한 바이트 수가 증가 O(2**n)하므로이 방법은 골프에 권장되지 않습니다. 이 소스 제한을 사용하는 quine은 엄청나게 길다.


연산자 우선 순위 만 +또는 -앞에 실행 %되는 경우 문자를 제거 할 수 있습니다.
mbomb007

Turing-completeness를 위해 모든 Python 프로그램을 축소 된 문자 세트로 번역 할 수는 없다는 점에 주목할 가치가 있습니다. exec어쨌든 사용하지 않고 필요한 양의 제어 흐름을 얻는 것이 어려울 것이라고 생각 합니다.
Martin Ender

이것은 실제로 기술적으로는 터닝 컴플리트 언어가 아닙니다. 내장 된 파이썬 인터프리터 인 터닝 컴플리트 언어를 위해 인터프리터를 호출 할 수 있습니다. 예를 들어, 다른 통역사에게 쉘 명령을 호출 할 수있는 기능이라면 터닝 완료 여부에 관계없이 모든 언어로 작동합니다.
mmachenry

@mmachenry 파이썬은 자체 컴파일러와 인터프리터를 사용 하고 있습니다 . 다른 별도의 언어를 사용하지 않습니다. 그리고 brainfuck 인터프리터는 Python으로 만들어 졌으므로 Turing Complete입니다. 그 지식을 사용하면, 당신의 주장은 거짓입니다.
mbomb007

@ mbomb007 내 주장은 거짓이 아닙니다. 파이썬은 터닝 컴플리트 언어입니다. 계산은 내부 호출에 원하는 문자를 사용하여 Python에서 Python 인터프리터를 호출하여 수행됩니다. 프로그램을 지정하는 언어는 프로그래밍 언어가 아니라 인코딩 일뿐입니다. 이를 사용하면 문자 0과 1을 사용하고 소스 파일을 이진 파일로보고 문자 그대로 모든 프로그래밍 언어 Turing Complete를 만드는 것이 쉽지 않습니다. 문제의 핵심은 실제 언어의 구문 적 부분 집합을 찾는 것입니다.
mmachenry

23

C (포팅 불가), 24 18 13 자

aimn[]={};,1+

여기에는 양식의 모든 프로그램이 포함됩니다

main[]={<sequence of constants>};

... 상수의 순서 (1 + 1 + 1 ... 형식)는 프로그램의 기계어 코드 표현을 포함합니다. 이것은 환경에서 모든 메모리 세그먼트가 실행될 수 있다고 가정합니다 (tcc [감사합니다! @Dennis!] 및 NX 비트가없는 일부 시스템의 경우). 그렇지 않으면 Linux 및 OSX의 경우 키워드를 앞에 추가해야 const하고 Windows의 #pragma경우 세그먼트를 실행 가능으로 명시 적으로 표시 해야 할 수 있습니다 .

예를 들어, 위의 스타일로 작성된 다음 프로그램 Hello, World!은 x86 및 x86_64의 Linux 및 OSX에서 인쇄 됩니다.

main[]={111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+11111+11111+11111+11111+11111+11111+11111+11111+111+11+11+11+11+11+11+1+1,1111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+11111+11111+11111+11111+11111+11111+1111+1111+1111+111+111+111+111+111+111,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+111111+111111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+11+11+1+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+111+111+111+111+111+11+11+11+11+11+11+1+1+1+1+1+1,111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+111+11+11+11+11+11+11+11+1,1111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+1+1+1+1+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+11+11+1+1+1+1+1,1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+1111+1111+1111+1111+1111+111+11+1+1+1+1+1,1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+1+1+1+1+1+1+1,1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+11+11+11+1+1+1,1111111111+111111111+111111111+111111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+111111+111111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+1+1+1+1+1+1,111111+111111+11111+11111+11111+11111+11111+11111+11111+1111+1111+1111+1111+1111+1111+1111+1111+111+111+111+11+11+11+11+11+11+11+11+11+11,11111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+111+111+111+11+11+11+11+11+11+11+1+1+1,111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+111+111+11+11+11+1,111111111+111111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+11111+11111+1111+1111+111+11+11+1+1+1+1+1,11111+11111+11111+11111+1111+1111+1111+1111+111+111+111+111+111+111+111+111+111+11+11+11+1+1+1+1+1};

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


2
@ GB : 0은 적어도 x86 머신 코드 (끔찍한 명령은 아님)에서 사용하지 않는 것이 매우 쉽습니다. 특히 문제는 4 바이트가 0 인 행에서만 발생하기 때문입니다.

2
@GB 32 비트 정수를 가진 머신에서0==1111111111+1111111111+1111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+111111111+11111111+11111111+11111111+11111111+11111111+11111111+1111111+1111111+1111111+1111111+1111111+111111+111111+111111+111111+11111+11111+11111+11111+11111+11111+11111+111+111+111+111+111+11+11+11+11+11+11+11+1
ceilingcat

3
tcc는 없이도 도망 갈 수 있습니다 const. tio.run/nexus/…
Dennis

8
@GB 나는 방금 0의 짧은 표현을 깨달았습니다.1==11
ceilingcat

3
@ wizzwizz4, 어떤 경우에도 순수한 C는 아니며 튜링을 완벽하게 만드는 의미는 아닙니다. C 의미가 없습니다. 어쨌든 컴파일러와 실행 환경 세부 정보를 사용하여 실행 가능한 것을 얻으려면 임의로 이름이 지정된 진입 점을 허용 할 수도 있습니다.
John Bollinger

20

레티 나 , 6 자

$%`{¶

줄 바꿈뿐만 아니라 (0x0A).

한편으로 나는이 낮은 얻을 수 놀랐습니다. 반면에을 포함하는 것에 대해 매우 불만족합니다 . 각각 $`{두 개 또는 심지어 세 가지 목적을 위해 재사용되지만 함께 단 하나의 목적을 제공합니다. 그것은 오히려 낭비로 보이고 접근의 우아함을 약간 파괴합니다. 이 구조를 이길 방법이 있기를 바랍니다.

증거에. 위의 문자를 사용하여 순환 태그 시스템 을 Retina 로 변환하는 간단한 방법을 설명하겠습니다 .

첫째로, 우리는 사용하고있을거야 `하고 {대신 바이너리 알파벳을 위해 01. 그것들은 정규 표현식에서 벗어날 필요가 없기 때문에 편리하지만 Retina 또는 대체 구문에서 의미가 있습니다. `for 0{for를 사용 하고 1있지만이 선택은 임의적입니다. 마지막 문자로 작업하는 우리가 사용할 수 있기 때문에 또한, 우리는 메모리에 문자열 (및 제작) 역 겁니다 $$`대신 ^$'문자 재사용을 극대화.

초기 단어로 표시하는 경우 Si일 (반전) 생산이 호출 , 그 결과 프로그램은 다음과 같이 표시됩니다pi


S
{`

{$
¶p1$%``
``$

{$
¶p2$%``
``$

{$
¶p3$%``
``$

...

이 구성은 생산이 적용될 때마다 필연적으로 메모리가 커지고 종료 될 가능성이 거의 없습니다. 실제로 순환 태그 시스템이 종료되는 시점 (작업 스트링이 비어있을 때)에서 결과 Retina 프로그램의 동작은 기본적으로 정의되지 않았습니다.

프로그램이 무엇을하는지 보자 :


S

작업 문자열을 초기 단어로 초기화하여 시작합니다.

{`

이것은 결과 문자열을 변경하지 못할 때까지 실행되는 프로그램의 나머지 부분을 래핑합니다 (이봐, 순진한 내장 무한 루프 감지 무료 ...). 두 개의 줄 바꿈이 실제로 필요하지는 않지만 개별 프로덕션과 루프를 더 명확하게 분리합니다. 나머지 프로그램은 각각의 제작 과정을 거치며, 루프로 인해 주기적으로 반복해서 효과적으로 처리하고 있습니다.

각 생산은 두 단계로 처리됩니다. 먼저 선행 (또는 우리의 경우 후행) 기호가 인 경우를 다루며,이 경우 {프로덕션을 사용합니다.

{$
¶pi$%``

정규식은 문자열이로 끝나는 경우에만 일치합니다 {. 이 경우 다음과 같이 교체하십시오.

  • 줄 바꿈 ( ). 우리는 항상 작업 문자열의 마지막 줄로 작업 할 것이므로 지금까지 작업 문자열을 효과적으로 버립니다 (그래서 프로그램의 메모리 사용량이 증가하고 증가합니다).
  • 현재 프로덕션 ( )은 작업 문자열 앞에 추가됩니다 (순환 태그 시스템이 추가하는 위치).pi
  • 이전의 나머지 작업 문자열 ( $%`) 이것이 우리가 : 를 삽입 해야하는 이유 $%`입니다. 따라서 이전 프로덕션에서 남긴 모든 정크를 볼 수는 없습니다. 이 트릭은 우리가에서 뭔가를 일치시킬 수 상기 뭔가를 삽입하는 작업 문자열의 시작 같은 것을 사용하지 않고, 작업 문자열을 (.+)하고 $1크게 우리가 필요로하는 문자의 수를 날려 버릴 것이다.
  • 단일 백틱 ( `) 이 효과적으로 대체 {( 1우리가 일치 -symbol)를 `( 0다음 단계는 우리가 이미 현재의 생산 처리 여부 알 필요하지 않도록 -symbol).

각 생산의 두 번째 부분은 생산을 건너 뛴 사소한 경우입니다.

``$

우리는 단순히 후행을 삭제합니다 `. `첫 번째 줄에 두 개가 필요한 이유는 Retina가 첫 번째 백틱을 구성과 정규식의 구분자로 간주하기 때문입니다. 이것은 단순히 빈 구성을 제공하므로 정규 표현식 자체에서 백틱을 사용할 수 있습니다.


20

자바 7, 18 17 자

\bcdefu0123456789

모든 Java 소스 코드를 유니 코드 코드 포인트로 줄일 수 있습니다. "a"는에만 사용되므로 필요하지 않습니다 *:jJzZ. 별표는 곱셈 또는 블록 주석에 사용됩니다. 곱셈은 ​​반복 된 덧셈이므로 한 줄 주석을 대신 사용하거나 생략 할 수 있습니다. 콜론은 삼항 연산자에 사용되며 대신 if 문을 사용할 수 있으며 foreach 루프는 일반 for 루프로 대체 될 수 있습니다. j와 z는 자바 키워드의 일부가 아닙니다.

다른 문자를 제거하려면 Java 보일러 플레이트에 필요한 문자 중 하나 이상을 추가해야합니다 class a{public static void main(String[]a){}}. 아래를보십시오 :

1 -> a (which has already been removed)
2 -> r (required for "String")
3 -> S (required for "String")
4 -> t (required for "static")
5 -> S (required for "String")
6 -> v (required for "void")
7 -> g (required for "String")
8 -> ( (required for "main(String[]a)"
9 -> i (required for "static")
b -> { (required for "class a{")
c -> l (required for "class")
d -> } (required for "(String[]a){}}")
e -> n (required for "main")
f -> o (required for "void")

다음은 Hello World 프로그램의 예입니다. 온라인으로 사용해보십시오!

Java 8, 16 자

\bdefu0123456789

이것을 지적 해준 ais523에게 감사합니다. Java 8은 인터페이스에 정적 메소드를 허용하므로 "class"의 "l"에 필요하지 않으므로 "c"를 삭제할 수 있습니다. "c"는 ,<lL\|우리가 "a"를 제거했을 때보 다 자바 기능을 조금 더 잃어 버리게되지만 여전히 완전한 튜링을하기에 충분합니다. 온라인으로 사용해보십시오!


3
분명히, 16 진수 중 어느 것이 생략 될 수 있는지 알아내는 것이 Java로 이것을 해결하는 흥미로운 부분입니까? :)
Martin Ender

@MartinEnder 절대적으로. 시간이 좀 오면이 작업을 더 많이 할 계획입니다.
Poke

6
그리고 무언가를 쓸 준비가되어있는 나 Java, 127 characters... Nice one, Poke;)
Olivier Grégoire

내 대답에 필요한 문자를 기준으로 다른 16 진수를 제거 할 수 있다고 생각하지 않습니다.

3
Java 8로 전환하면 16에서 수행 할 수 있습니다. Java 8을 사용하면 인터페이스에 정적 메소드를 사용할 수 있으므로 삭제할 수 있습니다 c(모든 문자는 16 진수 리터럴이 없거나 interface액세스 할 수 없음 ). ac

19

미로 , 5 자

~{}

또한 줄 바꿈 (0x0A) 및 공백 (0x20).

Smallfuck (1 비트 셀을 사용하는 축소 된 Brainfuck- 변형)의 축소 형식으로 증명을 스케치 하겠습니다 . 언어가 테이프가 유한해야한다고 지정하기 때문에 Smallfuck 자체는 Turing-complete가 아닙니다. 그러나 우리는 무한 테이프를 가진 Smallfuck의 변형을 가정 할 것입니다. 의도적으로 제한).

이 축소 과정에서 중요한 불변은 모든 프로그램 (또는 서브 프로그램)이 동일한 행에서 시작하고 끝나는 미로 프로그램 (또는 서브 프로그램)을 초래하고 짝수의 열에 걸쳐 있다는 것입니다.

미로에는 두 개의 스택이 있으며 처음에는 무한의 (암시 적) 양으로 채워집니다 0. {그리고 }이러한 스택의 꼭대기 값이 이동. 메인 스택의 상단을 현재 "셀"로 간주하면이 두 스택은 Smallfuck에서 사용하는 무한 테이프의 반 무한 절반으로 볼 수 있습니다. 그러나 위에서 언급 한 불변성을 보장하기 위해 스택에 각 테이프 값의 사본 두 개를 두는 것이 더 편리합니다. 따라서 <>로 변환됩니다 {{}}(만약 당신이 좋아하면 당신이 그들을 바꿀 수) 각각.

대신 셀 값을 허용 0하고 1, 우리가 사용하고 0그리고 -1우리가 사이를 전환 할 수있는 ~(비트 부정). 정확한 값은 Turing-completeness의 목적에 중요하지 않습니다. 스택에서 값의 사본을 모두 변경해야하므로 길이가 균등하게 변환 *됩니다 ~}~{.

제어 흐름 명령이 남습니다 []. Labyrinth에는 명시적인 제어 흐름이 없지만 대신 제어 흐름은 코드의 레이아웃에 의해 결정됩니다. 레이아웃을 수행하려면 공백과 줄 바꿈이 필요합니다.

첫째, ~~두 사람이 ~효과적으로 취소하기 때문에 그것은 no-op 입니다. 이 길이를 사용하면 코드에 임의로 긴 경로를 만들 수 있습니다. 이제 다음 구성을 사용하여 AA[BB]CCLabyrinth 로 번역 할 수 있습니다 (불확실성이 보장하는대로 Labyrinth의 각 스 니펫 크기가 고르도록 이중 문자를 사용하고 있습니다).

      ~~~~
      ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

여기에 ..적절한 수는 ~의 너비와 일치합니다 BB.

다시 말하지만, 구조물의 너비는 일정하게 유지됩니다.

이제이 루프의 작동 방식을 살펴볼 수 있습니다. 코드는을 통해 입력됩니다 AA. 첫 번째 ~~는 아무것도하지 않고 접합점에 도달하게합니다. 이것은 대략 다음에 해당합니다 [.

  • 현재 셀 값이 0이면 IP가 계속 직진하므로 결국 건너 뜁니다 BB. ..부분은 여전히 어떤 조합입니다. 그런 다음 ~다른 교차점에서 싱글 에 도달합니다 . 우리는 지금 알고있는 현재의 값이 0임을, 그래서 IP는 회전 북쪽을한다. 그것은 6 이후에 다른 접합점에 도달 할 때까지 상단의 굽힘 주위를 돌고 ~있습니다. 이 시점에서 현재 값은 여전히 0이 아니며 IP는 방향을 향해 동쪽으로 다시 돌아갑니다 CC. 루프를 건너 뛰었을 때와 같이 현재 값을 3 ~으로 CC되돌리려 면 3 을 반환하십시오 0.
  • 루프 시작 부분의 현재 셀 값이 0이 아닌 경우 IP는 남쪽으로 회전합니다. ~도달하기 전에 6 번 더 실행하고 BB(아무것도하지 않음) ~다음 교차점에 도달 하기 전에 6 번 더 실행 합니다. 이것은 대략 ].
    • 현재 셀이 0이면 IP가 북쪽으로 계속 이동합니다. 다음 ~은 값이 0이 아니므로 IP가이 두 번째 정션을 사용하여 루프를 완전히 건너 뛴 경우와 경로를 병합합니다. 다시, 3 ~은에 도달하기 전에 값을 0으로 반환합니다 CC.
    • 현재 셀이 0이 아닌 경우 IP는 서쪽을 향합니다. 거기 ~는 IP 서쪽으로 계속 갈 수 있도록이 시점에서 현재의 값이 0임을 의미 다음 접합하기 전에. 그런 다음 ~IP가 초기 정션에 다시 도달하기 전에 홀수 가 발생하므로 값이 리턴 -1되고 IP가 남쪽으로 다음 반복으로 이동합니다.

프로그램에 루프가 포함되어 있으면 AAIP가 시작될 올바른 셀을 찾을 수 있도록 첫 번째 를 프로그램 맨 위로 확장해야합니다.

~     ~~~~
~     ~  ~~~
AA~~..~~~~ ~CC
   ~     ~
   ~     ~
   ~     ~
   ~~~BB~~

그게 그거야. 이 축소로 인한 프로그램은 종료되지 않지만 Turing-completeness (규칙 101 또는 Fractran 고려)의 일부는 아닙니다.

마지막으로 이것이 최적인지 여부에 대한 질문이 남았습니다. 작업 부하 문자 측면에서 세 가지 명령보다 나은 작업을 수행 할 수 있는지 의심됩니다. 두 개의 레지스터가있는 Minsky 기계를 기반으로 한 대체 구성을 볼 수 있지만 스택 조작 명령 하나와 두 개의 산술 명령이있는 =()or 가 필요 =-~합니다. 나는 이것에 대해 틀리게 증명되어 기쁘다. :)

레이아웃 명령의 경우 한 줄에서 유용한 제어 흐름이 불가능하기 때문에 줄 바꿈이 필요하다고 생각합니다. 그러나 공백은 기술적으로 필요하지 않습니다. 이론적으로 전체 그리드를 ~{}(또는 =()또는 =-~) 로 채우 거나 선이 모두 같은 길이가 아닌 비정형 레이아웃을 사용하는 구조를 만들 수 있습니다. 그러나 Labyrinth는 모든 단일 셀을 접합으로 처리하므로 원하지 않는 경우 코드가 분기되지 않도록 조심해야하기 때문에 이와 같은 코드를 작성하는 것은 매우 어렵습니다. 공간을 생략하는 것이 Turing-completeness 가능 여부를 입증하거나 반증 할 수 있다면, 나는 그에 대한 상당한 현상금을 기꺼이 줄 것입니다. :)


19

하스켈, 5 7 자

()\->=;

기능 언어로서 Haskell은 물론 람다를 가지고 있으므로 람다 미적분을 시뮬레이션하는 것은 쉽습니다. 람다 구문 은 최소한 문자가 필요합니다 . 또한 임의의 람다 식을 만들려면 무제한의 가변 기호가 필요합니다. 다행히 우리는 때문에, 이것에 대한 어떤 새로운 캐릭터를 필요로하지 않는 , , , ..., 모든 유효한 변수 이름입니다. 실제로 내부 괄호 의 모든 조합은 유효한 변수 이름 이며 , 람다 식용으로 예약 된 and 및 행 주석을 시작하는을 제외하고는 유효한 변수 이름 입니다.(\variable->body)argument()\->
(>)(>>)(>>>)\->\->--

예 :

  • S = (\(>)(\\)(-)->(>)(-)((\\)(-)))유형(t2 -> t -> t1) -> (t2 -> t) -> t2 -> t1
  • K = (\(>)(-)->(>))유형t -> t1 -> t
  • I = (\(>)->(>))유형t -> t

편집 : 그러나 ais523 이 주석에서 지적 했듯이이 구성은 유형지정된 람다 미적분을 구현 합니다.이 루프 자체는 무한 루프를 입력 할 수 없기 때문에 Turing-complete가 아닙니다. 이 문제를 해결하려면 재귀를 수행하는 함수가 필요합니다. 지금까지 이름이없는 람다를 사용했는데, 이름이 없기 때문에 스스로 호출 할 수 없습니다. 그래서 우리는 문자를 추가해야 =하고 ;구현하는 fix기능을 :

(>)=(\(-)->(-)((>)(-)));   -- equivalent to: f =(\ x -> x ( f  x ));

이 선언으로 우리의 람다 계산법은 튜링 완전한 그러나 추가 한하게 =하고 ;당신이 볼 수 있듯이 우리는 더 이상 람다 필요하지 않습니다, nimi의 대답 만 사용합니다 ()=;.


컴파일 타임에 기술적으로 제거되지 main않습니까?
PyRulez

4
간단하게 입력 된 SKI 결합기 미적분은 Turing-complete가 아닙니다. 이를 위해서는 형식화되지 않은 람다 미적분학이 필요합니다. 불행히도 시연에서 언급했듯이 Haskell은 기본적으로 코드에 형식화 된 해석을 제공합니다.

@PyRulez 기본 규칙에 따라 함수를 사용할 수 있다고 가정했습니다.
Laikoni

@ ais523 SKI 결합기는 주어진 예를 사용하여 임의의 람다 용어 (예 : 교회 숫자 및 함수)를 작성할 수 있습니다.
Laikoni

@ ais523 타이핑 된 Lambda 미적분학은 몇 개의 조합기를 완성해야합니까? y 컴비 네이터 만 있으면된다고 생각합니다.
PyRulez

18

CJam, 3 자

)Martin Ender의 제안에 따라 제거

'(~

예제와 같이 파이썬과 비슷합니다.

사용 '~하면 ~캐릭터를 얻을 수 있습니다 . 그런 다음을 사용하여 (원하는 문자를 얻기 위해 값을 줄일 수 있습니다 ( ~마지막으로 인쇄 가능한 ASCII 문자 임). ~모든 문자열을 일반 CJam 코드로 회피합니다. 문자열은 문자를 가져와 [(감소를 통해 ~) 평가하고, 다른 문자 시퀀스를 넣은 다음 문자를 평가하여 만들 수 ]있습니다. 이를 통해이 세 문자 만 사용하여 CJam 프로그램을 빌드하고 실행할 수 있습니다.

2 + 2 만 사용하여 계산 '(~


또 다른 도전을 위해 누군가 cjam 프로그램을 가져 와서 자동 으로이 하위 집합으로 컴파일하는 프로그램을 만들었습니다. 내가 찾을 수 있으면 좋겠다
Zwei

1
저는 2 + 2 프로그램을 크게 줄 '~((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((~'~(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((~
Zwei

@Zwei 위대합니다, 여러분의 이름에 맞습니다
Chromium

18

Brain-Flak , 6 자

(){}[]

Brain-Flak은 8 개의 문자 만 사용할 수있는 미니멀리즘 언어입니다. 그러나 6 자만 사용하여 튜링이 완료된 Brain-Flak 하위 세트가 있음을 증명할 수 있습니다.

가장 먼저 할 일은 하나의 Brain-Flak 스택으로 Minsky Machine을 구현하는 것입니다. 하나의 스택만으로 Minsky Machine이 가능하다는 것을 증명할 수 있다면 Brain-Flak이 튜링없이 <>[]닐 라드 없이 완료되었음을 알 수 있습니다. 이것은 문자를 즉시 ​​저장하지는 않지만 나중에 <...>필요하지 않다는 것을 보여줄 때 나타납니다 .

Minsky Machine은 한정된 수의 무제한 레지스터와 두 개의 인스 트루먼 테이션이있는 Turing 완전한 오토 마톤 유형입니다.

  • 레지스터 증가

  • 0이 아닌 감소로 그렇지 않으면 지정된 명령어로 전환

Brain-Flak에서 goto 구조를 설정하기 위해 다음 스 니펫을 사용할 수 있습니다.

(({}[()])[(())]()){(([({}{})]{}))}{}{(([({}{}(%s))]{}))}{}

카운터가 감소하고 %s0이면 실행 됩니다. 이 묶음들이 묶여 있으면 우리가 가고 싶은 줄을 나타내는 숫자를 스택에 넣을 수 있습니다. 이들 각각은 스택의 맨 위를 줄이지 만 실제로는 하나만 코드를 실행합니다.

우리는 이것을 모든 Minsky Machine 지침의 래퍼로 사용합니다.

스택을 전환하지 않고 특정 레지스터를 증가시키는 것은 매우 쉽습니다. 이 문자열 수식으로 얻을 수 있습니다.

"({}<"*n+"({}())"+">)"*n

예를 들어 3 번째 레지스터를 늘리려면 다음 코드를 작성하십시오.

({}<({}<({}<({}())>)>)>)

이제 두 번째 작업 만 구현하면됩니다. Brain-Flak에서 숫자가 0인지 확인하는 것은 매우 간단합니다.

(({})){(<{}%s>)}{}

%sTOS가 0 인 경우 에만 실행 됩니다. 따라서 우리는 두 번째 작업을 할 수 있습니다.

Minsky Machines는 튜링이 완료되었으므로 Brain-Flak은 <>및을 사용하지 않고도 튜링이 완료 []됩니다.

때문에 우리는 아직 문자의 수를 감소하지 않은 <...>[...]사용에 여전히. 이것은 간단한 대체로 해결할 수 있습니다. 이후는 <...>실제로 동일합니다 [(...)]{}모든 경우입니다. 따라서 Brain-Flak은 <and >문자 (및 모든 no-ops)를 사용하지 않고 완료됩니다 .


"때문에 <...>[...]여전히 사용합니다." 그러나를 제거하지 않았습니다 [...]. 수정하십시오.
CalculatorFeline

질문 : [...]정말로 필요합니까? 0을 누르면하는로 시작에서 할 수있는 ({})가장 큰 문제는에 액세스하지 않고 스택을 갈 수있게되고 (단, 0은 신중하게 단행되어야 할 것이다 그래서, 빈 스택에 의존) <...>(더 이상 시뮬레이션 될 수없는)
계산기

16

> <> , 3 자

> <>은 3을 사용하여 1p-수행 할 수 있습니다.

1          Push 1
p          Pop y, x, c and put the char c in cell (x, y) of the codebox
-          Subtraction: pop y, x and push x-y

p코드 상자에 문자를 배치하여 2D 소스 코드를 수정하는 리플렉션을 제공합니다. 을 사용하면 1을 빼고 ( )가 1을 더하기 1-때문에 숫자를 스택에 넣을 수 있습니다 .1-111-1--x-(1-1-1) = x+1

모든 1p-명령이 실행되면 명령 포인터가 줄 바꿈되어 "실제"코드를 실행할 수 있습니다.

피보나치 수를 계산하는 예제 프로그램 ( 이 답변에서 )은 다음과 같습니다.

111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--11-p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11-1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--11p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1--1p111-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1--111-1-1-1-1-1-1-1-1-1-1-1-1-1-1--1p

온라인으로 사용해보십시오! 모든 1p-명령이 실행되면 코드 상자는 다음과 같습니다.

01aa+v1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1- ...
@+&1->:?!;&:nao:

v첫 번째 줄 이후의 모든 것을 제외하고 , 이것은 표준 피보나치> <> 프로그램입니다.


13

bash, 9 자

01456\$ '

Bash에는 $'\nnn'8 진 ASCII 값으로 문자를 입력하기위한 구문 이 있습니다. eval이 형식으로 명령을 입력 할 수 있습니다 $'\145\166\141\154'. 먼저 원하는 결과를 8 진수 값으로 바꿉니다. 그런 다음 0, 1, 4, 5 및 6 이외의 숫자를 사용하여 8 진수 값을 사용 $(())하여 뺄셈을 사용하여 8 진수 값을 평가하는 식으로 변환 하고 앞에을 추가합니다 eval. 마지막 단계에서 다른 단계를 추가 eval하고 괄호와 빼기 부호를 8 진수 값으로 변환합니다. 이 방법을 사용하면 모든 bash 명령을 실행할 수 있으므로이 하위 집합이 완료됩니다.

예:

dc 된다

$'\144\143' 이것은

$'\145\166\141\154' \$\'\\144\\$((144-1))\' 이것은

$'\145\166\141\154' $'\145\166\141\154' $'\$\\\'\\\\144\\\\$\050\050144\0551\051\051\\\''


12

사건 , 2 자

어느 두 문자를 고르 든 상관 없습니다. 두 옥텟의 모든 조합은 인시던트에서 Turing-complete입니다.

실제로 이것을 증명 하는 것은 예상보다 훨씬 어렵고, 글을 쓸 당시 사건에 관한 Esolang토론 페이지 는 문제에 대한 것입니다. 그래도 아래에서 가장 간단한 알려진 증거를 요약하려고 노력할 것입니다.

증거 전에 배경. 인시던트는 소스를보고 프로그램에서 사용 된 토큰을 유추합니다 (토큰은 소스에서 정확히 3 번 나타나는 문자열이며 다른 토큰의 하위 문자열이 아니며 다른 잠재적 토큰과 겹치지 않는 문자열입니다). 따라서 토큰이 무엇인지를 변경하여 모든 프로그램을 거의 모든 문자 집합을 사용하도록 변환 할 수 있습니다. 언어는 Turing-complete (그리고 I / O에도 완벽 함)입니다. 프로그래밍하기가 매우 어렵지만 "all"은 토큰을 인코딩하여 두 문자로만 작동하는 방법입니다.

그리고 이제 증거의 요약이 있습니다 (Esolang의 상주 수학자 인 Ørjan이 발견했습니다). 아이디어는 우리 1가 다른 캐릭터의 큰 바다에서 (예를 들어 ) 한 문자의 두 복사본을 사용하여 토큰을 인코딩한다는 것 0입니다. 1s 사이의 거리는 각 토큰마다 다르지만 항상 4의 배수입니다. 그런 다음 토큰 사이의 패딩 을 위해 중간에 0a 1를 가진 s 의 추가 목록을 사용 하지만의 각 측면에서 0의 수 1없는 4의 배수가 아니라 다른 프로그램에서 나타나지 않는 프로그램의 특정 발생에 고유 한 번호입니다. 그것은 각각의 의미는 1...1패딩 내에서 두 번만 나타날 수 있으므로 토큰의 일부가 아닙니다. 각각의 의도 된 토큰은 정확히 두 개의 1을 포함하며, 가짜 토큰은 둘 이상을 포함 할 수 없습니다 1. 그런 다음 측면에 패딩을 추가하여 적어도 4 개의 사본을 추가하여 1 1또는 0을 포함하는 가능한 모든 토큰을 제거 1합니다.


11

망막 , 3 자

{`

그리고 개행.

우선, 우리는 대체를 할 수있는 줄 바꿈이 필요하다 (전체 프로그램을 하나의 정규 표현식에 맞추고 싶지 않으면 더 많은 문자가 필요하지 않다면 필요하다) 과 `{루프를 할 수있는 최소 문자 집약적 인 방법입니다. 우리는 다른 것이 필요하지 않습니다.

구현할 목표 언어는 Thue 의 결정 론적 변형입니다 (Turing-completeness에는 비결정론이 필요하지 않습니다. 어떤 평가 순서가 사용되는지에 상관없이 Thue 프로그램을 작성하여 올바르게 작동 할 수 있습니다). 기본적인 아이디어는 컴파일하는 것입니다 pattern::=replacement으로

`pattern
replacement

(이것은 Thue의 직접적인 Retina 번역입니다. 또는 Thue가 아닌 Retina를 알고 있다면 Thue의 작동 방식을 배우는 방법으로 사용할 수 있습니다); 예외적으로, 첫 번째 패턴이 {`대신됩니다 (전체 프로그램을 루프에 배치하기 위해 대체 프로그램이 더 이상 가능하지 않을 때까지 Thue 프로그램이 계속 실행되므로 Retina가 동일한 방식으로 작동합니다).

물론, 이것은 우리가 가진 Thue 튜링 완전한 증명해야한다는 것을 의미 {하고 `패턴 및 교체에 있지만,이 정도로 간단합니다; 우리는 아스키 코드로 문자 대체 N 으로 `, N + 1 {, 및 다른 `. 패턴이 문자 경계에서 어디에서나 일치하는 것은 불가능하므로 원래 프로그램과 동일한 작업을 수행하게됩니다.


1
"Thue 프로그램은 더 이상 대체가 불가능할 때까지 계속 실행되므로 Retina가 동일한 방식으로 작동합니다."전체 프로그램을 통과 한 문자열이 문자열을 변경하지 못하면 Retina가 조기에 종료된다는 점만 예외입니다. 따라서 간단한 무한 루프 감지 기능도 무료로 사용할 수 있습니다.
Martin Ender 2012

1
아 맞다. 물론 내부 상태를 변경하지 않는 무한 루프는 프로그램의 계산 클래스에 기여할 수 없기 때문에 튜링 완성도에는 영향을 미치지 않습니다.

10

Brachylog , 5 자

~×₁↰|

문자의 부분 집합은 우리의 버전을 구현할 수 있습니다 Fractran 나타날 수있는 숫자 만 repunits의 제품 (단지 숫자 1을 사용하여 진수로 기록 될 수있는 숫자 즉, 제품)되는합니다. (아래 첨자로 정수를 사용하여)는 현재 값을 해당 정수로 나눕니다. 그러나 정확히 나눈 경우에만 (그렇지 않으면 "실패"하고 다른 사례를 찾아서 사례를 |분리합니다). ×정수를 곱해 봅시다. 따라서 ~×₁|우리는 Fractran 실행의 한 단계를 구현할 수 있습니다. 그런 다음 새로운 현재 값으로 전체 프로그램을 다시 실행하면서 재귀를 봅시다. 다음은11111111111111111111111/111 Brachylog로 번역 된 매우 간단한 Fractran 프로그램 ( ) 의 예입니다 .

이 튜링이 완료 되었습니까? Fractran Turing을 완성시키는 데 필요한 모든 것은 충분히 많은 양의 소수입니다. 가 있습니다 다섯 입증 네 의심repunit은 아직 발견되지 않은 것들과 더불어 아마도 소수입니다. 실제로이 경우에 필요한 것 이상입니다. 이 프로그램은 왼쪽에서 오른쪽으로 가능성을 확인하므로 하나의 소수를 지시 포인터로 사용하고 두 개의 소수를 카운터로 사용하여 튜링의 완성도를 3 개의 소수로 표시 할 수 있습니다. , 및 23 자리 숫자는 입증되었지만 성가 시게 큰 숫자에 의존하지 않고 317 또는 1031 자리 숫자로 소스 코드를 작성하기 어렵게 만듭니다. 이를 통해 카운터가 2 개인 Minsky 기계를 구현할 수 있습니다 (Turing-completeness에 충분).

컴파일이 구체적으로 작동하는 방법은 다음과 같습니다. Minsky 머신 구현을 위해 다음 두 가지 명령을 사용하며 (Turing complete라고 함) 각 명령에는 레이블로 정수가 있습니다.

  • 레이블 L : 카운터 {A 또는 B}가 0이면 X로 이동하십시오. 그렇지 않으면 감소시키고 Y로 이동하십시오.
  • 레이블 L : 증분 카운터 {A 또는 B}, Z로 이동하십시오.

우리는 11의 거듭 제곱을 분모에 위치시키고, 가장 높은 힘을 먼저 두는 명령을 선택합니다. 11의 지수는 명령의 레이블입니다. 그런 식으로 일치하는 첫 번째 부분은 현재 실행중인 명령이 될 것입니다 (이전 명령은 11로 나눌 수 없기 때문입니다). 감소 명령의 경우 카운터 A 또는 B 각각에 대해 1111111111111111111 또는 11111111111111111111111의 인수를 분모에 배치하고 해당 인수가없는 다른 명령으로 후속 조치를 수행합니다. "감소"사례는 첫 번째 명령에 의해 구현되고 "0"사례는 두 번째 명령에 의해 구현됩니다. 한편, "goto"는 분자에서 11의 적절한 거듭 제곱으로, 분자에서 1111111111111111111 또는 11111111111111111111111의 계수를 통해 "증가"로 처리됩니다.


페어 와이즈 코 프라임 리 펀트를 사용할 수없는 특별한 이유가 있습니까?
CalculatorFeline

@CalculatorFeline : 아니요.하지만 필요하지 않은 구조를 이미 찾은 후에야 생각했습니다. 이 캐릭터 세트로 작성된 골프 프로그램에서 확실히 도움이 될 것입니다.

또한,> 1을 초과하는 모든 repunit는 pairwise coprime입니다 (생각)
CalculatorFeline

@CalculatorFeline : 아닙니다. 111과 111111은 모두 3으로 나눌 수 있습니다.

* 어떤 rerepunit도 다른 rerepunit을 나누지 않습니다
CalculatorFeline

10

Befunge-98, 3 자

내가 아는 한, Befunge-98은 완전히 완성 된 상태 여야하므로 3 개의 문자만으로 Befunge-98 프로그램을 생성 할 수있는 방법을 보여 주면됩니다. 내 초기 솔루션은 다음 네 문자에 의존했습니다.

01+p

명령 1과 함께 여러 값 을 추가하여 양의 정수를 스택에 가져올 수 있으며 +0의 경우 간단히을 사용 0합니다. 원하는 숫자를 입력 할 수있게되면 p(put) 명령을 사용하여 ASCII 값을 Befunge 재생 필드의 어느 위치 에나 쓸 수 있습니다.

그러나 Sp3000이 지적했듯이 실제로 세 문자만으로 얻을 수 있습니다.

1-p

음수는 시작한 1다음 반복적으로 빼서 계산할 수 있습니다 1(예 : -3은 11-1-1-1-). 그런 다음 1에서 1-n을 빼서 양수를 나타낼 수 있습니다. 여기서 1-n은 처리 방법을 이미 알고있는 음수입니다 (예 : 4 = 1-(-3), 111-1-1-1--).

따라서 세 문자를 사용하여 실행하려는 실제 코드를 천천히 생성하는 일종의 부트 로더를 작성할 수 있습니다. 이 로더가 실행을 마치면 플레이 필드의 첫 번째 줄의 시작 부분으로 감싸고 새로 생성 된 코드의 시작 부분을 잡아야합니다.

예를 들어, 2 + 2를 합산하고 결과를 출력하는 데 필요한 Befunge 코드를 생성하는 부트 로더는 다음과 같습니다. 22+.@

그리고 좀 더 복잡한 예를 들어, "Hello World"입니다. "!dlroW olleH"bk,@


이것은 폴리 글롯이며> <> 및 그 파생어에 동일한 문자를 사용할 수 있습니다. 잘 했어!
Sok

2
Befunge-98은 3 1p-
로도 가능

@ Sp3000 물론입니다! 나는 그것을 3 자로 줄일 수있는 방법이 있었을 것이라고 확신했다. 감사.
James Holderness 2012

9

루비, 8 자

eval"<1+

파이썬 답변에서 영감을 받음

작동 원리

  • eval은 임의의 문자열을 실행하는 데 사용할 수 있습니다.
  • "<1+는 문자열을 만드는 데 필요한 최소 문자 집합입니다.

빈 문자열을 시작점으로 사용하고 아스키 문자를 추가하여 루비의 문자열을 만들 수 있습니다. 예를 들면 다음과 같습니다.

eval ""<<111+1<<11+11+11+1<<111<<11+11+11+1

실제로는

eval ""<<112<<34<<111<<34

문자열을 평가하는

p"o"

8

OCaml, 9 자

fun->()`X

이 문자는 OCaml에서 SKI 조합기 미적분을 구현하기에 충분합니다. 특히 우리는 충분한 괄호가있는 공간 사용을 피할 수 있습니다. 불행히도 OCaml의 람다 식에는 fun키워드가 필요 하므로 더 간결한 솔루션은 불가능합니다. 그러나 더 복잡한 람다식이 필요한 경우 동일한 문자를 사용하여 임의의 변수 이름을 작성할 수 있습니다.

S 조합기 :

fun(f)(u)(n)->f(n)(u(n)) 유형으로 ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c

K 조합기 :

fun(f)(u)->u 유형으로 'a -> 'b -> 'b

나는 조합 자 :

fun(f)->f 유형으로 'a -> 'a

ais523에서 알 수 있듯이 SKI를 단순히 인코딩하는 것만으로는 충분하지 않습니다. 다음은 타입 시스템을 조작하기 위해 다형성 변형을 사용하는 Z 인코딩입니다. 이것으로 내 하위 세트가 완료됩니다.

Z 조합기 :

fun(f)->(fun(`X(x))->(x)(`X(x)))(`X(fun(`X(x))y->f(x(`X(x)))y))

유형으로 (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b


2
간단하게 입력 된 SKI 결합기 미적분은 Turing-complete가 아닙니다. 이를 위해서는 형식화되지 않은 람다 미적분학이 필요합니다. 불행히도 데모에서 언급했듯이 OCaml은 기본적으로 코드에 형식화 된 해석을 제공합니다.

1
그런 다음 y 조합기 (및 유사하게 z 조합기)를 인코딩 할 수있는 다형성 변형을 사용할 수 있도록 몇 가지 문자가 더 필요합니다.
Devin Lehmacher

Z 콤비 네이터 란 무엇입니까?
CalculatorFeline

@CalculatorFeline y- 콤비 네이터의 엄격한 변형입니다. OCaml은 게으르지 않기 때문에 OCaml에서 필요합니다. 다음은 위키 백과 페이지로 연결되는 링크입니다 : en.wikipedia.org/wiki/...은
데빈 Lehmacher

8

스택 기반 연결 언어, 4 자

언더로드

():^

GolfScript

{}.~

CJam

{}_~

GS2

  • backspace, tab,, @space (GS2가 인쇄 할 수없는 것을 많이 사용한다는 것을 알고 있었지만 이것은 말도 안됩니다 ...)

dc (@seshoumara에서 제안)

[]dx

Underload는 ():^(Esolang의 상주 수학자 Ørjan 덕분에) 사용만으로 Turing-complete로 입증되었습니다 . 증거는 여기에 설명하기에는 너무 길지만 관심이 있으시면 여기를 읽어보십시오 .

문제가되는 명령은 ()(스택에서 코드 배치 리터럴), :(상단 스택 요소 복제) 및 ^(상단 스택 평가)입니다. 이러한 명령은 스택 기반 언어 (특히 연결 언어)에서 상당히 흔하므로 위의 명령 모음을 제공했습니다. 이 언어는 모두 Underload와 같은 이유로 4 자로 튜링 완료됩니다.


스택 작업을 수행 할 수는 있지만 수학 계산을 수행하기 위해 스택을 채우기 위해 최소한 숫자가 필요하지 않습니까? 아니면 4 문자 중 하나를 사용하여 단항식으로 수행됩니까?
seshoumara 2012

1
@seshoumara : 이 방법을 사용할 때 숫자 (및 기타 모든 데이터 저장 장치)는 매우 간접적으로 구현 됩니다. 산술로 인식 할 수있는 무언가에 도달하기 전에 2 ~ 3 개, 심지어 4 개 정도의 추상화 수준이 있습니다. 이런 종류의 것은 이와 같은 매우 제한된 시스템의 Turing-completeness 증거에서 일반적입니다.

나는 dc 자체, 스택 기반 언어로 대답을 제출하려고 생각했지만 4보다 많은 문자를 포함하는 다른 방법을 사용하면 dc에는 연결 연산자가 없지만 언급 한 것과 동등한 연산자가 있습니다. [] d x. dc가 목록에 들어갈 수 있습니까?
seshoumara

@seshoumara : 예, 필요한 기능이 모두있는 것 같습니다. 나는 그것을 추가하고 당신을 신용.

아마 당신은 FlogScript를 찾을 수 있습니다
mbomb007


7

라켓 (도표), 4 자

(λ)

λ, 괄호 및 공간 만 사용하여 Scheme의 Lambda Calculus 하위 집합에서 직접 프로그래밍 할 수 있습니다. 모든 식별자에 λ 문자를 재사용하여 임의로 많은 수의 고유 식별자를 제공합니다.

예를 들어, 여기에 영원히 반복되는 클래식 오메가 콤비 네이터가 있습니다.

((λ (λλ) (λλ λλ)) (λ (λλ) (λλ λλ)))

6

파이썬 3, 9 자

exc('%1+)

기본 설명은 Python 2 답변 을 참조하십시오 . 이 답변은 저것에 기초합니다.

단순히 파이썬 2와 동일한 문자를 사용하는 대신 () 이제 괄호를 사용하므로 문자를 삭제할 수 있습니다. 프로그램은 여전히 ​​기본적인 형태를 갖습니다

exec('%c'%stuff)

그러나 +대신을 사용하여 프로그램 길이를 줄인 -다음 대신을 ~사용하여 제거 할 수 있습니다 . 그런 다음 추가 할 수 있습니다101 , 11그리고 111필요한 ASCII 값을 얻을 수 있습니다.

프로그램 print()은 가장 짧게 다음과 같이됩니다.

exec('%c%%c%%%%c%%%%%%%%c%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%c'%(111+1)%(111+1+1+1)%(11+11+11+11+11+11+11+11+11+1+1+1+1+1+1)%(11+11+11+11+11+11+11+11+11+11)%(111+1+1+1+1+1)%'('%')')

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

당신은 스스로 생각할 수도 있습니다. 어떻게 NUL 바이트를 만들지 0않습니까? 어린 메뚜기를 두려워하지 마라! 우리는 %수학 에 사용할 수있는 능력을 가지고 1%1있습니다.


왜 프로그램에서 NUL 바이트를 원합니까?
NieDzejkob

@NieDzejkob이 사이트에서 "왜"에 대한 답변은 항상 "우리가 할 수 있기 때문에"입니다. 그러나이 경우 오류가 발생하더라도 파이썬을 완전히 구현할 수는 없습니다.
mbomb007

튜링 완전성을 위해 NUL 바이트가 필요하지 않습니다. BF 통역사는 하나없이 작성 될 수 있습니다
MilkyWay90

@ MilkyWay90 사실이지만, 가능하다면 설명하지 않겠습니까?
mbomb007

6

PHP 7, 6 자

'().;^

아이디어는 다음 구성을 사용하여 임의 코드를 실행할 수 있다는 것입니다.

('create_function')('','<code>')();

eval 언어 구조이기 때문에 변수 함수를 사용하여 호출 할 수 없으므로 여기서 작동하지 않습니다.

create_function 코드는 사용 가능한 문자의 비트 XOR을 연결하여 작성할 수 있습니다.

(<char1_1>^<char1_2>^...).(<char2_1>^<char2_2>^...)...

().;^for를 사용 <charX_Y>하면

()./:;<=JKLMXY^_bcdepqvw

그리고 인쇄 할 수없는 캐릭터들. 충분하지 않지만 이제 전화를 걸고 'eXp'()숫자를 얻을 수도 있습니다.

''.'eXp'('eXp'('')) -> 1
''.'eXp'('eXp'('eXp'(''))) -> 2.718281828459
''.'eXp'('eXp'('eXp'('eXp'('eXp'(''))))) -> 3814279.1047602

그것은 우리에게 1( 2그리고 3다른 문자열이 한 문자 길이이면 다른 문자는 XOR에 의해 무시 될 것입니다)을 제공합니다. 에서().;^123 우리는 지금 모든 ASCII 문자 집합을 생성 할 수 있습니다.

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


5

파이크, 5 자

0h.CE

이것은 무한히 많은 수를 만들어 문자열로 바꾸고 파이크 코드로 평가할 수 있습니다.

코드 설명 :

0-스택에 0을 추가하십시오. 이것은 숫자를 시작하는 데 필요합니다

h-전에 숫자를 늘리십시오. 이것을 임의의 횟수만큼 반복하면 무한히 큰 숫자를 만들 수 있습니다. Pyke는 파이썬으로 작성된 큰 숫자를 지원합니다.이 숫자는 기본값으로 사용됩니다.

.C-다음 알고리즘을 사용하여 숫자를 문자열로 바꿉니다 : ( Github link )

def to_string(num):
    string = ""
    while num > 256:
        num, new = divmod(num, 256)
        string = chr(new) + string
    string = chr(num) + string
    return string

이 시점에서 Pyke에서 임의의 값으로 임의의 양의 문자열과 자연수를 만들 수 있습니다. 정규식에 해당하는 형식으로 숫자를 만들 수 있으며 다음 0(h)*과 같이 문자열을 만들 수 있습니다.0(h)*.C . 그것들은 서로 섞여서 문자열과 정수의 임의의 혼합을 만들 수 있습니다.

E-문자열을 파이크 코드로 평가하십시오. 이것은 이미 실행중인 파이크 코드와 동일한 환경을 사용하므로 입력과 같은 것을 공유합니다.

파이크가 튜링 완료되었다는 증거를 시도했습니다.

언어를 보여주는 가장 간단한 방법 중 하나는 튜링을 완료하는 것입니다. Pyke가 실행되도록 설계된 영역에서 가 필요하지 않기 때문에 목록 및 사전 작업이 거의 없기 때문에 Pyke에서 다른 언어보다 훨씬 어려울 수 있습니다 .

첫째로 우리는 brainf의 * CK 등록에 대한 통역을 생성하고 숫자를 만든 다음에 그 숫자를 표현하기 위해 위의 알고리즘을 사용하여 인코딩 0하고 h. 그런 다음 정확히 같은 방식으로 실행할 코드가 포함 된 문자열을 만듭니다. 만약 우리가 그것을 그대로두면 스택은

string containing brainf*ck code
string containing brainf*ck interpreter

이것은 Pyke 스택이 마지막으로 끝나기 때문에 코드가 반대 형식이어야 함을 의미합니다.

이제 재미있는 부분은 무려 216 바이트 인 brainf * ck 인터프리터입니다!

Q~B"><ht.,".:=B;Z]1=L;W~Bo@D=c"ht"{I~c~LZ@EZ]1~LR3:=L)~c\,qIz.oZ]1~LR3:=L)~c\.qI~LZ@.CpK)~c"<>"{I~c"<>""th".:ZE=ZZ1_qI0=Z~L0"":0]10:=L)Z~LlqI~L~Ll"":1_]10:=L))~c\[qI~LZ@0qI\]~B~o>@~o+h=o))~c\]qI~o\[~B~o<_@-t=o)~o~BlN

여기 사용해보십시오!

반 완전하지만 편집 가능한 형식으로 코드를 사용하려면 여기 에서 시도하십시오!

문자열을 숫자로 변환하려면 다음 Python 코드를 사용할 수 있습니다.

def conv(string, t=0):
    t *= 256
    t += ord(string[0])
    if len(string) != 1:
        return conv(string[1:], t)
    return t

(거의) 최종 솔루션은 여기에서 시도 할 수 있습니다 !

Brainf * ck 해석기 설명

먼저 프로그램을 여러 부분으로 분리하십시오.

  • 초기화 :

Q~B"><ht.,".:=B;Z]1=L; - The initialisation part
Q~B"><ht.,".:          - input.replace("><+-.,[]", "><ht.,")
                       - replace the characters in brainf*ck with some modified ones. 
                       - this means we can `eval` the add and subtract bits easily.
             =B;       - set `B` to this.
                       - The `B` variable contains the instructions
                Z]1=L; - set `L` to [0]
                       - `L` contains the stack, initialised with 0
  • 메인 루프 :

​​ ​ ​

W~Bo@D=c !code! ~o~BlN - The main loop
W                      - do
 ~Bo@D=c               -  c=B[o++]
                       -  the c variable is used to store the current character.
                ~o~BlN - while
                ~o     -   o 
                     N -  ^ != V 
                  ~Bl  -   len(B)
                       -  this stops the program running once it's finished.
  • 지시
    • 증가 / 감소 :+-

​​ ​ ​

"ht"{I~c~LZ@EZ]1~LR3:=L) - The bit that does incrementing and decrementing
"ht"{I                 ) - if c in "ht"
        ~LZ@             -  L[Z]
                         -  `Z` contains the current stack pointer
      ~c    E            -  eval current character with ^ as an argument
                         -  returns the contents of `Z` either incremented or decremented
             Z]1~LR3:=L  - L[Z] = ^
  • 입력 : ,:

​​ ​ ​

~c\,qIz.oZ]1~LR3:=L) - The code for output 
~c\,qI             ) -  if character == ",":
      z.o            -    ord(input)
         Z]1~LR3:=L  -   L[Z] = ^
  • 출력 : .:

​​ ​ ​

~c\.qI~LZ@.CpK) - The code for input 
~c\.qI        ) - if c == ".":
      ~LZ@      -    L[Z]
          .C    -   chr(^)
            pK  -  print(^)
  • 왼쪽 / 오른쪽 이동 : <>:

​​ ​ ​

~c"<>"{I~c"<>""th".:ZE=Z - main part 
~c"<>"{I                 - if "<>" in c:
        ~c"<>""th".:     -  c.replace("<>", "th")
                    ZE=Z -  Z = eval(char, Z)

Z1_qI0=Z~L0"":0]10:=L) - lower bound check
Z1_qI                ) - if Z == -1:
     0=Z               -  Z = 0
        ~L0"":         -  L.insert("", 0)
              0]10:=L  -  L[0] = 0

Z~LlqI~L~Ll"":1_]10:=L) - upper bound check
Z~LlqI                ) - if Z == len(L):
        ~Ll"":          -  L.insert("", len(L))
      ~L      1_]10:=L  -  L[-1] = 0
  • 조건부 : [:

​​ ​ ​

~c\[qI~LZ@0qI\]~B~o>@~o+h=o)) - Code for `[`
~c\[qI                      ) - if c == "[":
      ~LZ@0qI              )  -  if L[Z] == 0:
               ~B~o>          -     B[o:]
             \]     @         -    ^.find("]")
                     ~o+h=o   -   o = o + ^ + 1

-그리고 ]:

​​ ​ ​

~c\]qI~o\[~B~o<_@-t=o) - Code for `]`
~c\]qI               ) - if c == "]":
          ~B~o<_       -    reversed(B[:o])
        \[      @      -   ^.find("[")
      ~o         -t=o  -  o = o - ^ -1

5

누적, 5 자

{!n:}

놀랍게도 짧습니다. Stacked가 각 SKI 조합을 구현할 수 있으면 Turing Complete입니다. 요약 :

  • I 결합기-항등 함수. x -> x
  • K 결합기-상수 기능. x -> y -> x
  • S combinator-대체 함수 (x, y, z) -> x(z)(y(z))

나는 결합기 : {!n}

이제 누적 된 특성에 대해 {! ... }n- 람다입니다. 인수가 암시 적으로있는 단항 함수입니다 n. 그런 다음 마지막 표현식이 함수에서 리턴됩니다. 따라서 {!n}인수를 취하고 n산출 하는 함수입니다n .

K 콤비 네이터 : {!{:n}}

이제 {:...}인자를받지 않고를 반환하는 함수입니다 .... 이것을 n-lambda 형성과 결합하면 다음과 같이됩니다 (명확성을 위해 공백을 추가).

{! { : n } }
{!         }   n-lambda. arguments: (n)
   { : n }     lambda.   arguments: ()
       n       yields n.

S 조합기 : {n!nn!nnn:nnn{!n}!nn!nnn{!n}!n!!}

좋아, 이것은 좀 더 복잡해 보인다. 따라서 람다는 식별자가 아닌 문자로 구분 된 인수를 사용합니다. 따라서 헤더의 람다는 다음과 같습니다.

{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}

이 세 개의 인수를 람다이다 n, nn하고 nnn. 의는 이러한 교체하자 x, yz명확성을 위해 :

{x y z:z{!n}!y!z{!n}!x!!}

이 둘 {!n}!은 공백을 다시 피하기위한 신원 기능 일뿐 !입니다. 따라서 다시 줄이십시오.

{x y z:z y!z x!!}

설명과 함께 :

{x y z:z y!z x!!}
{x y z:         }  three arguments
       z y!        apply `y` to `z` -- `y(z)`
           z x!    apply `x` to `z` -- `x(z)`
               !   apply `x(z)` to `y(z)` -- `x(z)(y(z))`

따라서 이것이 S 결합기입니다.


{n nn nnn:nnn{!n}!nn!nnn{!n}!n!!}공백을 포함합니다.
CalculatorFeline

@CalculatorFeline 그 전에 문장을 읽었습니까? 좋아, 이것은 좀 더 복잡해 보인다. 따라서 람다는 식별자가 아닌 문자로 구분 된 인수를 취합니다. 따라서 헤더의 람다는 다음과 같습니다.
Conor O'Brien

오. (자기 메모 : 바보가되는 것을 그만 두십시오.)
CalculatorFeline
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.