17
\$\begingroup\$

In any programming or scripting language x, write a program that takes a valid brainfuck sourcecode from stdin and output, to stdout, the sourcecode of a program, written in language x, that would output the exact same thing as the brainfuck program would do.

Your program must work for any valid brainfuck program, including the empty file.

Your score would be equal to the byte count of your sourcecode, plus the byte count of your output given the following input:

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

For example, for an input of [-], the output of *p=0; is much more favourable than while(*p) *p--;

If you happen to use non-ASCII characters, the byte count must be calculated using the UTF-8 encoding.

Lowest score wins. However, creative solutions that attempt to minimise the output shall be encouraged by upvotes.

\$\endgroup\$
12
  • 13
    \$\begingroup\$ You might want to add a clause that the target language not also be brainfuck ;) \$\endgroup\$
    – Josh
    Feb 3, 2014 at 1:58
  • \$\begingroup\$ @Josh well, if someone managed to write a short brainfuck program that removes unnecessary useless codes, why not let them do it? \$\endgroup\$
    – user12205
    Feb 3, 2014 at 11:11
  • 2
    \$\begingroup\$ Well quite simply because the trivial solution of outputting the source unchanged is going to have a really low score anyway for brainfuck. I will be surprised if another language can beat that. \$\endgroup\$ Feb 3, 2014 at 11:19
  • \$\begingroup\$ @Tim Seguine I could change the question, but would that be unfair to those who have already provided an answer? And if I change the question, I'm thinking about changing the score calculation, making it byte count of source + (byte count of output)^2, would that encourage people to focus more on simplifying the output? \$\endgroup\$
    – user12205
    Feb 3, 2014 at 11:25
  • \$\begingroup\$ Generally changing a question like that after it has already been answered is frowned upon. I was just pointing out a reason why I think Josh was right. It's good to post stuff like this in the sandbox first, so you can work out potential problems while being fair to everyone. \$\endgroup\$ Feb 3, 2014 at 11:33

9 Answers 9

14
\$\begingroup\$

Brainfuck, 5 + 540 = 545 bytes

5 bytes of code, 540 from output of given test file (assuming got the count right from my paste of that code).

,[.,]

Assuming EOF is 0.

\$\endgroup\$
3
  • \$\begingroup\$ @primo since it doesn't reset before reading a interpreter that does not chaneg value at EOF will make this program an endless loop for all input larger than 0 bytes. \$\endgroup\$
    – Sylwester
    Feb 3, 2014 at 16:12
  • \$\begingroup\$ I cant help to wonder, what software is used to run this stuff? xD \$\endgroup\$
    – Teun Pronk
    Feb 5, 2014 at 14:31
  • \$\begingroup\$ @TeunPronk There's a brainfuck interpreter called bfi (github.com/susam/bfi). Just compile and install it, and run it like so: bfi input.bf where input.bf is the brainfuck file to be interpreted. \$\endgroup\$ Feb 10, 2014 at 1:17
12
\$\begingroup\$

Perl - 177 (source) + 172 (output) = 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'

Counting the shebang as 2 bytes, one for each option. First, each of the eight commands is translated onto the range p-w, while at the same time removing all other characters. This string is then run-length encoded and output with a minimal decoder/interpreter. A few things are optimized away: the string >< obviously does nothing, and a for loop that follows directly after another may be removed entirely, as it will never be entered.

Output for the test program:

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

A sample run:

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

Perl - 232 (source) + 21 (output) = 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\"")

This one is based on FIQ's observation that if the original program doesn't contain an input statement, the output will be static, and therefore can be reduced to a single print statement. If you like this one, be sure to give his answer a +1.

So what we can do is pipe stdout to a variable, eval the code we would have output, and wrap the result in a print.

...that won't always work, though. Whenever the code to be translated would have resulted in an infinite loop, (e.g. +[.]), this cannot be reduced to a single print statement, for obvious reasons. So instead, we launch the eval in a child process with a short timeout, and if it doesn't finish executing within that time we output the translated program as before.

Structured and commented:

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

Output for sample program:

print"Hello\ world\!"

Output for ,[.]:

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

Output for +[.] (after 9 seconds):

eval'21647'=~s/./qw(--$ ++$ -- ++ print+chr$ $$i=ord+getc; while($$i){ })[$&].q($i;)/ger
\$\endgroup\$
3
  • 1
    \$\begingroup\$ This is amazing! Brain hurts :) \$\endgroup\$
    – Timwi
    Feb 3, 2014 at 20:25
  • \$\begingroup\$ I think wv.*?(?=w) is wrong. I think it will only remove code up to the next ], but you need it to find the matching ]; you need to take care of nesting... \$\endgroup\$
    – Timwi
    Feb 3, 2014 at 20:35
  • \$\begingroup\$ @Timwi Fixed, by ignoring the nested cases wv[^v]*(?=w), which is significantly shorter than the alternative. \$\endgroup\$
    – primo
    Feb 4, 2014 at 0:20
5
\$\begingroup\$

PHP, 553 + 27 = 580 bytes

(553 bytes with all whitespaces, i.e. newlines and spaces, removed)

I suck badly at golfing PHP, so this approach can be heavily optimized. I mostly wanted to show my approach to the solution in something not 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);

Error reporting must be off, otherwise PHP will hate you. Usage: throw this up as a page, and run it with script.php?c=CODE (if the resulting script requires input, you run it as out.php?i=INPUT). Remember to url escape the input!

What this does is basically this - if the BF script contains ",", it pretty much embeds itself as the resulting script with an attached $b=1; at the top. If it does NOT contain ",", it optimizes it down to "echo '<BF output>'". Conveniently, the test script in the OP does NOT require any input. The addslashes() is just there for escaping ' and \.

\$\endgroup\$
4
\$\begingroup\$

C++, 695 + 510 = 1205 bytes

Code:

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

Output:

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

Original code:

#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 << "}";
}
\$\endgroup\$
3
\$\begingroup\$

Brainfuck, 109 + 407 = 516

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

Try it online!

It only removes non BF ops and does not look at other optimizations.

\$\endgroup\$
2
\$\begingroup\$

Python - 514 + 352 = 866

Code:

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

Output:

import zlib,base64
exec(zlib.decompress(base64.b64decode("eNrLzC3ILypRKK4s5krUybSNNojVMjYAAR0DrsTozFhtW0OCdHlGZk6qAoinaGtgxQVm6QLFFQoSi4uJNoVc2zJBggowWTIZVDGEEvMzddFJ1FDMxBYUwFjTKy5JyS8t0SsvyixJ1UjOKNIASWpqomrAp5DceMBnJjn2Ee0ZojToUiGlEfIFzA5yaGqHELXtp5XfMukVwMOFRi/u8IXZqOSo5KjkqOSIlAQ3k9BLy1HBUcFRwVFBOgpmIrfeMhGE9ihrpLEAudg3NA==")).decode("utf8"))
\$\endgroup\$
1
\$\begingroup\$

Lua - 319 + 21 = 340

This is most likely the shortest code of all, but it doesn't accept input, so it is kinda cheaty. I got a idea for another version with input, see the end of this comment.

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

This version is to prove that lua can do better than 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;"}))()')

Both versions add in 30000 bytes of data. My second version is based on input/output: everything after a '.' or ',' will be removed. My second version does not allow infinite loops ( [.,], [], etc. )

My Idea is to get:

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

From your input, with a extra ',+.'

\$\endgroup\$
1
\$\begingroup\$

io

659 + 553 = 1212

Things like File standardInput readBufferOfLength(1) really kill the byte count but I can't get around it. I didn't do optimizations for repeated symbols or lack of input in the BF program, but will continue to work on it, also working on one making use of io's metaprogramming capabilities.

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

Testing

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

Yields

Hello world!
659  +  553  = 1212
\$\endgroup\$
0
\$\begingroup\$

Lua - 328 + 2256 = 2584

(Oh I just realized you need to add the length of the result too, poor score, it looks like)

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

Taken from this answer of mine.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.