BrainFlow Interpreter!

11

3

BrainFlow

What is BrainFlow?

BrainFlow is an extension of BrainF**k (BFk) with 3 additional commands for added functionality and confusion.

What commands?

In addition to the normal BFk commands, we also have:

^ Jumps to the cell # depending on the value in the cell. Ex: If we are at cell # 0 with a value of 4, ^ will jump us to cell # 4.

= Sets the value at the cell to the index of the cell. Ex: If we are at cell # 4 with a value of 0, = will set our value to 4.

& Will set the value at the current cell equal to the value at the cell based on the value in our current cell. (This one's hard to word, so here's an example!) Ex: We are at cell # 33 and our current value at this cell is 7, & will set our current value at cell # 33 to whatever value is in cell # 7.

Optional Challenges

Accomplishing any of the following will apply the specified bonus to your byte count.

Interpreter written in BrainFlow (Can be interpreted by the sample and contains at least one meaningful ^ = or &): Score / 3

Interpreter written in BrainF**k: Score / 2

Doesn't contain any English letters (in either upper or lower case): Score - 20

Doesn't contain any of the BrainFlow / BFk commands in the interpreter itself: Score - 50

Example

An example Java interpreter:

import java.util.Scanner;

public class Interpreter {

    private String exp;

    private int[] values = new int[256];
    private int index = 0;

    private Scanner in;

    public Interpreter(String exp, Scanner in){
        this.exp = exp;
        this.in = in;
    }

    public void run(){
        //Reset index and values
        for(int i = 0; i < values.length; i++){
            values[i] = 0;
        }
        this.index = 0;

        System.out.println("Starting...");
        this.process(this.exp, false);
        System.out.println("\nDone.");
    }

    private void process(String str, boolean loop){
        boolean running = loop;
        do{
            for(int i = 0; i < str.length(); i++){
                switch(str.charAt(i)){
                case '>':increaseIndex();break;
                case '<':decreaseIndex();break;
                case '+':increaseValue();break;
                case '-':decreaseValue();break;
                case '[':
                    String s = str.substring(i);
                    int j = this.getClosingIndex(s);
                    if(this.values[this.index] == 0){
                        i +=j;
                        break;
                    }
                    process(s.substring(1, j), true);
                    i += j;
                    break;
                case '.':
                    int v = this.values[this.index];
                    System.out.print((char)v);
                    break;
                case ',':this.values[this.index] =  this.in.next().charAt(0);break;
                case '^':this.index = this.values[this.index];break;// Jumps to the index specified in the current cell.
                case '=':this.values[index] = this.index;break;// Sets the value at cell #x to x
                case '&':this.values[index] = this.values[this.values[index]];break;// If cell contains X, makes value of current cell equal to value in cell X
                default:
                    //Ignore others
                    break;
                }
            }
            if(this.values[this.index] == 0){
                running = false;
            }
        }while(running);
    }

    private void increaseIndex(){
        if(++this.index >= this.values.length){
            this.index = 0;
        }
    }

    private void decreaseIndex(){
        if(--this.index < 0){
            this.index = this.values.length - 1;
        }
    }

    private void increaseValue(){
        int newVal = this.values[this.index] + 1;
        if(newVal >= this.values.length){
            newVal = 0;
        }
        this.values[this.index] =  newVal;
    }

    private void decreaseValue(){
        int newVal = this.values[this.index] - 1;
        if(newVal < 0){
            newVal = this.values.length - 1;
        }
        this.values[this.index] =  newVal;
    }

    private int getClosingIndex(String str){
        int openings = 0;
        int closings = 0;
        for(int i = 0; i < str.length(); i++){
            char c = str.charAt(i);
            if(c == '['){
                openings++;
            }else if(c == ']'){
                closings++;
            }
            if(openings == closings){
                return i;
            }
        }
        return -1;
    }
}

Not even close to golfed but should provide a good starting point.

Lowest final score wins, where score is number of bytes in your program after the applicable Challenge reductions have been taken into account.

Testing

The following BrainFlow program should print the specified output after reading a '+' char from stdin:

