Napisz tłumacza pieprzonego mózgu


18

W dowolnym języku programowania lub skryptowym x napisz program, który pobiera prawidłowy kod źródłowy skoku mózgowego ze standardowego wyjścia i wyjścia, do standardowego kodu źródłowego programu napisanego w języku x , który wygenerowałby dokładnie to samo, co zrobiłby ten program.

Twój program musi działać dla każdego prawidłowego programu do pieprzenia mózgu, w tym pustego pliku.

Twój wynik byłby równy liczbie bajtów kodu źródłowego oraz liczbie bajtów danych wyjściowych przy następujących danych wejściowych:

+++++ [-]
+++++ +++++ [
    > +++++ ++
    > ++ +++ ++++ +
    > +++
    <<< -
]
> ++ . H
> + . e
++ +++ ++. l
. l
+++ . o
> ++ . space
< +++++ +++ . w
----- --- . o
+++ . r
---- - - . l
----- --- . d
> + . exclamation mark
------lol; useless code :-)--------------------------[.............................................][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]<-<<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><

Na przykład dla wejścia [-]wartość wyjściowa *p=0;jest znacznie bardziej korzystna niżwhile(*p) *p--;

Jeśli zdarzy ci się używać znaków spoza ASCII, liczbę bajtów należy obliczyć przy użyciu kodowania UTF-8.

Najniższy wynik wygrywa. Jednak kreatywne rozwiązania, które próbują zminimalizować wyniki, będą zachęcane przez entuzjastów.


11
Możesz dodać klauzulę, że językiem docelowym też nie jest pieprzenie mózgów;)
Josh

@Josh cóż, jeśli komuś udało się napisać krótki program do pieprzenia mózgu, który usuwa niepotrzebne niepotrzebne kody, dlaczego nie pozwolić mu tego zrobić?
user12205

2
Cóż, po prostu dlatego, że trywialne rozwiązanie przekazywania niezmienionego źródła i tak będzie miało naprawdę niski wynik za pieprzenie mózgu. Będę zaskoczony, jeśli inny język da sobie radę.
Tim Seguine

@Tim Seguine Mógłbym zmienić pytanie, ale czy byłoby to niesprawiedliwe wobec tych, którzy już udzielili odpowiedzi? A jeśli zmienię pytanie, myślę o zmianie sposobu obliczania wyniku byte count of source + (byte count of output)^2, czy to zachęciłoby ludzi do większego skupienia się na uproszczeniu wyników?
user12205

Zasadniczo zmiana takiego pytania po udzieleniu odpowiedzi jest niezadowolona. Właśnie wskazałem powód, dla którego uważam, że Josh miał rację. Dobrze jest najpierw umieszczać takie rzeczy w piaskownicy, abyś mógł rozwiązywać potencjalne problemy, zachowując przy tym sprawiedliwość wobec wszystkich.
Tim Seguine

Odpowiedzi:


12

Perl - 177 (źródło) + 172 (wyjście) = 349

#!perl -p0
y/-+><.,[]
-~/p-w/d;s/(.)\K\1+|rs|wv[^v]*(?=w)/$+&&length$&/ge;$_="eval'r$_'=~".'s/.(\d*)/(qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&&v63].q($i;))x($++1)/ger'

Licząc shebang jako 2 bajty, po jednym dla każdej opcji. Po pierwsze, każde z ośmiu poleceń jest tłumaczone na zakres p-w, jednocześnie usuwając wszystkie pozostałe znaki. Łańcuch ten jest następnie kodowany i uruchamiany przy użyciu minimalnego dekodera / interpretera. Kilka rzeczy zostało zoptymalizowanych: łańcuch ><oczywiście nic nie robi, a pętla for, która następuje bezpośrednio po innej, może zostać całkowicie usunięta, ponieważ nigdy nie zostanie wprowadzona.

Dane wyjściowe dla programu testowego:

