Prelude를 Befunge로 번역


19

입니다 주간 도전 # 2. 주제 : 번역

Prelude 에서 프로그램의 소스 코드를 취하고 Befunge-93 에서 동등한 프로그램의 코드를 출력 하는 프로그램 또는 함수를 작성하십시오 . 프로그램이 동등하게 되려면 주어진 입력에 대해 Prelude 프로그램과 동일한 출력을 생성하고 Prelude 프로그램이 중지 된 경우에만 중지해야합니다.

입력 언어 : Prelude

파이썬 인터프리터 :

Prelude 프로그램은 명령을 동시에 실행하는 많은 "음성"으로 구성됩니다. 각 음성에 대한 지침은 별도의 회선에 있습니다. 각 음색에는 별도의 스택이 있으며 무한한 양의 0으로 초기화됩니다. 실행은 맨 왼쪽 열에서 시작하여 영향을 )받거나 (명령에 영향을받는 경우를 제외하고 각 눈금마다 한 열씩 오른쪽으로 이동합니다 . 마지막 열에 도달하면 프로그램이 종료됩니다.

이 과제에 대한 전주 사양 :

Digits 0-9      Push onto the stack a number from 0 to 9. Only single-digit
                    numeric literals can be used.
^               Push onto the stack the top value of the stack of the above 
                    voice.
v               Push onto the stack the top value of the stack of the below 
                    voice.
#               Remove the top value from the stack.
+               Pop the top two integers from the stack and push their sum.
-               Pop the top two integers from the stack, subtract the topmost 
                    from the second, and push the result.
(               If the top of the stack is 0, jump to the column after the 
                    matching `)` after the current column executes.
)               If the top of the stack is not 0, jump to the column after 
                    the matching `(` after the current column executes.
?               Read an integer from STDIN.
!               Pop one value from the stack and print it to STDOUT as an
                    integer.
<space>         No-op

노트

  • v그리고 ^이렇게, 순환 작용 v하단 보이스 상단 음성의 스택 요소를 복사하며, ^상단에 하단 음성 음성 복사한다. 추론 : 모두 v와하는 ^단일 음성 프로그램에서 스택의 상단을 중복.
  • A (와 일치하는 항목 )은 다른 줄에있을 수 있습니다. 그러나 , a )는 항상 그 자체가 배치 된 (스택이 아니라 해당 스택이 배치 된 음색의 스택을 확인합니다 ).
  • ^v명령어로 생성 된 값은 동일한 열에서 다른 작업이 완료되기 전에 존재하는 값에서 작동합니다.
  • ?!esolangs.org에있는 사양 과 다르게 작동하므로이 게시물에 제공된 약간 수정 된 인터프리터로 테스트해야합니다.

입력 내용은 다음과 같습니다.

  • 일치하는 괄호
  • 열에 하나 이상의 괄호가 없습니다
  • 각 줄에 같은 수의 문자
  • 최소한 한 줄
  • 둘 이상의 I / O ( !또는 ?) 명령어가있는 열이 없습니다.
  • 각 음성에 대한 지침 다음에 한 줄 바꿈 문자
  • 위에서 언급 한 것 이외의 문자는 없습니다

출력 언어 : Befunge-93

Befunge는 프로그램 카운터 (PC; 현재 명령에 대한 포인터)가 2 차원 그리드에서 자유롭게 이동하는 스택 기반 언어입니다. 왼쪽 상단에서 시작하여 오른쪽으로 이동합니다. 운동장은 환상적입니다. 즉 PC 움직임이 양쪽 가장자리를 감 쌉니다. Befunge는 또한 무한의 0으로 초기화되는 스택을 가지고 있습니다. Befunge는 다음과 같은 작업을 수행합니다.

Befunge-93 컴파일러 / 인터프리터의 다음 특성을 가정 할 수 있습니다.

  • 정수는 무제한 정밀도입니다.
  • 모든 크기의 그리드를 허용합니다.
  • 그리드 좌표 (for gp)는 0을 기준으로합니다.

채점

Befunge에서 Prelude 인터프리터를 생성하고 Prelude 소스를 하드 코딩하는 제출을 막기 위해 결과 Befunge 소스 코드의 크기를 최소화하는 것이 목표입니다.

다음은 다양한 Prelude 프로그램입니다. 당신의 번역가는이 모든 것들에서 실행될 것입니다. 당신의 점수는 Befunge 프로그램의 크기의 합계입니다.

번역자는 이러한 테스트 사례에 맞게 특별히 최적화되어서는 안됩니다 (예 : 필기 Befunge 프로그램을 하드 코딩하여). 본인의 답변이 의심되는 경우 입력을 변경하거나 추가 입력을 생성 할 권리가 있습니다.