<<,++++[>++++[>++++<-]<-] Set cell #0 to a value dependent on input
>>>+[[-]&>=]+& Set every other cell to that value
[ Start loop
+^ Add one to current value and jump to that cell index
. Print the value at that cell
& Copy value from specified cell
] End loop

Output:

ðñðòñðòðôóòñóñôóðòõóñõðôôóòñööõôöðóöðõðùõñô÷ùõóñöóùñô÷øôøõôòöõóðòöóñ÷ðõôûôòú÷úø÷öùøöùñøðùúðûðþöûñùýøðòñ

spocot

Posted 2014-08-28T19:50:48.247

Reputation: 606

Note that the & allows you to essentially create variables in the lower cells then reference them later.

For example if I store my age in the 2nd cell and the month I was born in the 3rd cell, and I am currently in the 64th cell, I can do ++& to retrieve my age or +++& to retrieve the month I was born in. (Assuming of course the 64th cell is at the default value of 0) – spocot – 2014-08-28T19:52:55.020

2I think you mean 'superset', not subset. – ɐɔıʇǝɥʇuʎs – 2014-08-28T19:54:58.487

@ɐɔıʇǝɥʇuʎs Changed from subset to extension. Thanks for the feedback. – spocot – 2014-08-28T19:56:21.073

score for being written in brainflow is a bad idea - brainfuck is a subset of brainflow, therefore any brainfuck program is a brainflow program. its like saying a c++ program will score better than a C program. OK, my C program is a C++ program, soo.... – pseudonym117 – 2014-08-28T20:22:11.547

@pseudonym117 I'll make it more specific, thanks – spocot – 2014-08-28T20:23:52.160

for challenge #4, does that mean just literals or in the source code at all? – pseudonym117 – 2014-08-28T20:36:34.040

@pseudonym117 None in the source code at all. – spocot – 2014-08-28T20:38:15.093

if anyone manages to do that i will be thoroughly impressed. = and , pretty important in every language... – pseudonym117 – 2014-08-28T20:43:22.377

@pseudonym117 That's why its a -50 to your score. – spocot – 2014-08-28T20:45:40.853

Does it have to be unbounded in both directions or is it okay to not allow negative cell indices? – Ingo Bürk – 2014-08-28T21:02:21.233

@IngoBürk It should work the same way BrainF**k does. Decrementing a cell or value when at 0 sets the value to 255. And incrementing when at 255 should set to 0. – spocot – 2014-08-28T21:03:44.737

Well there are different brainfuck implementations. But we're talking about a wrapping one on both ends here. Got it :) – Ingo Bürk – 2014-08-28T21:07:41.337

@IngoBürk Yah, it's the only implementation that makes sense to me, especially since output can only be 0-255. – spocot – 2014-08-28T21:11:03.407

True, nin-wrapping would cause problems in the new commands. Hadn't thought of that. Thanks! – Ingo Bürk – 2014-08-28T21:12:43.550

1Why is writing an implementation in Brainfuck have a smaller benefit than writing one in Brainflow? It seems like the former would be more challenging, since it is a smaller language. – Peter Olson – 2014-08-28T21:33:34.397

@PeterOlson Because I said so. JK, it's because I wanted to give a strong reason to experiment and use the new commands in your interpreter if writing in a Brain[Flow/F**k] language. – spocot – 2014-08-29T02:12:29.590

Any submission in BFk or BFw would automatically also get the third bonus. In that case, which bonus is applied first? – Martin Ender – 2014-08-31T00:15:41.467

@MartinBüttner Division bonuses will be applied after subtraction bonuses. – spocot – 2014-08-31T02:04:23.053

Can we assume a limited size for the array (e.g. the "standard" 30k cell array?). – Bakuriu – 2014-09-23T16:53:35.707

@Bakuriu There are 255 cells that can hold values up to 255 – spocot – 2014-09-25T03:09:08.453

@spocot According to your description there are at least 255 cells, but you could have an infinite number (although you can only jump to the first 255). Anyway your comment clarifies that you only require exactly 255 cells. – Bakuriu – 2014-09-25T06:49:36.067