eval'rq4vpwq9vrq6rq9rq2s2pwrq1trqtq6t1q2trq1tsq7tp7tq2tp5tp7trqtp32vt44wsps1'=~s/.(\d*)/(qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&&v63].q($i;))x($++1)/ger

Przykładowy przebieg:

$ perl brainfusk.pl < in.bf | perl
Hello world!

Perl - 232 (źródło) + 21 (wyjście) = 253

#!perl -p0
y/-+><.,[]
-~/0-7/d;$_="eval'2$_'=~".'s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger';
/5/||fork?(wait,$?||exit):($SIG{ALRM}=sub{exit 1},alarm 9,$S=select(open 1,'>',\$o),eval,print$S "print\"\Q$o\E\"")

Ten opiera się na spostrzeżeniu FIQ , że jeśli oryginalny program nie zawiera instrukcji wejściowej, wynik będzie statyczny, a zatem może zostać zredukowany do pojedynczej printinstrukcji. Jeśli ci się podoba, pamiętaj, aby dać jego odpowiedź +1.

Więc co możemy zrobić, to potokować stdoutdo zmiennej, evalkod, który otrzymalibyśmy, i zawinąć wynik w print.

... to jednak nie zawsze zadziała. Ilekroć kod do przetłumaczenia spowodowałby nieskończoną pętlę (np. +[.]), Z oczywistych powodów nie można tego zredukować do pojedynczej printinstrukcji. Zamiast tego uruchamiamy evalproces potomny z krótkim limitem czasu, a jeśli nie zakończy się on w tym czasie, wysyłamy przetłumaczony program jak poprzednio.

Zorganizowany i skomentowany:

if(!/5/) { # no `,` in program

  if(fork) { # parent process

    # wait for child
    wait;
    # no child error, terminate without output
    $?||exit

  } else { # child process

    # alarm handler, exit with error
    $SIG{ALRM}=sub{exit 1};
    # set an alarm in 9 seconds
    alarm 9;
    # redirect STDOUT to variable $o
    $S=select open 1,'>',\$o;
    # execute translated code
    eval;
    # wrap the result in a print statement
    print$S "print\"\Q$o\E\""
  }
}

Dane wyjściowe dla przykładowego programu:

print"Hello\ world\!"

Dane wyjściowe dla ,[.]:

eval'25647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger

Wyjście dla +[.](po 9 sekundach):

eval'21647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger

1
To jest niesamowite! Mózg boli :)
Timwi

Myślę, że wv.*?(?=w)jest źle. Myślę, że usunie tylko kod do następnego ], ale potrzebujesz go, aby znaleźć pasujące ] ; musisz zadbać o zagnieżdżanie ...
Timwi

@Timwi Naprawiono, ignorując zagnieżdżone przypadki wv[^v]*(?=w), które są znacznie krótsze niż alternatywa.
primo

14

Brainfuck, 5 + 540 = 545 bajtów

5 bajtów kodu, 540 z danych wyjściowych danego pliku testowego (zakładając, że otrzymałem liczbę bezpośrednio z mojej pasty tego kodu).

,[.,]

Zakładając, że EOF wynosi 0.


@primo, ponieważ nie resetuje się przed odczytem interpretera, który nie zmienia wartości w EOF, sprawi, że ten program będzie nieskończoną pętlą dla wszystkich danych wejściowych większych niż 0 bajtów.
Sylwester

Nie mogę się zastanawiać, jakie oprogramowanie jest używane do uruchamiania tych rzeczy? xD
Teun Pronk

@TeunPronk Istnieje tłumacz pieprzony mózg o nazwie bfi ( github.com/susam/bfi ). Wystarczy go skompilować i zainstalować, a następnie uruchomić w następujący sposób: bfi input.bfgdzie input.bfnależy interpretować plik pieprzony mózg.
Braden Best

5

PHP, 553 + 27 = 580 bajtów

