Tłumacz znormalizowany z Malbolge na Malbolge

12

W tym zadaniu napiszesz program / funkcję, która pobiera znormalizowany program Malbolge i wyświetla wynikowy program Malbolge . (To tajne narzędzie, z którego korzystają wszyscy programiści Malbolge!)

Wejście

Struktura danych, która (jakoś) reprezentuje znormalizowany program Malbolge.

Wynik

Struktura danych reprezentująca wynikowy program Malbolge.

Przykłady

jpoo*pjoooop*ojoopoo*ojoooooppjoivvvo/i<ivivi<vvvvvvvvvvvvvoji
(=BA#9"=<;:3y7x54-21q/p-,+*)"!h%B0/.~P<<:(8&66#"!~}|{zyxwvugJ%

jjjj*<jjjj*<v
('&%#^"!~}{XE

jjjjjjjjjjjjjjjjjjjjjjj*<jjjjjjjjjjjjjjjjjjjjjjjj*<v
('&%$#"!~}|{zyxwvutsrqpnKmlkjihgfedcba`_^]\[ZYXWVT1|

Jak konwertować

Powtórz znormalizowany program Malbolge, wykonując następujące kroki dla każdego znaku:

  1. Zamień znaki w ciągu *jpovi</na odpowiedni znak w '(>DQbcu. (Oznacza to, że mapa *do ', jdo (, i tak dalej).

  2. Następnie odejmij bieżącą pozycję licznika programu (tj. Liczbę znaków przed bieżącą) od kodu ASCII znaku.

  3. Jeśli wynikowy kod ASCII jest mniejszy niż 33, zwiększ go o 94 i powtarzaj, aż będzie to co najmniej 33.

  4. Dołącz wynikowy znak do wyniku.

Zasady

Ilmari Karonen
źródło
4
Czy dane wejściowe zawierają tylko znaki z „ *jpovi</”?
Joel
7
Nie rozumiem co „W takim razie minus pozycja”. znaczy. Prawdopodobnie mógłbym to zrozumieć na podstawie pseudokodu, ale wyjaśnienie powinno być samodzielne.
xnor
1
Podczas gdy kod ASCII tymczasowych reprezentacji Malbolge jest mniejszy niż 33, należy zwiększyć znak o 94. ” Co przez to rozumiesz? Zrozumiałem wyzwanie: 1) mapowanie postaci; 2) przekonwertować na wartość Unicode; 3) zmniejszaj każdy według licznika programu (mamy teraz tak zwany „tymczasowy kod ASCII reprezentacji Malbolge”); 4) jeżeli jakakolwiek wartość jest mniejsza niż 33, zwiększ ją o 94; 5) przekonwertuj te wartości z powrotem na znaki. Ale stosując to podejście, wynik wyraźnie nie jest poprawny. Czy możesz wyjaśnić, co masz na myśli, jeśli chodzi o dane wejściowe dłuższe niż 33 znaki?
Kevin Cruijssen
1
a: if ascii_code(temporary Malbolge representation) < 33: char := char + 94; goto a;
1
Z radością dam nagrodę każdemu, kto może napisać jedną z tych rzeczy w Malbolge :)
JDL

Odpowiedzi:

4

Galaretka , 29 22 bajtów

Oị“%þV DCµ2®  ‘_JịØṖḊ¤

Wypróbuj online!

Monadyczny link przyjmujący łańcuch Jelly jako argument i zwracający łańcuch Jelly.

Dzięki @JonathanAllan za uratowanie 2 bajtów!

Wyjaśnienie

O                      | Convert to Unicode code points
 ị“%þV DCµ2®  ‘        | Index into compressed integer list [37, 31, 86, 32, 68, 67, 9, 50, 8, 32, 32] (note the 32s are never actually used because the input mod 11 will be one of 1,2,3,5,6,7,8,9)
               _J      | Subtract position of character in original string
                 ị   ¤ | Index into the following as a nilad:
                  ØṖ   | - Printable ASCII characters
                    Ḋ  | - With the first character (space) removed
Nick Kennedy
źródło
..._J‘ịØṖḊ¤oszczędza jeden bajt.
Jonathan Allan
@JonathanAllan dzięki, dobry telefon!
Nick Kennedy
2
och, i możemy zwiększyć wewnątrz naszego wyszukiwania>. < oszczędzając kolejny bajt:Oị“%þV DCµ2® ‘_JịØṖḊ¤
Jonathan Allan
6

Python 3 , 82 bajty

p=0
for c in input():print(end=chr((b"de{#0ABT"["*jpovi<".find(c)]-p)%94+33));p+=1

Wypróbuj online!

