퍼플 인터프리터 골프


13

퍼플 인터프리터 골프

자주색 은 두 가지 주요 목적으로 설계된 esolang입니다.

  • Aubergine을 최소화하기 위해서는 주변에 자체 수정 한 명령 언어가 충분하지 않기 때문입니다.
  • 매우 작은 골프 통역사 의 가능성을 인정합니다 . 합리적인 기능을 갖춘 Python 2 인터프리터의 첫 번째 패스는 702 바이트에 불과하며 경험이 많은 골퍼가 그로부터 약간의 면도를 할 수 있다고 확신합니다.

귀하의 목표는이 언어에 대한 통역사를 작성하는 것입니다.

퍼플에 대한 정보 :

자주색 프로그램은 프로그램의 첫 번째 문자가 주소 0에 위치하도록 주소를 지정할 수있는 무한한 메모리 배열에 배치 된 일련의 문자입니다. 배열의 나머지 부분 (Purple 프로그램이 저장되기 전과 후)은 0으로 초기화됩니다.

Purple에는 abi 라는 3 개의 레지스터가 있으며 , 각각의 레지스터 는 부호있는 정수를 보유 할 수 있으며 0으로 초기화됩니다. i 도 명령 포인터이며 항상 현재 실행중인 Purple 명령을 가리 킵니다.

각 사이클에서 인터프리터는 명령 포인터로 표시된 메모리 위치에서 시작하여 3 개의 연속 문자 시퀀스를 읽고이 시퀀스를 퍼플 명령으로 실행하려고 시도합니다. 그 후 명령 포인터는 항상 3 씩 증가합니다.

구문 상, Purple 명령어는 " xyz " 와 같이 한 행에 3 개의 문자 (또는 그 인코딩)로 구성됩니다 .

첫 번째 문자 x 는 다음 중 하나 일 수 있습니다.

abABio

이 기호의 의미는 다음과 같습니다.

a - Place the result in register a.
b - Place the result in register b.
A - Place the result in the location in memory referred to by register a.
B - Place the result in the location in memory referred to by register b.
i - Set the instruction pointer to the result.
o - Output the result to stdout.

다른 두 바이트 yz 는 다음 중 하나 일 수 있습니다.

abABio1

이러한 각 기호는 다음과 같은 의미를 갖습니다.

a - Return the contents of register a.
b - Return the contents of register b.
A - Return the contents of the memory array at the address stored in register a.
B - Return the contents of the memory array at the address stored in register b.
i - Return the contents of register i (the instruction pointer).
o - Return the value of a single character read from stdin.
1 - Return the literal numeric value 1.

명령을 인출 한 후, 퍼플 인터프리터 평가할 것이다 Y 그리고 Z를 , 감산 결과 (Z)이 결과로부터 Y , 다음 작업이 수행로 나타낸 X 차이에서.

세 문자 시퀀스 (또는 그 인코딩)가 유효한 Purple 명령어가 아닌 경우, 인터프리터는 오류없이 즉시 중단됩니다.

통역사는 :

  • 기능이 아닌 완전한 프로그램이어야합니다.
  • EOF를 읽지 않으면 stderr로 출력하지 마십시오 .
  • 아래 주어진 테스트 프로그램을 포함하여 매우 많은 수를 포함하지 않는 잘 구성된 모든 입력에 대한 참조 구현과 동일하게 작동하십시오. (음, 타이밍에 동일하게-느리게 실행될 수는 있지만 너무 많이 실행할 수는 없습니다!)

프로그램을 원하는 형식으로 인터프리터에 제공 할 수 있습니다. 파일에서 읽거나 프로그램에 문자열로 포함 시키거나 stdin에서 읽습니다.

테스트 사례 :

프로그램

ooo

입력으로 실행할 때

z!

양보해야한다

Y

프로그램

bbboobiii

입력으로 실행할 때

It's a cat program.

(또는 다른 입력)

It's a cat program.

(또는 수신 된 모든 입력) 그런 다음 다시 시작하고 동일한 작업을 다시 수행하십시오 .


프로그램

Aoab11bi1bABoAaiba

입력으로 실행할 때

0

양보해야한다

0

그런 다음 정지하지만 입력으로 실행하면

1

계속 출력해야합니다

1

영원히.


프로그램

b1bbb1oAbabaa1ab1Ab1Bi1b

양보해야한다

b1bbb1oAbabaa1ab1Ab1Bi1b

프로그램

aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG

양보해야한다

Hello, World!

채점 :

이것은 이므로 다음 보너스로 잠재적으로 수정 된 바이트 단위의 가장 짧은 소스가 승리합니다.