(Usunięto 553 bajtów ze wszystkimi białymi spacjami, tj. Znakami nowej linii i spacjami)

Źle podchodzę do gry w golfa w PHP, więc to podejście można mocno zoptymalizować. Chciałem przede wszystkim pokazać swoje podejście do rozwiązania w czymś innym niż BF.

<?php
echo "<?php ";
$x = 'if (!$b) $c = $_GET[c];
$x=$y=$n[0]=$p=0;$o[0]=1;$d="";
while($a=$c[$x++]){
    if($o[$p]){
        if($a=="-")$m[$y]--;
        if($a=="+")$m[$y]++;
        $m[$y]=$m[$y]%256;
        if($a=="<")$y--;
        if($a==">")$y++;
        if($a=="."){
            $e=chr($m[$y]);
            if ($b) echo $e;
            else $d.=addslashes($e);
        }
        if($a==",")$m[$y]=($b=$_GET[i])?ord($b):0;
    }if($a=="["){
        $p++;
        $n[$p]=$x-1;
        $o[$p]=$o[$p-1]?$m[$y]:0;
    }
    if($a=="]"){
        if($o[$p])$x=$n[$p];
        $p--;
        if($p=-1)$p=0;
    }
}
if (!$b) echo "echo \'$d\';";';
if (strstr($_GET['c'],",")) {
    $x = '$b=1;'.$x;
    echo '$c="'.addslashes($_GET[c]).'";'.$x;
    return;
}
eval($x);

Raportowanie błędów musi być wyłączone, w przeciwnym razie PHP cię nienawidzi. Sposób użycia: wyrzuć to jako stronę i uruchom za pomocą script.php? C = CODE (jeśli wynikowy skrypt wymaga danych wejściowych, uruchom go jako out.php? I = INPUT). Pamiętaj, aby URL uratować wejście!

To, co to robi, jest w zasadzie takie - jeśli skrypt BF zawiera „,”, to właściwie osadza się jako wynikowy skrypt z dołączonym $ b = 1; na górze. Jeśli NIE zawiera „,”, optymalizuje go do „echo <wyjście BF>”. Dogodnie skrypt testowy w PO NIE wymaga żadnych danych wejściowych. Addlasheshes () służy tylko do ucieczki 'i \.


4

C ++, 695 + 510 = 1205 bajtów

Kod:

#include<iostream>
#include<utility>
#include<vector>
#define D "\n#define "
using namespace std;using S=string;int main(){vector<pair<S,S>>m={{"--------","(*p)-=8;"},{"<>",""},{"[]","F;"},{"+","A;"},{"-","B;"},{">","C;"},{"<","D;"},{"[","F{"},{"]","}"},{".","E;"},{",","std::cin>>*p;"}};S s;char c;while(cin>>c)if(S("+-><[].,").find(c)<8)s+=c;for(int i=0;i<s.length();i++)if(s.substr(i,4)=="[][]")s=s.replace(i--,4,"[]");cout<<"#include<iostream>" D"A ++*p" D"B --*p" D"C p++" D"D p--" D"E std::cout<<*p" D"F while(*p)\nint main(){char*p=new char[1<<19]();";while(s.size())for(auto p:m)if(s.substr(0,p.first.length())==p.first){s=s.substr(p.first.length());cout<<p.second;break;}cout<<"}";}

Wynik:

#include<iostream>
#define A ++*p
#define B --*p
#define C p++
#define D p--
#define E std::cout<<*p
#define F while(*p)
int main(){char*p=new char[1<<19]();A;A;A;A;A;F{B;}A;A;A;A;A;A;A;A;A;A;F{C;A;A;A;A;A;A;A;C;A;A;A;A;A;A;A;A;A;A;C;A;A;A;D;D;D;B;}C;A;A;E;C;A;E;A;A;A;A;A;A;A;E;E;A;A;A;E;C;A;A;E;D;A;A;A;A;A;A;A;A;E;(*p)-=8;E;A;A;A;E;B;B;B;B;B;B;E;(*p)-=8;E;C;A;E;(*p)-=8;(*p)-=8;(*p)-=8;(*p)-=8;B;F{E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;E;}F;D;B;D;D;}

