파이썬 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)
|
---
스택 공간은 프로그램 외부에 있으므로 이전의 줄 바꿈 스팸 방지 주석입니다.
핵심 아이디어는 각 음성에 스택 역할을하는 행을 할당하는 것입니다. 이러한 스택을 유지하기 위해 각 스택의 길이가 행을 따라 셀에 기록되는 특수 스택 길이 행도 있습니다. 프로그램은 다음과 같은 많은 g
ets와 p
uts입니다.
- 에 세포를 얻을
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
있지만, 한 번에 한 단계 씩 수행하고 있습니다. :)