보너스:

  • 인터프리터가 stdin 또는 명령 행 인수에서 파일 이름을 읽고 파일에서 프로그램을로드하는 경우 -10 %

1
메모리 셀의 크기는 얼마입니까? 바이트, 문자 (유니 코드 문자?), (임의) 큰 정수? 같은 의미로 "문자"와 "바이트"를 사용하고있는 것 같습니다.
Paŭlo Ebermann

@ PaŭloEbermann 제 생각에는 구현에 따라 다릅니다. 예를 들어 uint32, 문자에는 정수를, 정수에는 MAXINT 를 사용해야 합니다.
cat

2
@sysreq 정말 차단제입니까? 구현에는 단순히 네 개의 테이프와 양의 인덱스에 대한 두 개의 테이프가있을 수 있습니다. (예, 조금 더 많은 코드가 필요하지만 그렇게 생각하지는 않습니다.)
Paŭlo Ebermann

1
@sysreq 기본적으로 Purple self-interpreter는 stdin에서 Purple 프로그램을 읽은 다음 해당 프로그램이 수행하는 모든 작업을 수행하는 프로그램입니다. 첫 번째 퍼플 프로그램 (인터프리터)은 원하는 인터프리터에서 실행될 수 있습니다. 입력으로 가장 낮은 메모리 주소를 완전히 덮어 쓴 다음 어떻게 든 읽기 코드로 점프하기 전에 스스로 삭제하는 프로그램입니다 (실제로는 가능하지 않다고 생각합니다).
quintopia

2
나는 자기 해석이 가능한 런타임을 갖기 위해 너무 가까이 왔지만 너무 늦었다.
cat

답변:


7

Pyth, 148 128 121 바이트 (또는 124 * 0.9 = 111.6, 하단 참조)

J,00=kjb.z .eXHkCbz#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

테스트 스위트

STDIN의 첫 번째 행에 제공된 코드로, 나머지 STDIN의 Purple 프로그램에 입력됩니다. 줄 바꿈과 함께 코드를 사용하려면 맨 아래에 대체 버전을 사용하십시오.

합리적인 골프. 명확성을 위해 줄 바꿈과 들여 쓰기가 있습니다.

J,00
=kjb.z
 .eXHkCbz
#
  =b-Fm
    ?=zx"oabABi1"C@H+Zd
      @
        s[0Jm.x@Hk0JZ1H)
        z
      Ch~tk
    S2
   ?hKx"abAB"=YC@HZ
    ?PK
      XH@JKb
      XJKb
  ?qY\i=Zb
  ?qY\opCb
  vN
  =+Z3

기본적으로 #루프는 오류 구분을 통해 실행 및 중지를 수행합니다.

a그리고 b, 하나의 변수에 결합된다 J. Z명령 포인터입니다. k퍼플 프로그램에 입력됩니다. H사전으로 표시되는 테이프입니다. b현재 결과입니다. Y명령어의 현재 첫 바이트입니다.

파일에서 읽기 :

J,00=kjb.z .eXHkCbjb'z#=b-Fm?q\o=zC@H+ZdCh~tk@s[Jm.x@Hk0JZ1H)x"abABi1"zS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

파일 이름을 STDIN의 첫 번째 줄로 지정하십시오. 시운전 :

$ cat purple-final.pyth 
J,00=kjb.z .eXHkCbjb'z#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3
$ cat purple-code.txt 
aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG
$ pyth purple-final.pyth <<< 'purple-code.txt' 
Hello, World!

5

자바 스크립트 (ES6), 292 바이트

eval(`a=b=i=d=0;v=n=>(x=m[i+n])==97?a_98?b_65?m[a]_66?m[b]_105?i_111?p()[c]()_49?1:d=1;for(m=[...(p=prompt)()].map(b=>b[c="charCodeAt"]());!d;i+=3)(y=v(1),d)||(z=v(2),d)?1:(x=m[r=y-z,i])==97?a=r_98?b=r_65?m[a]=r_66?m[b]=r_105?i=r-3_111?alert(String.fromCharCode(r)):d=1`.replace(/_/g,":x=="))

설명

자바 스크립트 대답은 항상 때 이상한 있습니다 STDINSTDOUT필요 ...

첫 번째 프롬프트는 프로그램 문자열의 입력입니다. o명령의 결과 인 각 프롬프트 는 첫 번째 문자 만 읽습니다.

eval몇 바이트를 절약하는 일반적인 문구를 대체하는 데 사용됩니다. Ungolfed 및 eval프로그램이 없는 경우 다음과 같습니다.