Oryginalny kod:

#include <iostream>
#include <utility>
#include <vector>
using namespace std;
int main() {
    vector<pair<string, string>> m={
    {"--------","(*p)-=8;"},
    {"<>",""},
    {"[]","F;"},
    {"+","A;"},
    {"-","B;"},
    {">","C;"},
    {"<","D;"},
    {"[","F{"},
    {"]","}"},
    {".","E;"},
    {",","std::cin>>*p;"}};
    string s;
    char c;
    while (cin >> c)
        if (string("+-><[].,").find(c) < 8)
            s += c;
    for(int i = 0; i < s.length(); i++)
        if(s.substr(i, 4) == "[][]")
            s = s.replace(i--, 4, "[]");
    cout << "#include<iostream>\n"
            "#define A ++*p\n"
            "#define B --*p\n"
            "#define C p++\n"
            "#define D p--\n"
            "#define E std::cout<<*p\n"
            "#define F while(*p)\n"
            "int main(){char*p=new char[1<<19]();";
    while (s.size())
        for (auto p : m)
            if (s.substr(0, p.first.length()) == p.first) {
                s = s.substr(p.first.length());
                cout << p.second;
                break;
            }
    cout << "}";
}

2

Python - 514 + 352 = 866

Kod:

import sys,zlib,base64
s,i="import sys\na,i=[0]*300000,0\n",0
for c in sys.stdin.read():
 if c in"+-><,.[]":
  s+=" "*i+{'+':"a[i]+=1\n",'-':"a[i]-=1\n",'>':"i+=1\n",'<':"i-=1\n",',':"a[i]=(lambda x:0if x==''else ord(x))(sys.stdin.read(1))\n",".":"sys.stdout.write(chr(a[i]))\n","[":"while a[i]!=0:\n","]":"pass\n"}[c]
  i+={'[':1,']':-1}.get(c,0)
print('import zlib,base64\nexec(zlib.decompress(base64.b64decode("'+base64.b64encode(zlib.compress(bytes(s,"utf8"),9)).decode("utf8")+'")).decode("utf8"))')

Wynik:

import zlib,base64
exec(zlib.decompress(base64.b64decode("eNrLzC3ILypRKK4s5krUybSNNojVMjYAAR0DrsTozFhtW0OCdHlGZk6qAoinaGtgxQVm6QLFFQoSi4uJNoVc2zJBggowWTIZVDGEEvMzddFJ1FDMxBYUwFjTKy5JyS8t0SsvyixJ1UjOKNIASWpqomrAp5DceMBnJjn2Ee0ZojToUiGlEfIFzA5yaGqHELXtp5XfMukVwMOFRi/u8IXZqOSo5KjkqOSIlAQ3k9BLy1HBUcFRwVFBOgpmIrfeMhGE9ihrpLEAudg3NA==")).decode("utf8"))

1

io

659 + 553 = 1212

Rzeczy takie jak File standardInput readBufferOfLength(1)zabijanie liczby bajtów, ale nie mogę tego obejść. Nie robiłem optymalizacji pod kątem powtarzających się symboli lub braku danych wejściowych w programie BF, ale będę nadal nad tym pracował, również nad tym, który korzysta z możliwości metaprogramowania io.

