Escreva um tradutor de cérebro

18

Em qualquer linguagem de programação ou script x , escreva um programa que leve um código-fonte válido para o cérebro de stdin e output para stdout, o código-fonte de um programa, escrito na linguagem x , que produziria exatamente a mesma coisa que o programa brainfuck faria.

Seu programa deve funcionar para qualquer programa válido do cérebro, incluindo o arquivo vazio.

Sua pontuação seria igual à contagem de bytes do seu código-fonte, mais a contagem de bytes da sua saída, com a seguinte entrada:

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

Por exemplo, para uma entrada de [-], a saída de *p=0;é muito mais favorável do quewhile(*p) *p--;

Se você usar caracteres não ASCII, a contagem de bytes deverá ser calculada usando a codificação UTF-8.

Menor pontuação ganha. No entanto, soluções criativas que tentam minimizar a produção devem ser incentivadas por votos positivos.

user12205
fonte
11
Você pode querer adicionar uma cláusula de que o idioma de destino também não deve ser um problema cerebral;)
Josh
@ Josh, bem, se alguém conseguiu escrever um pequeno programa de foda cerebral que remove códigos inúteis desnecessários, por que não deixá-los fazer isso?
User12205
2
Bem, simplesmente porque a solução trivial de gerar a fonte inalterada terá uma pontuação realmente baixa para o cérebro. Ficarei surpreso se outro idioma puder superar isso.
Tim Seguine 03/02
@ Tim Seguine Eu poderia mudar a pergunta, mas isso seria injusto para aqueles que já forneceram uma resposta? E se eu mudar a pergunta, estou pensando em mudar o cálculo da pontuação, tornando-a byte count of source + (byte count of output)^2, isso encorajaria as pessoas a se concentrarem mais na simplificação do resultado?
User12205
Geralmente, alterar uma pergunta como essa depois de já ter sido respondida é desaprovado. Eu estava apenas apontando uma razão pela qual acho que Josh estava certo. É bom postar coisas como essa na sandbox primeiro, para que você possa resolver problemas em potencial e ser justo com todos.
Tim Seguine

Respostas:

12

Perl - 177 (origem) + 172 (saída) = 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'

Contando o shebang como 2 bytes, um para cada opção. Primeiro, cada um dos oito comandos é traduzido para o intervalo p-w, ao mesmo tempo em que remove todos os outros caracteres. Essa sequência é codificada e executada no comprimento de execução com um decodificador / intérprete mínimo. Algumas coisas são otimizadas: a sequência ><obviamente não faz nada, e um loop for que segue diretamente após o outro pode ser completamente removido, pois nunca será inserido.

Saída para o programa de teste:

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

Uma amostra de execução:

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

Perl - 232 (origem) + 21 (saída) = 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\"")

Este é baseado na observação do FIQ de que, se o programa original não contiver uma instrução de entrada, a saída será estática e, portanto, poderá ser reduzida a uma única printinstrução. Se você gosta deste, certifique-se de dar uma resposta para +1.

Então, o que podemos fazer é canalizar stdoutpara uma variável, evalo código que teríamos de saída e agrupar o resultado em a print.

... isso nem sempre funciona, no entanto. Sempre que o código a ser traduzido resultasse em um loop infinito (por exemplo +[.]), isso não pode ser reduzido a uma única printinstrução, por razões óbvias. Então, em vez disso, iniciamos o evalprocesso em um filho com um tempo limite curto e, se não terminar de executar nesse período, produzimos o programa traduzido como antes.

Estruturado e comentado:

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\""
  }
}

Saída para o programa de amostra:

print"Hello\ world\!"

Saída para ,[.]:

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

Saída para +[.](após 9 segundos):

eval'21647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger
primo
fonte
1
Isso é incrível! Cérebro dói :)
Timwi
Eu acho que wv.*?(?=w)está errado. Eu acho que ele só removerá o código até o próximo ], mas você precisa encontrar a correspondência ] ; você precisa cuidar de nidificação ...
Timwi
@ Timwi Corrigido, ignorando os casos aninhados wv[^v]*(?=w), que é significativamente mais curto que a alternativa.
primo
14

Brainfuck, 5 + 540 = 545 bytes

5 bytes de código, 540 da saída do arquivo de teste fornecido (supondo que a contagem seja correta na minha colagem desse código).

,[.,]

Supondo que EOF seja 0.

FIQ
fonte
@primo, pois ele não é redefinido antes de ler um intérprete que não altera o valor no EOF, fará deste programa um loop infinito para todas as entradas maiores que 0 bytes.
194 Sylwester
Não posso deixar de me perguntar, que software é usado para executar essas coisas? xD
Teun Pronk
@TeunPronk Existe um intérprete de foda cerebral chamado bfi ( github.com/susam/bfi ). Apenas compile e instale-o e execute-o da seguinte forma: bfi input.bfonde input.bfestá o arquivo brainfuck a ser interpretado.
Braden Best
5

PHP, 553 + 27 = 580 bytes

(553 bytes com todos os espaços em branco, ou seja, novas linhas e espaços, removidos)

Eu sou péssima em jogar golfe no PHP, então essa abordagem pode ser fortemente otimizada. Eu queria principalmente mostrar minha abordagem da solução em algo que não fosse o melhor.

<?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);

O relatório de erros deve estar desativado; caso contrário, o PHP o odiará. Uso: jogue isso como uma página e execute-o com script.php? C = CODE (se o script resultante exigir entrada, você o executará como out.php? I = INPUT). Lembre-se de url para escapar da entrada!

O que isso faz é basicamente isso - se o script BF contiver ",", ele se incorporará como o script resultante com um $ b = 1 anexado; no topo. Se NÃO contiver ",", ele será otimizado para "eco '<BF output>'". Convenientemente, o script de teste no OP NÃO requer nenhuma entrada. O addslashes () existe apenas para escapar 'e \.

FIQ
fonte
4

C ++, 695 + 510 = 1205 bytes

Código:

#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<<"}";}

Resultado:

#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;}

Código original:

#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 << "}";
}
johnchen902
fonte
2

Python - 514 + 352 = 866

Código:

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"))')

Resultado:

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

io

659 + 553 = 1212

Coisas como File standardInput readBufferOfLength(1)realmente matam a contagem de bytes, mas não consigo contornar isso. Eu não fiz otimizações para símbolos repetidos ou falta de entrada no programa BF, mas continuarei trabalhando nele, também trabalhando em um que faça uso dos recursos de metaprogramação da 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))

Teste

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

Rendimentos

Hello world!
659  +  553  = 1212
Jordon Biondo
fonte
1

Brainfuck , 109 + 407 = 516

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

Experimente online!

Ele remove apenas operações que não são BF e não analisa outras otimizações.

Sylwester
fonte
0

Lua - 328 + 2256 = 2584

(Ah, eu acabei de perceber que você precisa adicionar o tamanho do resultado também, baixa pontuação, parece)

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]")))

Retirado desta resposta minha.

mniip
fonte
0

Lua - 319 + 21 = 340

Este é provavelmente o código mais curto de todos, mas não aceita entrada, por isso é meio barato. Eu tive uma idéia para outra versão com entrada, veja o final deste comentário.

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

Esta versão é para provar que lua pode fazer melhor que 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;"}))()')

Ambas as versões adicionam 30000 bytes de dados. Minha segunda versão é baseada em entrada / saída: tudo depois de um '.' ou ',' serão removidos. Minha segunda versão não permite loops infinitos ([.,], [] Etc.)

Minha idéia é obter:

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

De sua entrada, com um ', +' extra.

YoYoYonnY
fonte