// Initialisation
a=b=i=                            // initialise registers to 0
  d=0;                            // d is set to true when the program should die

// Gets the result of Y or Z
v=n=>                             // n = offset from i
  (x=m[i+n])==97?a:               // x = value of instruction
  x==98?b:
  x==65?m[a]:
  x==66?m[b]:
  x==105?i:
  x==111?p()[c]():
  x==49?1:
  d=1;                            // if it was none of the valid values, die

// Execution loop
for(
  m=                              // m = memory array
    [...(p=prompt)()]             // receive the program
    .map(b=>b[c="charCodeAt"]()); // initialise m to the ASCII values of the program
  !d;                             // finish if an error occured
  i+=3                            // increment i
)
  (y=v(1),d)||                    // get the value of Y and check for errors
  (z=v(2),d)?1:                   // get the value of Z and check for errors

    // Get the result of X
    (x=m[r=y-z,i])==97?a=r:       // r = result of y - z
    x==98?b=r:
    x==65?m[a]=r:
    x==66?m[b]=r:
    x==105?i=r-3:
    x==111?alert(String.fromCharCode(r)):
    d=1

2
두 번째 c="charCodeAt"를 그냥 대체 할 수 있습니까 c?
Dendrobium

음수 인덱스를 사용한 배열 액세스가 JavaScript에서 작동합니까?
nimi

@Dendrobium 와우, 나는 그 하하를 어떻게 그리웠는지 모르겠다! 감사.
user81655

2
@nimi 작동합니다. 배열 자체는 음수 인덱스를 지원하지 않지만 개체로도 작동한다는 사실을 이용합니다. array[-1] = 1와 동일합니다 array = { "-1": 1 }. 둘 다로 액세스 할 수 있습니다 array[-1].
user81655

@ user81655 : 아, 잘 몰랐어요.
nimi

3

실론, 827 792671 바이트

import ceylon.language{l=variable,I=Integer,x=nothing,p=process,m=map}shared void run(){try{if(exists d=p.arguments[0]){l value t=m{*d*.hash.indexed};l I a=0;l I b=0;l I i=0;I g(I j)=>t[j]else 0;l{I*}c=[];I o{if(c==[]){if(exists e=p.readLine()){c=e*.hash.chain{10};}else{c={-1}.cycled;}}assert(is I r=c.first);c=c.rest;return r;}value f=m{97->{a},98->{b},65->{g(a)},66->{g(b)},105->{i},111->{o},49->{1}};value s=m{97->((I v)=>a=v),98->((I v)=>b=v),65->((I v)=>t=m{a->v,*t}),66->((I v)=>t=m{b->v,*t}),105->((I v)=>i=v),111->((I v)=>p.write("``v.character``"))};I h(I v)=>f[v]?.first else x;while(0<1){(s[g(i)]else x)(h(g(i+1))-h(g(i+2)));i+=3;}}}catch(AssertionError e){}}

프로그램이 EOF에서 입력을 읽으려고 할 때 참조 구현과 약간 다르게 작동합니다. 참조 구현은 TypeError와 충돌하여 여기에서 재현하기에는 너무 비싸고 (그리고 버그 일 수도 있음) 대신 -1을 반환합니다 ( 필요한 경우 반복적으로).

(이 -1을 stdout에 쓰려고 할 때 인터프리터는 OverflowError로 끝납니다. 유니 코드 범위를 벗어난 정수가 출력되는 경우에도 마찬가지입니다.)

인터프리터는 프로그램을 첫 번째 명령 줄 인수로 사용합니다 (공백 또는 기타 흥미로운 내용이 포함 된 경우 쉘에 대해 인용해야 함).

실론에서 우리는 입력을 한 줄씩 쉽게 읽을 수 있습니다 (다음 버전 중 하나에서 변경 될 것이라고 생각합니다). o읽기를 위해 사용될 때 전체 줄을 읽고 나중에 사용할 수 있도록 부품을 버퍼링합니다. 터미널에 연결할 때 Python 구현에서 비슷하게 작동한다고 생각합니다.


유효한 문자 중 하나가 아닌 명령 (부분)을 실행하려고 nothing하면 AssertionError가 발생하여 주 루프 주위의 catch 블록을 잡습니다.

필자는 이것이 커스텀 예외 유형 (AssertionError가 버그가있는 경우 다른 곳에서도 발생할 수 있음)이어야한다고 생각하지만 훨씬 많은 공간이 필요하므로 첫 번째 버전에서 개선 된 부분이 많이 있습니다.