"v :=Vector clone setSize(30000)
p :=0
z :=getSlot(\"method\")
j :=z(p=p+1)
k :=z(p=p-1)
a :=z(v at(p))
l :=z(v atPut(p,a+1))
m :=z(v atPut(p,a-1))
n :=z(a asCharacter print)
u :=getSlot(\"while\")
o :=z(v atPut(p,File standardInput readBufferOfLength(1)))"println
z :=getSlot("method")
g :=z(a,b,if(a,a,b))
v :=z(e,f,if((x :=s)==e,nil,f .. g(w(x),"")))
s :=z(File standardInput readBufferOfLength(1))
w :=z(c,c switch(">",v("<","j"),"<","k","+","l","-","m",".","n",",","o","[",v("]","u(a>0,"),"]",")"))
while((c :=s)!=nil,if((t :=w(c))!=nil,t println))

Testowanie

cat test.bf | io bftrans.io > out.io && io out.io && echo && echo  $(cat out.io | wc -c) " + " $(cat bftrans.io | wc -c) " = "$(($(cat bftrans.io | wc -c) + $(cat out.io | wc -c)))

Wydajność

Hello world!
659  +  553  = 1212

1

Brainfuck , 109 + 407 = 516

>+[>+++++++[-<------>]<-[-[-[-[--------------[--[>+++++[-<------>]<+[--[[-]<[-]>]]]]]]]]<[.[-]]>>,[-<+<+>>]<]

Wypróbuj online!

Usuwa tylko operacje inne niż BF i nie analizuje innych optymalizacji.


0

Lua - 328 + 2256 = 2584

(Och, właśnie zdałem sobie sprawę, że musisz również dodać długość wyniku, słaby wynik, wygląda na to)

print((("l,m,p=loadstring,{0},1 z,y,x,w,v,u=l'io.write(string.char(@))',l'@=io.read(1):byte()',l'p=p-1',l'p=p+1 @=@or 0',l'@=(@+1)%256',l'@=(@-1)%256'"..io.read"*a":gsub("[^.,<>[%]+-]",""):gsub(".",{["."]="z()",[","]="y()",["<"]="x()",[">"]="w()",["["]="while @~=0 do ",["]"]="end ",["+"]="v()",["-"]="u()"})):gsub("@","m[p]")))

Zrobione z tym odpowiedź kopalni.


0

Lua - 319 + 21 = 340

Jest to prawdopodobnie najkrótszy kod ze wszystkich, ale nie przyjmuje danych wejściowych, więc jest trochę oszustwo. Wpadłem na pomysł innej wersji z wejściem, patrz koniec tego komentarza.

loadstring("o=\"\";d={"..string.rep("0,",30000).."}p=1;"..io.read():gsub("[^%+%-<>%.,%[%]]+",""):gsub(".",{["+"]="d[p]=d[p]+1;",["-"]="d[p]=d[p]-1;",[">"]="p=p+1;",["<"]="p=p-1;",["."]="o=o..string.char(d[p])",[","]="d[p]=io.read()",["["]="while d[p]~=0 do ",["]"]="end;"}))()print("print("..string.format("%q",o)..")")

Lua - 376 + 366 = 742

Ta wersja ma udowodnić, że lua może zrobić lepiej niż 2584: D

print('loadstring("d={"..string.rep("0,",30000).."}p=1;"..('..string.format("%q",io.read():gsub("[^%+%-<>%.,%[%]]+",""):gsub("%[[^%+%-<>%,%[%]]*%]",""):match("(.*[.,]).-"))..'):gsub(".",{["+"]="d[p]=d[p]+1;",["-"]="d[p]=d[p]-1;",[">"]="p=p+1;",["<"]="p=p-1;",["."]="io.write(string.char(d[p]))",[","]="d[p]=string.byte(io.read())",["["]="while d[p]~=0 do ",["]"]="end;"}))()')

Obie wersje dodają 30000 bajtów danych. Moja druga wersja opiera się na danych wejściowych / wyjściowych: wszystko po „.” lub „,” zostaną usunięte. Moja druga wersja nie zezwala na nieskończone pętle ([.,], [] Itd.)

Moim pomysłem jest uzyskanie:

print("Hello world!"..string.char(string.byte(io.read())+1)

Z twojego wkładu, z dodatkowym „, +”.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.