Dzięki @Joel za zastąpienie brzydkich znaków niedrukowalnych w bajtowaniu znakami drukowalnymi.

Szukam łańcucha modów do zastąpienia "*jpovi<".find(c), ale nie sądzę, aby istniał taki, który jest krótszy, a niewyczerpane poszukiwanie siły brutalnej niczego dotąd nie znalazło.

82 bajty

f=lambda s,p=0:s and chr((b"de{#0ABT"["*jpovi<".find(s[0])]-p)%94+33)+f(s[1:],p+1)

Wypróbuj online!

xnor
źródło
Niedrukowalne znaki ASCII można przesunąć o 94, aby przekształcić je w znaki drukowalne dla lepszej czytelności.
Joel
Możesz spróbować znaleźć funkcję matematyczną, która zastąpiłaby mapowanie, b"de{#0ABT"["*jpovi<".find(c)]jeśli masz do tego program.
Joel
1
@Joel Niestety, myślę, że mapowanie jest zbyt szeroką przestrzenią poszukiwań dla funkcji arytmetycznej, przynajmniej przy pomocy posiadanych przeze mnie narzędzi. I właśnie zostały poszukiwania Modulo łańcuchy jak x%84%15%7na prawej połowie mapowania, ale myślę, że mogę recyklingu jakiś kod, który napisałem na kolejne wyzwanie do poszukiwania w tym *i /warunki.
xnor
@Joel Nie znajduję nic w stylu łańcucha modów dla prawej strony %i *( //w Pythonie 3 prawdopodobnie nie warto). W rzeczywistości nic nie pasowało do pierwszych 6 z 7 wartości. Miałem nadzieję, że to zadziała, ponieważ przybliżona ocena entropii mówi, że prawdopodobnie jest wystarczająco dużo wyrażeń kończących się na% 7`, ale jest blisko. I może te łańcuchy dają wyniki dalekie od równomiernie rozłożonych, zwłaszcza, że ​​gdy dwa wejścia zapadną się do tej samej wartości, żadne dalsze operacje nie mogą ich rozdzielić. Rzeczy, których próbuję, są nadal zbyt głupie, aby szukać większego wyrażenia, ale jeśli masz jakieś pomysły, skorzystaj z nich.
xnor
Myślę, że lepszy algorytm jest prawdopodobnie potrzebny do takich arbitralnych danych wejściowych map(ord, "*jpovi<"). Jeśli dane wyjściowe nie zachowują porządku dla większości danych wejściowych (tj. f(m)>=f(n)Jeśli m>=n), niektóre starannie spreparowane stałe są %i *prawdopodobnie są potrzebne, a przeszukiwanie metodą brutalnej siły raczej nie przyniesie pozytywnego wyniku.
Joel
6

Malbolge Unshackled (wariant rotacji 20-trytów), 7,784e6 bajtów

Rozmiar tej odpowiedzi przekracza maksymalny rozmiar programu do wysłania (eh), więc kod znajduje się w moim repozytorium GitHub .

Jak to uruchomić?

Może to być trudna część, ponieważ naiwny tłumacz Haskell będzie wieków na wieki, aby to uruchomić. TIO ma przyzwoitego interpretera Malbogle Unshackled, ale niestety nie będę mógł go używać (ograniczenia).

Najlepszy, jaki udało mi się znaleźć, to stały wariant szerokości rotacji 20-trytów, który działa bardzo dobrze, przekształcając 0,5 znaków na sekundę .

Aby nieco przyspieszyć tłumacza, usunąłem wszystkie kontrole z nieskrępowanego tłumacza Matthiasa Luttera.

Moja zmodyfikowana wersja może działać o około 6,3% szybciej.

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* translation = "5z]&gqtyfr$(we4{WP)H-Zn,[%\\3dL+Q;>U!pJS72Fh"
        "OA1CB6v^=I_0/8|jsb9m<.TVac`uY*MK'X~xDl}REokN:#?G\"i@";

typedef struct Word {
    unsigned int area;
    unsigned int high;
    unsigned int low;
} Word;

void word2string(Word w, char* s, int min_length) {
    if (!s) return;
    if (min_length < 1) min_length = 1;
    if (min_length > 20) min_length = 20;
    s[0] = (w.area%3) + '0';
    s[1] = 't';
    char tmp[20];
    int i;
    for (i=0;i<10;i++) {
        tmp[19-i] = (w.low % 3) + '0';
        w.low /= 3;
    }
    for (i=0;i<10;i++) {
        tmp[9-i] = (w.high % 3) + '0';
        w.high /= 3;
    }
    i = 0;
    while (tmp[i] == s[0] && i < 20 - min_length) i++;
    int j = 2;
    while (i < 20) {
        s[j] = tmp[i];
        i++;
        j++;
    }
    s[j] = 0;
}

unsigned int crazy_low(unsigned int a, unsigned int d){
    unsigned int crz[] = {1,0,0,1,0,2,2,2,1};
    int position = 0;
    unsigned int output = 0;
    while (position < 10){
        unsigned int i = a%3;
        unsigned int j = d%3;
        unsigned int out = crz[i+3*j];
        unsigned int multiple = 1;
        int k;
        for (k=0;k<position;k++)
            multiple *= 3;
        output += multiple*out;
        a /= 3;
        d /= 3;
        position++;
    }
    return output;
}

Word zero() {
    Word result = {0, 0, 0};
    return result;
}

Word increment(Word d) {
    d.low++;
    if (d.low >= 59049) {
        d.low = 0;
        d.high++;
        if (d.high >= 59049) {
            fprintf(stderr,"error: overflow\n");
            exit(1);
        }
    }
    return d;
}

Word decrement(Word d) {
    if (d.low == 0) {
        d.low = 59048;
        d.high--;
    }else{
        d.low--;
    }
    return d;
}

Word crazy(Word a, Word d){
    Word output;
    unsigned int crz[] = {1,0,0,1,0,2,2,2,1};
    output.area = crz[a.area+3*d.area];
    output.high = crazy_low(a.high, d.high);
    output.low = crazy_low(a.low, d.low);
    return output;
}

Word rotate_r(Word d){
    unsigned int carry_h = d.high%3;
    unsigned int carry_l = d.low%3;
    d.high = 19683 * carry_l + d.high / 3;
    d.low = 19683 * carry_h + d.low / 3;
    return d;
}

// last_initialized: if set, use to fill newly generated memory with preinitial values...
Word* ptr_to(Word** mem[], Word d, unsigned int last_initialized) {
    if ((mem[d.area])[d.high]) {
        return &(((mem[d.area])[d.high])[d.low]);
    }
    (mem[d.area])[d.high] = (Word*)malloc(59049 * sizeof(Word));
    if (!(mem[d.area])[d.high]) {
        fprintf(stderr,"error: out of memory.\n");
        exit(1);
    }
    if (last_initialized) {
        Word repitition[6];
        repitition[(last_initialized-1) % 6] =
                ((mem[0])[(last_initialized-1) / 59049])
                    [(last_initialized-1) % 59049];
        repitition[(last_initialized) % 6] =
                ((mem[0])[last_initialized / 59049])
                    [last_initialized % 59049];
        unsigned int i;
        for (i=0;i<6;i++) {
            repitition[(last_initialized+1+i) % 6] =
                    crazy(repitition[(last_initialized+i) % 6],
                        repitition[(last_initialized-1+i) % 6]);
        }
        unsigned int offset = (59049*d.high) % 6;
        i = 0;
        while (1){
            ((mem[d.area])[d.high])[i] = repitition[(i+offset)%6];
            if (i == 59048) {
                break;
            }
            i++;
        }
    }
    return &(((mem[d.area])[d.high])[d.low]);
}

unsigned int get_instruction(Word** mem[], Word c,
        unsigned int last_initialized,
        int ignore_invalid) {
    Word* instr = ptr_to(mem, c, last_initialized);
    unsigned int instruction = instr->low;
    instruction = (instruction+c.low + 59049 * c.high
            + (c.area==1?52:(c.area==2?10:0)))%94;
    return instruction;
}

int main(int argc, char* argv[]) {
    Word** memory[3];
    int i,j;
    for (i=0; i<3; i++) {
        memory[i] = (Word**)malloc(59049 * sizeof(Word*));
        if (!memory) {
            fprintf(stderr,"not enough memory.\n");
            return 1;
        }
        for (j=0; j<59049; j++) {
            (memory[i])[j] = 0;
        }
    }
    Word a, c, d;
    unsigned int result;
    FILE* file;
    if (argc < 2) {
        // read program code from STDIN
        file = stdin;
    }else{
        file = fopen(argv[1],"rb");
    }
    if (file == NULL) {
        fprintf(stderr, "File not found: %s\n",argv[1]);
        return 1;
    }
    a = zero();
    c = zero();
    d = zero();
    result = 0;
    while (!feof(file)){
        unsigned int instr;
        Word* cell = ptr_to(memory, d, 0);
        (*cell) = zero();
        result = fread(&cell->low,1,1,file);
        if (result > 1)
            return 1;
        if (result == 0 || cell->low == 0x1a || cell->low == 0x04)
            break;
        instr = (cell->low + d.low + 59049*d.high)%94;
        if (cell->low == ' ' || cell->low == '\t' || cell->low == '\r'
                || cell->low == '\n');
        else if (cell->low >= 33 && cell->low < 127 &&
                (instr == 4 || instr == 5 || instr == 23 || instr == 39
                    || instr == 40 || instr == 62 || instr == 68
                    || instr == 81)) {
            d = increment(d);
        }
    }
    if (file != stdin) {
        fclose(file);
    }
    unsigned int last_initialized = 0;
    while (1){
        *ptr_to(memory, d, 0) = crazy(*ptr_to(memory, decrement(d), 0),
                *ptr_to(memory, decrement(decrement(d)), 0));
        last_initialized = d.low + 59049*d.high;
        if (d.low == 59048) {
            break;
        }
        d = increment(d);
    }
    d = zero();

    unsigned int step = 0;
    while (1) {
        unsigned int instruction = get_instruction(memory, c,
                last_initialized, 0);
        step++;
        switch (instruction){
            case 4:
                c = *ptr_to(memory,d,last_initialized);
                break;
            case 5:
                if (!a.area) {
                    printf("%c",(char)(a.low + 59049*a.high));
                }else if (a.area == 2 && a.low == 59047
                        && a.high == 59048) {
                    printf("\n");
                }
                break;
            case 23:
                a = zero();
                a.low = getchar();
                if (a.low == EOF) {
                    a.low = 59048;
                    a.high = 59048;
                    a.area = 2;
                }else if (a.low == '\n'){
                    a.low = 59047;
                    a.high = 59048;
                    a.area = 2;
                }
                break;
            case 39:
                a = (*ptr_to(memory,d,last_initialized)
                        = rotate_r(*ptr_to(memory,d,last_initialized)));
                break;
            case 40:
                d = *ptr_to(memory,d,last_initialized);
                break;
            case 62:
                a = (*ptr_to(memory,d,last_initialized)
                        = crazy(a, *ptr_to(memory,d,last_initialized)));
                break;
            case 81:
                return 0;
            case 68:
            default:
                break;
        }

        Word* mem_c = ptr_to(memory, c, last_initialized);
        mem_c->low = translation[mem_c->low - 33];

        c = increment(c);
        d = increment(d);
    }
    return 0;
}

To działa!

To działa

Krzysztof Szewczyk
źródło
2
To jest po prostu szalone.
MilkyWay90
Dla przechodniów liczba bajtów wynosi 7,784 MB, a nie 7,784 GB. Zinterpretowałem przecinek jako początkowo grupujący tysiące, a nie przecinek dziesiętny.
Potato44
@ Potato44 używamy przecinka jako separatora dziesiętnego w Polsce, używanie kropki jako takiej jest zabronione.
Krzysztof Szewczyk
5

Python 3 , 84 83 bajty

f=lambda p,i=0:p and chr(126-(i+b"WV@:-zyg"["*jpovi<".find(p[0])])%94)+f(p[1:],i+1)

Wypróbuj online!

Jest to głównie problem matematyczny dotyczący uproszczenia obliczeń, a także trochę gry w golfa po wykonaniu matematyki. Wersja bez golfa pokazana jest poniżej.

Wersja bez golfisty, nierekurencyjna

def convert(prog):
    offsets = dict(zip("*jpovi</", [87, 86, 64, 58, 45, 122, 121, 103]))  # ASCII encoded to "WV@:-zyg"
    output = ""
    for pos, c in enumerate(prog):
        output += chr(126-(offsets[c]+pos)%94)
    return output

Wypróbuj online!

Joel
źródło
5

JavaScript (Node.js) , 69 bajtów

s=>(B=Buffer)(s).map((c,i)=>33+(B(" #{T BAe0d")[c%11]+94-i%94)%94)+''

Wypróbuj online!

W jaki sposób?

[1..9]11

 char. | ASCII code | mod 11
-------+------------+--------
  '*'  |      42    |   9
  'j'  |     106    |   7
  'p'  |     112    |   2
  'o'  |     111    |   1
  'v'  |     118    |   8
  'i'  |     105    |   6
  '<'  |      60    |   5
  '/'  |      47    |   3
Arnauld
źródło
3

05AB1E , 32 31 23 22 bajtów

žQ¦•4¡ˆ¶ü]₁η₃•₃вIÇèā-è

