Prelude to Befunge temasını tercüme et


19

Bu Haftalık Görev # 2. Tema: Çeviri

Prelude'taki bir program için kaynak kodunu alan ve Befunge-93'te eşdeğer bir program için kod çıkaran bir program veya işlev yazın . Programın eşdeğer olması için, herhangi bir giriş için Prelude programıyla aynı çıktıyı üretmeli ve yalnızca Prelude programı durursa durmalıdır.

Giriş dili: Prelude

Python yorumlayıcısı:

Bir Prelude programı, talimatları aynı anda yürüten bir dizi "ses" den oluşur. Her ses için talimatlar ayrı bir satırdadır. Her sesin, sonsuz miktarda sıfırla başlatılan ayrı bir yığını vardır. Yürütme en soldaki sütundan başlar ve etkilenen durumlar )veya (talimatlar dışında her bir işaretin sağına bir sütun ilerletir . Program, son sütuna ulaşıldığında sona erer.

Bu meydan okuma için başlangıç ​​spesifikasyonu:

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

notlar

  • vve ^döngüsel olarak hareket eder, böylece valt ses üst sesin yığın öğesini kopyalar ^ve üst ses alt sesden kopyalanır. Corollary: Hem vve ^tek sesli programında yığının tepesine çoğaltmak.
  • A (ve eşleşmesi )farklı hatlarda bulunabilir. Bununla birlikte , a )her zaman karşılık gelen sesin yığınına bakacaktır (, )kendi yerleştirildiği yığına değil .
  • ^Ve vtalimatları tarafından üretilen değerler, aynı sütundaki diğer işlemlerin tamamlanmasından önce mevcut değerler üzerinde çalışır.
  • ?ve !esolangs.org adresinde bulunan spesifikasyondan farklı şekilde çalıştığından, bu yayında sağlanan biraz değiştirilmiş yorumlayıcıyla test ettiğinizden emin olun.

Girdi şunlara sahiptir:

  • Eşleşen parantezler
  • Bir sütunda birden fazla parantez yok
  • Her satırda aynı sayıda karakter
  • En az bir satır
  • Birden fazla G / Ç ( !veya ?) talimatı olan sütun yok
  • Her ses için talimatlardan sonra bir satır besleme karakteri
  • Yukarıda belirtilenlerden başka karakter yok

Çıkış dili: Befunge-93

Befunge, program sayacı (PC; geçerli talimatın bir işaretçisi) iki boyutlu bir ızgarada serbestçe hareket eden yığın tabanlı bir dildir. Sol üst köşeden başlayarak sağa doğru hareket eder. Oyun alanı toroidaldir, yani PC hareketi her iki kenarı da sarar. Befunge ayrıca sonsuz sayıda sıfır değerine başlatılan bir yığını da içerir. Befunge aşağıdaki işlemlere sahiptir:

Befunge-93 derleyicisinin / yorumlayıcısının aşağıdaki özelliklerini varsayabilirsiniz:

  • Tamsayılar sınırsız hassasiyettedir.
  • Her boyutta ızgaraya izin verir.
  • Izgara koordinatları ( gve için p) 0 tabanlıdır.

puanlama

Befunge'de bir Prelude yorumlayıcısı üreten ve Prelude kaynağını buna kodlayan gönderimleri önlemek için amaç, ortaya çıkan Befunge kaynak kodunun boyutunu en aza indirmektir.

Aşağıda bir dizi Prelude programı verilmiştir. Çevirmeniniz bunların hepsinde çalışacaktır. Puanınız, hepsi geçerli olması koşuluyla, Befunge programlarının boyutlarının toplamıdır.

Tercümanınız özellikle bu test senaryolarına göre optimize edilmemelidir (örneğin, bunlar için elle yazılmış Befunge programlarını kodlayarak). Bunun herhangi bir cevabından şüphelenirsem, girdileri değiştirme veya ilave giriş yapma hakkımı saklı tutarım.

Örnek Girişler

n-1Aşağıya yazdırın 0:

?(1-^!)

Mantıksal VE:

?  (0)  
 ?(0  ) 
    1  !

Mantıksal VEYA:

 ?   (0) 
? (0)    
   1  1 !

Negatif olmayan sayının giriş paritesini (yani modulo 2) kontrol edin:

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

Girdinin karesini alın:

 ^    
  ^+ !
?(1-) 

Baskı n Fibonacci sayısı, inci burada n = 00 karşılık gelir ve n = 11 karşılık gelir:

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

İşaret:

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

Negatif olmayan girişler için bölüm:

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

Elbette, örnek programın negatif sayılar için davranışı belirtilmemiş olsa bile, programınızın tüm durumlar için aynı davranışı göstermesi gerekir.

Son olarak, çevirmeniniz mantıksızca uzun olmamalıdır:

  • Bir Stack Exchange gönderisinin içinde bulunmalıdır
  • Tipik bir masaüstü bilgisayarda örnek girişlerini 10 dakikadan daha kısa sürede işlemelidir.

Prelude veya Befunge için sayısal bir girişin isteğe bağlı eksi işareti ve ardından bir veya daha fazla ondalık basamak ve ardından bir satırsonu olarak verildiğini unutmayın. Diğer girdi tanımsız davranıştır.

Çevirmeninizi herhangi bir dilde yazabilirsiniz. En kısa tercüme edilen Befunge kodu kazanır.

Liderler Sıralaması

  • Sp3000 : 16430 bayt