골프에 사용되는 몇 가지 트릭 :

  • 이전 버전에서는 ceylon.collection.HashMap을 사용했습니다. 대신 map함수에서 만든 변경 불가능한 맵을 사용하고 매번 새 맵을 만들 A거나 xB 로 사용합니다 .
  • ceylon.language의 모든 식별자에 대해 별칭 가져 오기를 사용합니다 ( variable주석을 포함하여 두 번 이상 사용됨 l).
  • 클래스 E(환경) 및 s(단계) 메소드를 제거했습니다 run. 이제 모든 것이 함수 내부에서 발생 합니다.
  • .integer문자의 코드 포인트를 얻는 데 사용 하는 대신 .hash동일한 결과를 제공합니다. 따라서 (문자열에서 코드 포인트를 반복 가능 string*.hash하게 함)과 동일 string.map(Character.integer)합니다.
  • 유형을 별칭으로 가져 오는 경우 is I ...보다 짧습니다 exists ....
  • 무언가를 (예를 들어 x) 문자열로 변환 할 때 (또는 문자에 사용한 "``t``"것)보다 짧습니다 .t.stringString{t}
  • 한 번만 사용 된 함수는 종종 인라인 될 수 있습니다.

형식화 및 주석 처리 된 버전은 다음과 같습니다.

// Purple – a self-modifying, "one-instruction" language.
//
// Question:  http://codegolf.stackexchange.com/q/65411/2338
// My answer: http://codegolf.stackexchange.com/a/65492/2338

import ceylon.language {
    l=variable,
    I=Integer,
    x=nothing,
    p=process,
    m=map
}

shared void run() {
    try {
        // Reading code from file certainly takes more than 73 characters,
        // this isn't worth the 10% bonus.
        if (exists d = p.arguments[0]) {

            // The memory tape, as a Map<Integer, Integer>.
            // We can't modify the map itself, but we
            // can replace it by a new map when update is needed.
            l value t = m {
                // It is initialized with the code converted to Integers.
                // We use `.hash` instead of `.integer` because it is shorter.
                *d*.hash.indexed };

            // three registers
            l I a = 0;
            l I b = 0;
            l I i = 0;

            // get value from memory
            I g(I j) =>
                    t[j] else 0;

            // cached input which is still to be read
            l {I*} c = [];

            // get value from stdin.
            // we can only comfortably access stdin by line, so we read a whole line
            // and cache the rest for later.
            I o {
                if (c == []) {
                    if (exists e = p.readLine()) {
                        c = e*.hash.chain { 10 }; // convert string into ints, append \n
                    } else {
                        // EOF – return just -1 from now on.
                        c = { -1 }.cycled;
                    }
                }
                assert (is I r = c.first);
                c = c.rest;
                return r;
            }


            // Map of "functions" for fetching values.
            // We wrap the values in iterable constructors for lazy evaluation
            //  – this is shorter than using (() => ...).
            // The keys are the (Unicode/ASCII) code points of the mapped
            // source code characters.
            value f = m {
                // a
                97 -> { a },
                // b
                98 -> { b },
                // A
                65 -> { g(a) },
                // B
                66 -> { g(b) },
                // i
                105 -> { i },
                // o
                111 -> { o },
                // 1
                49 -> { 1 }
            };

            // Map of functions for "storing" results.
            // The values are void functions taking an Integer,
            // the keys are the ASCII/Unicode code points of the corresponding
            // source code characters.
            value s = m {
                // a
                97 -> ((I v) => a = v),
                // b
                98 -> ((I v) => b = v),
                // Modification of the memory works by replacing the map with a new one.
                // This is certainly not runtime-efficient, but shorter than importing
                // ceylon.collections.HashMap.
                // A
                65 -> ((I v) => t = m { a->v, *t }),
                // B
                66 -> ((I v) => t = m { b->v, *t }),
                // i
                105 -> ((I v) => i = v),
                // o – output as a character.
                111 -> ((I v) => p.write("``v.character``"))
            };

            // accessor function for the f map
            I h(I v) =>
                    f[v]?.first else x;

            // the main loop, can only be left by exception
            while (0 < 1) {
                (s[g(i)] else x)(h(g(i + 1)) - h(g(i + 2)));
                i += 3;
            }
        }
    } catch (AssertionError e) {
        // abort silently
    }
}

나는 모든 정지 프로그램을 찾으려고 하는 "병렬 통역사"를 위해 그 코드의 일부를 재사용했다 . (많은 것들이 있습니다.) (I / O는 많은 공간을 차지하고 그 작업에 사용되지 않기 때문에 비 I / O 버전의 자주색을 사용했습니다.)
Paŭlo Ebermann
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.