-8 bajty tworząc port NickKennedy „s Jelly odpowiedzi , więc upewnij się, aby go upvote !!
-1 bajt dzięki @Grimy.

Wyjście w postaci listy znaków.

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

   4¡ˆ¶ü]₁η₃•          # Push compressed integer 82767635194143615015
              ₃в        # Converted to base-95 as list: [1,36,30,85,0,67,66,8,49,7,0]
                IÇ      # Push the input and convert each character to its unicode value
                  è     # Index each into the list we created
                   ā    # Push an integer list in the range [0, length] 
                        # (without popping the list itself)
                    -   # Subtract it from the previous list
žQ                      # Push builtin with all printable ASCII characters,
  ¦                     # and remove the leading space
                     è  # Index the values of the list into the ASCII characters
                        # (after which the result is output implicitly)

Zobacz moją wskazówkę 05AB1E (sekcja Jak kompresować duże liczby całkowite? I Jak kompresować listy liczb całkowitych? ), Aby zrozumieć, dlaczego •4¡ˆ¶ü]₁η₃•jest 82767635194143615015i •4¡ˆ¶ü]₁η₃•₃вjest [1,36,30,85,0,67,66,8,49,7,0].

Kevin Cruijssen
źródło
•1ÃQWý₂Ýδ9•86в->•4¡ˆ¶ü]₁η₃•₃в
Grimmy
@Grimy Thanks :)
Kevin Cruijssen
2