@Bakuriu I can assure you... there are only, at max, 255 cells... The indexes and values wrap around. ex: 255 + 1 = 0 – spocot – 2014-09-26T21:31:07.263

Answers

7

Perl - 233 230 210 182 180 176 174 171 bytes

$/=$,;%d=qw(> $p++ < $p-- + $v[$p]++ - $v[$p]-- , $v[$p]=ord+getc . print+chr+$v[$p] [ while+$v[$p]{ ] } ^ $p=$v[$p] = $v[$p]=$p & $v[$p]=$v[$v[$p]]);eval$d{$_}for<>=~/./g

Simply took an existing BrainFuck interpreter of mine, golfed it, and added the BrainFlow functions.

Update: Completely restructured the program to lose 28 bytes.

malkaroee

Posted 2014-08-28T19:50:48.247

Reputation: 332

I think this does not work with loops ([]). You cannot eval character by character for that. – nutki – 2014-12-25T17:08:21.493

How the pluses get translated back into parenthesis? – nutki – 2014-12-25T17:17:57.550

Notice that if you were to be fed a string of 300 "+"s, you'd end up with invalid values. You need to do a %256 sanity check after/while setting many of those values. – user0721090601 – 2014-09-01T04:30:54.567

6

Let's get this party started.

C - 408 384 393 390 380 357 352 bytes (still chipping away)

Compile with gcc on a POSIX compliant system. The first argument is the name of a file containing the Brainflow code to be interpreted. Newlines added to improve readability.

i,p,b[9999],*k=b;unsigned char g[9999],a[30000],*d=a;main(c,v)char**v;
{read(open(v[1],0),g,9999);while(c=g[i++]){c-62||d++;c-60||d--;c-43||
(*d)++;c-45||(*d)--;c-46||putchar(*d);c==44?*d=getchar():0;c==94?d=a+*d:0;
c==61?*d=d-a:0;c==38?*d=a[*d]:0;c==93?i=*(--k):0;if(c==91)if(*d)*k++=i-1;else 
while(c=g[i++]){c==91?p++:0;if(c==93)if(p)p--;else break;}}}

And the ungolfed version if you're interested. Let me know if you see any bugs.

int i, depth, buffer[9999], *stack = buffer;
unsigned char c, program[9999], array[30000], *data = array;

main(int argc, char **argv)
{
    read(open(argv[1], 0), program, 9999);

    while(c = program[i++]){
        if (c=='>') data++;
        if (c=='<') data--;
        if (c=='+') (*data)++;
        if (c=='-') (*data)--;
        if (c=='.') putchar(*data);
        if (c==',') *data=getchar();
        if (c=='^') data=array+*data;
        if (c=='=') *data=data-array;
        if (c=='&') *data=array[*data];
        if (c==']') i=*(--stack);
        if (c=='[')
            if (*data) *stack++=i-1;
            else while (c=program[i++]) {
                    if (c=='[') depth++;
                    if (c==']') if (depth) depth--; else break;
            }
    }
}

Updates:

  • Thanks for the initial feedback which allowed me to knock an extra 24 bytes off.

  • Sign bug fixed. Added another 9 bytes.

  • Saved another 3 bytes per es1024's suggestions.

  • Saved another 10 bytes per more suggestions from es1024.

  • Just remembered that global variables are initialized to 0. Switched from fread and fopen to read and open. Saved 23 bytes.

  • Don't need to set null terminator on program because buffer is already initialized to zero. Saved 5 bytes.

Orby

Posted 2014-08-28T19:50:48.247

Reputation: 844

2I think the if() and the ; could be replaced with ?: and save some characters. – Jerry Jeremiah – 2014-08-29T11:29:34.913

2The character literals can be replaced with their ASCII equivalents to save characters. – pseudonym117 – 2014-08-29T14:25:01.773

1@Orby It doesn't seem to process input chars correctly. It should convert them to the ascii representation and store them. Other than that it works. – spocot – 2014-08-29T16:06:38.587

isn't there switch in c? (i don't know c yet) – proud haskeller – 2014-08-29T16:55:01.997