샘플 입력

n-1아래로 인쇄 0:

?(1-^!)

논리 AND :

?  (0)  
 ?(0  ) 
    1  !

논리 OR :

 ?   (0) 
? (0)    
   1  1 !

음수가 아닌 입력 (예 : 모듈로 2)의 패리티를 확인하십시오.

?(1-)   
 ^  v   
 v1-^^-!

입력의 제곱 :

 ^    
  ^+ !
?(1-) 

n 번째 피보나치 수를 인쇄하십시오 . 여기서 n = 00에 n = 1해당하고 1에 해당합니다

0 v+v!
1   ^ 
?(1-) 

Signum :

  1) v #  - !
 vv (##^v^+) 
?(#   ^   ## 

음이 아닌 입력의 구분 :

1 (#  1) v #  - 1+)   
     vv (##^v^+)      
?  v-(0 # ^   #       
 ?                    
   1+              1-!

물론, 음수에 대한 샘플 프로그램의 동작이 지정되지 않은 경우에도 프로그램은 모든 경우에 대해 동일한 동작을 나타내야합니다.

마지막으로, 번역자는 비합리적으로 길지 않아야합니다.

  • 스택 교환 게시물 안에 포함되어야합니다.
  • 일반적인 데스크탑 컴퓨터에서 10 분 이내에 샘플 입력을 처리해야합니다.

Prelude 또는 Befunge에 대한 숫자 입력은 선택적 빼기 부호, 하나 이상의 10 진수 및 개행 문자로 제공됩니다. 다른 입력은 정의되지 않은 동작입니다.

당신은 어떤 언어로 번역기를 쓸 수 있습니다. 번역 된 가장 짧은 Befunge 코드가 이깁니다.

리더 보드

  • Sp3000 : 16430 바이트

이해할 수 없습니다. "위의 음성 스택에서 최상위 값을 스택에 푸시하십시오." 꼭 그럴 필요는 없습니다 . "위의 음성 스택의 최상위 값 스택에 푸시하십시오 ."
데프

그것은 prelude가 동시에 음성을 실행한다는 것을 의미합니다. 실제로 별도의 스레드에서 실행되거나 모든 음성에서 첫 번째 명령 (위에서 아래로)과 두 번째 명령 등을 실행할 수 있습니까?
데프

@Deformyer "on"에서 "of"로 변경했지만 "stack의 최상위 값"도 잘못된 것이 아니라고 생각했습니다. 동시성에 관해서는 실제로 병렬로 해석 할 필요가 없습니다. 중요한 것은 모두 스택의 이전 상태에서 작동하며 주어진 열의 작업은 해당 열의 다른 작업에 영향을 줄 수 없다는 것입니다.
마틴 엔더

여러 테스트 사례가 "두 개 이상의 I / O (! 또는?) 명령이있는 열이 아닙니까?"
Fuwjax

@proudhaskeller The 1루프 안에 있기 때문에 푸시되지 않을 수 있습니다. 0은 스택에서 시작되는 무한한 양의 0에서 올 수 있습니다.
feersum

답변:


10

파이썬 3, 나중에 득점

from collections import defaultdict
from functools import lru_cache
import sys

NUMERIC_OUTPUT = True

@lru_cache(maxsize=1024)
def to_befunge_num(n):
    # Convert number to Befunge number, using base 9 encoding (non-optimal,
    # but something simple is good for now)

    assert isinstance(n, int) and n >= 0

    if n == 0:
        return "0"

    digits = []

    while n:
        digits.append(n%9)
        n //= 9

    output = [str(digits.pop())]

    while digits:
        output.append("9*")
        d = digits.pop()

        if d:
            output.append(str(d))
            output.append("+")

    output = "".join(output)

    if output.startswith("19*"):
        return "9" + output[3:]

    return output

def translate(program_str):
    if program_str.count("(") != program_str.count(")"):
        exit("Error: number of opening and closing parentheses do not match")

    program = program_str.splitlines()
    row_len = max(len(row) for row in program)
    program = [row.ljust(row_len) for row in program]
    num_stacks = len(program)


    loop_offset = 3
    stack_len_offset = program_str.count("(")*2 + loop_offset
    stack_offset = stack_len_offset + 1
    output = [[1, ["v"]], [1, [">"]]] # (len, [strings]) for each row
    max_len = 1 # Maximum row length so far

    HEADER_ROW = 0
    MAIN_ROW = 1
    FOOTER_ROW = 2
    # Then stack lengths, then loop rows, then stacks

    # Match closing parens with opening parens
    loop_map = {} # {column: (loop num, stack number to check, is_start)}
    loop_stack = []
    loop_num = 0

    for col in range(row_len):
        col_str = "".join(program[stack][col] for stack in range(num_stacks))

        if col_str.count("(") + col_str.count(")") >= 2:
            exit("Error: more than one parenthesis in a column")

        if "(" in col_str:
            stack_num = col_str.index("(")

            loop_map[col] = (loop_num, stack_num, True)
            loop_stack.append((loop_num, stack_num, False))
            loop_num += 1

        elif ")" in col_str:
            if loop_stack:
                loop_map[col] = loop_stack.pop()

            else:
                exit("Error: mismatched parentheses")


    def pad_max(row):
        nonlocal max_len, output

        while len(output) - 1 < row:
            output.append([0, []])

        if output[row][0] < max_len:
            output[row][1].append(" "*(max_len - output[row][0]))
            output[row][0] = max_len


    def write(string, row):
        nonlocal max_len, output

        output[row][1].append(string)
        output[row][0] += len(string)

        max_len = max(output[row][0], max_len)


    def stack_len(stack, put=False):
        return (to_befunge_num(stack) + # x
                str(stack_len_offset) + # y
                "gp"[put])


    def get(stack, offset=0):
        assert offset in [0, 1] # 1 needed for 2-arity ops

        # Check stack length
        write(stack_len(stack) + "1-"*(offset == 1) + ":0`", MAIN_ROW)

        pad_max(HEADER_ROW)
        pad_max(MAIN_ROW)
        pad_max(FOOTER_ROW)

        write(">" + to_befunge_num(stack + stack_offset) + "g", HEADER_ROW)
        write("|", MAIN_ROW)
        write(">$0", FOOTER_ROW)

        pad_max(HEADER_ROW)
        pad_max(MAIN_ROW)
        pad_max(FOOTER_ROW)

        write("v", HEADER_ROW)
        write(">", MAIN_ROW)
        write("^", FOOTER_ROW)


    def put(stack, value=""):
        put_inst = (value +
                    stack_len(stack) +
                    to_befunge_num(stack + stack_offset) +
                    "p")

        post_insts.append(put_inst)


    def pop(stack):
        put(stack, "0")


    def inc_stack_len(stack):
        post_insts.append(stack_len(stack) + "1+")
        post_insts.append(stack_len(stack, put=True))


    def dec_stack_len(stack):
        post_insts.append(stack_len(stack) + ":0`-") # Ensure nonnegativity
        post_insts.append(stack_len(stack, put=True))


    # Technically not necessary to initialise stack lengths per spec, but it makes it
    # more portable and easier to test against other Befunge interpreters

    for stack in range(num_stacks):
        write("0" + stack_len(stack, put=True), MAIN_ROW)

    for col in range(row_len):
        post_insts_all = []

        loop_start = False
        loop_end = False

        if col in loop_map:
            if loop_map[col][2]:
                loop_start = True
            else:
                loop_end = True

        if loop_start:
            loop_row = loop_offset + 2*loop_map[col][0]
            get(loop_map[col][1])

        elif loop_end:
            get(loop_map[col][1])
            write("!", MAIN_ROW)


        for stack in range(num_stacks-1, -1, -1):
            char = program[stack][col]
            post_insts = [] # Executed after the gets in reverse order, i.e. last added first

            if char in " ()":
                continue

            # Pre-inc, post-dec
            elif char.isdigit():
                inc_stack_len(stack)
                put(stack, char)

            elif char == "?":
                inc_stack_len(stack)
                put(stack, "&")

            elif char == "!":
                get(stack)
                post_insts.append(".91+," if NUMERIC_OUTPUT else ",")
                pop(stack)
                dec_stack_len(stack)

            elif char == "#":
                pop(stack)
                dec_stack_len(stack)

            elif char in "+-":
                get(stack, 1)
                get(stack)
                post_insts.append(char)
                pop(stack) # This one first in case of ! or 1!
                post_insts.append(stack_len(stack) + ":1`-:1\\`+") # Ensure >= 1
                post_insts.append(stack_len(stack, put=True))
                put(stack)                

            elif char in "^v":
                offset = -1 if char == "^" else 1

                get((stack + offset) % num_stacks)
                inc_stack_len(stack)
                put(stack)

            else:
                exit("Error: invalid character " + char)

            post_insts_all.append(post_insts)


        while post_insts_all:
            write("".join(post_insts_all.pop()), MAIN_ROW)

        if loop_start or loop_end:
            loop_row = loop_offset + 2*loop_map[col][0]

            pad_max(HEADER_ROW)
            pad_max(MAIN_ROW)
            pad_max(loop_row)
            pad_max(loop_row + 1)

            write(">v", HEADER_ROW)
            write("|>", MAIN_ROW)

            if loop_start:
                write(" ^", loop_row)
                write(">", loop_row + 1)

            else:
                write("<", loop_row)
                write(" ^", loop_row + 1)


    write("@", MAIN_ROW)
    return "\n".join("".join(row) for row_len, row in output)

if __name__ == '__main__':
    if len(sys.argv) < 3:
        exit("Usage: py -3 prefunge.py <input filename> <output filename>")

    with open(sys.argv[1]) as infile:
        with open(sys.argv[2], "w") as outfile:
            outfile.write(translate(infile.read()))

처럼 실행하십시오 py -3 prefunge.py <input filename> <output filename>.

저에게는 느린 주였습니다. 그래서 마침내이 6 개월 된 질문을 해결할만큼 지루했습니다. 다른 사람이 시도하지 않은 이유를 묻지 만 여전히 디버깅으로 인한 고통을 느끼고 있습니다 (아마도 여전히 버그가 남아 있습니다).

이 질문은 Befunge-93 통역사를 제공하지 않으므로 사양과 약간 다른 해석기를 사용 했습니다 . 두 가지 주요 차이점은 다음과 같습니다.

  • 프로그램의 주어진 행에 문자가 존재하지 않으면 해당 행에 쓸 수 없습니다. 즉, Enter 키를 여러 번 눌러 끝에 줄 바꿈이 충분해야합니다 . NaN출력에 s가 표시 되면 이것이 가장 가능성이 큰 원인입니다.

  • 그리드 셀은 0으로 사전 초기화되지 않았습니다. 편의상 Befunge 출력에 사전 초기화가 포함되었지만 필요하지 않기 때문에 점수를 시작할 때 제거 할 수 있습니다.

출력 프로그램의 핵심 레이아웃은 다음과 같습니다.

v [header row]
> [main row]
  [footer row]
  ---
   |
   | rows for loops (2 per loop)
   |
  ---
  [stack length row]
  ---
   |
   | rows for stack space (1 per voice)
   |
  ---

스택 공간은 프로그램 외부에 있으므로 이전의 줄 바꿈 스팸 방지 주석입니다.

핵심 아이디어는 각 음성에 스택 역할을하는 행을 할당하는 것입니다. 이러한 스택을 유지하기 위해 각 스택의 길이가 행을 따라 셀에 기록되는 특수 스택 길이 행도 있습니다. 프로그램은 다음과 같은 많은 gets와 puts입니다.

  • 에 세포를 얻을 y = stack_row[stack], x = stack_length[stack]
  • 수행 .91+,의 정수는 다음 개행 문자를 인쇄로 즉, 인쇄,
  • 위 좌표의 셀을 0으로 바꿉니다 (팝핑 시뮬레이션).
  • 감소 stack_length[stack]

열의 동시 평가를 수행하기 위해 모든 필요한 셀을 읽고 셀에 쓰기 전에 값을 스택에 유지합니다 (예 : 인쇄 예제의 경우 첫 번째 단계와 두 번째 단계 사이에 더 많은 명령이있을 수 있습니다).

`보다 큰,는 스택 길이가 음수가되지 않도록하고 스택이 비어있을 때 0을 푸시하기 위해 사용됩니다. 이것은 분명히 보이는 분기가 나오는 곳이지만 분기를 제거하는 아이디어를 얻었습니다. 첫 번째와 세 번째 행에서 많은 공백을 제거해야합니다.

루프의 경우 Prelude 루프가 양방향으로 이동할 수 있으므로 다음과 같이 구성에서 루프 당 두 개의 행을 사용합니다.

       >v                     >v
(cond) |>  (program)  (cond) !|>

        ^                     <
       >                       ^

이 루프는 현재 대부분의 바이트를 구성하지만 코드 상자에 코드를 삽입하여 쉽게 다운 할 수 있습니다 p.

다음은 몇 가지 예를 출력입니다 ?(1-^!)즉, 인쇄, n-1아래로 0:

v                        >6gv>v                      >6gv      >6gv                                 >6gv                   >6gv                           >6gv >v
>005p05g1+05p&05g6p05g:0`|  >|>05g1+05p105g6p05g1-:0`|  >05g:0`|  >-005g6p05g:1`-:1\`+05p05g6p05g:0`|  >05g1+05p05g6p05g:0`|  >.91+,005g6p05g:0`-05p05g:0`|  >!|>@
                         >$0^                        >$0^      >$0^                                 >$0^                   >$0^                           >$0^
                              ^                                                                                                                                <
                             >                                                                                                                                  ^

제곱 입력 :

v                                >8gv      >8gv             >v      >6gv                                   >8gv      >8gv        >7gv      >7gv                                                            >8gv >v      >7gv
>005p015p025p25g1+25p&25g8p25g:0`|  >25g:0`|  >05g1+05p05g6p|>05g:0`|  >15g1+15p15g7p25g1+25p125g8p25g1-:0`|  >25g:0`|  >15g1-:0`|  >15g:0`|  >+015g7p15g:1`-:1\`+15p15g7p-025g8p25g:1`-:1\`+25p25g8p25g:0`|  >!|>15g:0`|  >.91+,015g7p15g:0`-15p@
                                 >$0^      >$0^                     >$0^                                   >$0^      >$0^        >$0^      >$0^                                                            >$0^         >$0^
                                                             ^                                                                                                                                                  <
                                                            >                                                                                                                                                    ^

구분 (작은 입력 권장) :

v                                                                          >91+gv>v      >94+gv                                                         >95+gv      >95+gv        >93+gv      >93+gv                                                                    >93+gv      >93+gv               >v      >93+gv                                                     >93+gv >v      >92+gv                  >v      >92+gv                                       >92+gv                                       >91+gv                                       >93+gv                     >91+gv                       >92+gv      >92+gv        >91+gv      >91+gv                                                                                      >92+gv >v                        >91+gv      >91+gv                                     >91+gv >v                        >95+gv      >95+gv                                     >95+gv
>009p019p029p039p049p09g1+09p109g91+p29g1+29p&29g93+p39g1+39p&39g94+p09g:0`|    >|>39g:0`|    >009g91+p09g:0`-09p29g1+29p29g93+p49g1+49p149g95+p49g1-:0`|    >49g:0`|    >29g1-:0`|    >29g:0`|    >-029g93+p29g:1`-:1\`+29p29g93+p+049g95+p49g:1`-:1\`+49p49g95+p29g:0`|    >29g:0`|    >19g1+19p19g92+p|>29g:0`|    >09g1+09p109g91+p19g1+19p19g92+p29g1+29p029g93+p29g:0`|    >!|>19g:0`|    >029g93+p29g:0`-29p|>19g:0`|    >09g1+09p09g91+p019g92+p19g:0`-19p19g:0`|    >019g92+p19g:0`-19p29g1+29p29g93+p09g:0`|    >009g91+p09g:0`-09p19g1+19p19g92+p29g:0`|    >19g1+19p19g92+p09g:0`|    >19g1+19p19g92+p19g1-:0`|    >19g:0`|    >09g1-:0`|    >09g:0`|    >-009g91+p09g:1`-:1\`+09p09g91+p+019g92+p19g:1`-:1\`+19p19g92+p029g93+p29g:0`-29p19g:0`|    >!|>09g1+09p109g91+p09g1-:0`|    >09g:0`|    >+009g91+p09g:1`-:1\`+09p09g91+p09g:0`|    >!|>49g1+49p149g95+p49g1-:0`|    >49g:0`|    >-049g95+p49g:1`-:1\`+49p49g95+p49g:0`|    >.91+,049g95+p49g:0`-49p@
                                                                           >$0  ^        >$0  ^                                                         >$0  ^      >$0  ^        >$0  ^      >$0  ^                                                                    >$0  ^      >$0  ^                       >$0  ^                                                     >$0  ^         >$0  ^                          >$0  ^                                       >$0  ^                                       >$0  ^                                       >$0  ^                     >$0  ^                       >$0  ^      >$0  ^        >$0  ^      >$0  ^                                                                                      >$0  ^                           >$0  ^      >$0  ^                                     >$0  ^                           >$0  ^      >$0  ^                                     >$0  ^
                                                                                  ^                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <
                                                                                 >                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ^
                                                                                                                                                                                                                                                                                                          ^                                                                        <
                                                                                                                                                                                                                                                                                                         >                                                                          ^
                                                                                                                                                                                                                                                                                                                                                                                                                    ^                                                                                                                                                                                                                                                                                                                                              <
                                                                                                                                                                                                                                                                                                                                                                                                                   >                                                                                                                                                                                                                                                                                                                                                ^

로 교체 07p07g하는 것과 같은 여러 가지 사소한 최적화가 :07p있지만, 한 번에 한 단계 씩 수행하고 있습니다. :)


그래서. 많은. 비어 있는. 시각.
Optimizer

1
Will score later2 년 이상! :)
HyperNeutrino
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.