Perl 5 ( -p), 53 , 51 bajtów

oszczędzając 2 bajty, używając de{#0ABTzamiast '(>DQbcu, aby 61nie było już potrzebne

y;*jpovi</;de{#0ABT;;s/./chr 33+(-"@-"+ord$&)%94/ge

TIO

pierwsza odpowiedź brzmiała

y;*jpovi</;'(>DQbcu;;s/./chr 33+(61-"@-"+ord$&)%94/ge

TIO

Nahuel Fouilleul
źródło
2

Japt , 24 23 bajty

Rozwiązanie Port of Nick's Jelly

;£EÅgYn" #T BA0 "cXc

Spróbuj

;£EÅgYn"..."cXc     :Implicit input of string
 £                  :Map each character X at 0-based index Y
; E                 :ASCII
   Å                :Slice of the first character (space)
    g               :Get character at index
     Y              :  Increment Y
      n             :  Subtract from
       "..."        :    Literal string (Codepoints: 32,35,29,84,32,66,65,7,48,6,32)
            c       :    Codepoint at index
             Xc     :      Codepoint of X
Kudłaty
źródło
1

Retina 0.8.2 , 50 bajtów

T`*j\p\ovi</`'(>DQbcu
.
$.`$* $&¶
+T`!p`~_p` .¶
¶

Wypróbuj online! Link zawiera przypadki testowe. Wyjaśnienie:

T`*j\p\ovi</`'(>DQbcu

Dokonaj transliteracji zgodnie z opisem w pytaniu. p(opisane poniżej) i omają specjalne znaczenie do Twymazywania, więc należy je zacytować.

.
$.`$* $&¶

Podaj każdy znak w osobnym wierszu, poprzedzony liczbą spacji zgodnie z jego indeksem, tj. Tym, jaki byłby licznik programu.

+T`!p`~_p` .¶

Wielokrotnie cyklicznie zmniejszaj ostatni znak w każdym wierszu, usuwając za każdym razem poprzednią spację, aż wszystkie spacje zostaną usunięte. Te pstojaki dla druku ASCII czyli -~jednak chcemy, !aby na mapie, aby ~tak, że najpierw jest transliteracji, a następnie _powoduje, że przestrzeń w meczu który ma zostać usunięty, a pozostałe znaki uzyskać transliteracji jeden kod znaku naraz.

Połącz ponownie wszystkie postacie.

Neil
źródło
1

Węgiel , 23 bajty

⭆S§Φγμ⁻℅§ #{T BAe0d ℅ικ

Wypróbuj online! Link jest do pełnej wersji kodu. Port odpowiedzi JavaScript na @ Arnauld. Wyjaśnienie:

 S                      Input string
⭆                       Map over characters and join
                     ι  Current character
                    ℅   ASCII code
        §               Cyclically indexed into
          #{T BAe0d     Literal string ` #{T BAe0d `
       ℅                ASCII code
      ⁻                 Subtract
                      κ Current index
  §                     Cyclically indexed into
    γ                   Printable ASCII
   Φ                    Filtered on
     μ                  Inner index (i.e. skip initial space)
                        Implicitly print
Neil
źródło
1

Haskell , 135 bajtów

t=h"*jpovi</"(fromEnum<$>"'(>DQbcu")
h(x:m)(y:n)i|i==x=y|1<2=h m n i
a n|n<33=a(n+94)|1<2=n
f=(toEnum.a<$>).(zipWith(+)[0,-1..]).(t<$>)

Wypróbuj online!

David
źródło