Anlamıyorum: "Yukarıdaki ses yığınında üst değeri yığının üzerine itin." Mu olması için vardır: "Push yığını üzerine en üst değer arasında yukarıdaki ses istifi".
Def

Başlangıçta seslerin eşzamanlı olarak yürütüldüğü, bu gerçekten ayrı bir iş parçacığında yürütüldükleri veya tüm seslerde ilk komutları (yukarıdan aşağıya) sonra ikinci komutları vb.
Def

@Deformyer Ben "on" dan "of" olarak değiştirdim, ama "yığın üst değeri" de yanlış olmadığını düşündüm. Eşzamanlılığa gelince, hayır onları aslında paralel olarak yorumlamanıza gerek yoktur. Önemli olan, hepsinin yığınların önceki durumuna etki etmesi ve belirli bir sütundaki hiçbir işlemin o sütundaki diğer işlemleri etkilememesi.
Martin Ender

Birkaç test durumu "Birden fazla G / Ç (! Veya?) Komutuna sahip sütun yok mu?"
Fuwjax

@proudhaskeller 1Bir döngünün içindedir, bu yüzden itilmeyebilir . 0, yığınlarda başlayan sonsuz miktarda 0'dan gelebilir.
feersum

Yanıtlar:


10

Python 3, daha sonra gol atacak

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()))

Gibi koş py -3 prefunge.py <input filename> <output filename>.

Benim için yavaş bir hafta oldu, bu yüzden bu altı aylık soruyu çözmek için yeterince sıkıldım. Neden başka kimsenin denemediğini soracağım, ama yine de ağrının hata ayıklama hissini hissediyorum (ve muhtemelen bildiğim her şey için hala hatalar var).

Kullandığım bu yüzden soru, bir Befunge-93 tercüman sağlamaz bu bir spec den biraz farklıdır. İki temel fark şunlardır:

  • Programın belirli bir satırında bir karakter yoksa, o satıra yazamazsınız. Bu , sonunda yeterince yeni satır tanıtmak için Enter tuşuna birkaç kez basmanız gerektiği anlamına gelir . NaNÇıktıda s görürseniz , bu en olası nedendir.

  • Izgara hücreleri sıfıra önceden başlatılmamıştır - kolaylık sağlamak için Befunge çıktılarına bazı önceden başlatmalar ekledim, ancak gerekli olmadığından puanlamaya başladığımda alabilirim.

Çıktı programlarının temel düzeni şudur:

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

Yığın alanı programın dışındadır, bu nedenle daha önce gelen yeni satır Enter-spaming yorumu.

Ana fikir, her bir sese yığını olarak hizmet eden bir satır atamaktır. Bu yığınları korumak için, her bir yığının uzunluğunun sıra boyunca bir hücreye kaydedildiği özel bir yığın uzunluğu satırımız da vardır. Program daha sonra birçok gets ve puts, örneğin yazdırma işlemi için:

  • Şu hücreyi alın: y = stack_row[stack], x = stack_length[stack]
  • .91+,Tam sayı olarak gerçekleştirin , ardından yeni satır yazdırın
  • Yukarıdaki koordinatlardaki hücreyi 0 ile değiştirin (patlamayı simüle etmek için)
  • azalma stack_length[stack]

Bir sütunun eşzamanlı değerlendirmesini yapmak için, gerekli tüm hücreler okunur ve değerleri herhangi bir hücreye yazılmadan önce yığının üzerinde tutulur (örneğin yazdırma örneği için, birinci ve ikinci adımlar arasında daha fazla talimat olabilir).

`, bundan daha büyük olan, yığın uzunluklarının hiçbir zaman negatif olmamasını sağlamak ve yığın boşken 0'ları itmek için kullanılır. Bu, açıkça görülebilen dallanmanın geldiği yerdir, ancak dallanmayı kaldıracak bir fikrim var, bu da birinci ve üçüncü satırlardan çok fazla boşluk kaldırmalıdır.

Döngüler için, Prelude döngüleri her iki yönde de atlayabildiğinden, böyle bir yapılandırmada döngü başına iki satır kullanırız:

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

        ^                     <
       >                       ^

Bu döngüler şu anda baytların çoğunluğunu oluşturuyor, ancak pçevirmenin doğru çalıştığından memnun kaldıktan sonra yapmayı planladığım kod kutusuna yerleştirerek kolayca golf oynayabilir .

İşte bazı örnek çıktısı var ?(1-^!)yani baskı, n-1aşağı 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^
                              ^                                                                                                                                <
                             >                                                                                                                                  ^

Kare-girişi:

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^
                                                             ^                                                                                                                                                  <
                                                            >                                                                                                                                                    ^

Bölme (küçük girişler önerilir):

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  ^
                                                                                  ^                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <
                                                                                 >                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ^
                                                                                                                                                                                                                                                                                                          ^                                                                        <
                                                                                                                                                                                                                                                                                                         >                                                                          ^
                                                                                                                                                                                                                                                                                                                                                                                                                    ^                                                                                                                                                                                                                                                                                                                                              <
                                                                                                                                                                                                                                                                                                                                                                                                                   >                                                                                                                                                                                                                                                                                                                                                ^

Akla gelen, yerine koymak gibi bir sürü küçük optimizasyon da 07p07gvar :07p, ama bunu her seferinde bir adım atıyorum :)


Yani. Çok. Bedava. Zaman.
Doktor

1
Will score later2 yıl ve artıyor! :)
HyperNeutrino
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.