@proudhaskeller There is a switch statement in C, but it uses more bytes than sequential ifs. – Orby – 2014-08-29T20:25:14.137

@spocot I don't understand what you mean. <code>getchar()</code> should return the ASCII code for the letter (not the keyboard code). Could you give me an example of a character which it fails to store correctly? – Orby – 2014-08-29T21:00:37.427

@Orby http://i.imgur.com/rF0FZQ7.png

– spocot – 2014-08-29T21:03:01.713

@spocot What are the contents of test.flo? Just ",."? When I execute ",." I don't encounter any problems. Edit: Oh I see, sorry, you're probably running the test program listed in the problem description. One second, I'll tell you what I get. – Orby – 2014-08-29T21:18:49.837

@Orby the test program above, your output does not match the test program output – spocot – 2014-08-29T21:23:14.827

@spocot: Found the culprit. Just a stupid sign bug. All patched up now. You still won't see the extended ASCII characters on the terminal emulator because its dumping raw ASCII instead of Unicode, but the cell values are correct. – Orby – 2014-08-29T21:49:39.510

1You can replace main(int c,char**v){ with main(c,v)char**v;{ and save two bytes, as well as move int i=0,p=0,b[9999],*k=b; to outside the function, and drop the int to save four bytes. if (c==91) also has an unnecessary space. – es1024 – 2014-08-29T22:10:44.077

@es1024: Moving the integer declaration outside the function won't compile for me on gcc, but the other suggestions work. Thanks! – Orby – 2014-08-29T22:19:31.820

1You can also replace most if not all of the c==[number]?[action]:0; with c-[number]||[action]. (c-[number] is equivalent to c != [number] and if(p)p--; with p&&p--; – es1024 – 2014-08-29T22:22:14.230

@es1024 c-[number]||[action] works in some places, but p&&p-- exhibits different behaviour (though I have no idea why?). – Orby – 2014-08-29T22:55:26.620

1@Orby Ah, the if(p) has an else; that would explain why. – es1024 – 2014-08-30T02:49:03.470

1c cannot equal 44 and 94 and 61 etc all at the same time, so rather than c==a?x:0;c==b?y:0 style you could do c==a?x:c==b?y:... ? – Will – 2014-08-31T14:56:30.900

@Orby what happens when you actually read 9999 characters? Your program array will be entirely full you won't be sure that the character beyond the input is a \0. Fix: read 9998 chars instead of 9999. – tomsmeding – 2014-11-04T13:01:39.110

6

AppleScript 972 670

Mostly golfed although there's no way it will ever win. I don't know why I didn't think about just constructing a script like the perl one did (though it still won't win haha). This could probably be golfed more by readjusting how the index values a bit better, AppleScript is frustratingly (for this type of stuff) a 1 index language.

Just pass the BrainFlow code in to e(). Note that AppleScript's ASCII commands use MacOSRoman encoding, so while the output will appear different, it is correct looking at its binary representation. You'll need to take that into account when passing in any upper ASCII characters though on "," commands.

on e(x)
set d to {"", "set b'sitem(i+1)to(b'sitem(i+1)+1)mod 256", "set b'sitem(i+1)to(b'sitem(i+1)+255)mod 256", "set i to(i+1)mod 256", "set i to(i+255)mod 256", "repeat while b'sitem(i+1)≠0", "end", "set o to o&(ASCII character b'sitem(i+1))", "display dialog \"\"default answer\"\"
set b'sitem(i+1)to ASCII number result'stext returned'stext1", "set i to b'sitem(i+1)", "set b'sitem(i+1)to i", "set b'sitem(i+1)to b'sitem(b'sitem(i+1)+1)"}
set s to "set i to 0
set b to{}
repeat 256
set b'send to 0
end
set o to  \"\"
"  
repeat with c in x'stext
set s to s&d'sitem((offset of c in "+-><[].,^=&")+1)&"
"
end
set s to s&"return o"
return run script s
end

(because what f***s with your brain more than writing a brainfuck/flow interpreter in another language that f***s with your head way too much?

user0721090601

Posted 2014-08-28T19:50:48.247

Reputation: 928