11
\$\begingroup\$

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:

ðñðòñðòðôóòñóñôóðòõóñõðôôóòñööõôöðóöðõðùõñô÷ùõóñöóùñô÷øôøõôòöõóðòöóñ÷ðõôûôòú÷úø÷öùøöùñøðùúðûðþöûñùýøðòñ
\$\endgroup\$
  • \$\begingroup\$ 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) \$\endgroup\$ – spocot Aug 28 '14 at 19:52
  • 2
    \$\begingroup\$ I think you mean 'superset', not subset. \$\endgroup\$ – ɐɔıʇǝɥʇuʎs Aug 28 '14 at 19:54
  • \$\begingroup\$ @ɐɔıʇǝɥʇuʎs Changed from subset to extension. Thanks for the feedback. \$\endgroup\$ – spocot Aug 28 '14 at 19:56
  • \$\begingroup\$ 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.... \$\endgroup\$ – pseudonym117 Aug 28 '14 at 20:22
  • 1
    \$\begingroup\$ Why 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. \$\endgroup\$ – Peter Olson Aug 28 '14 at 21:33
7
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – user0721090601 Sep 1 '14 at 4:30
  • \$\begingroup\$ I think this does not work with loops ([]). You cannot eval character by character for that. \$\endgroup\$ – nutki Dec 25 '14 at 17:08
  • \$\begingroup\$ How the pluses get translated back into parenthesis? \$\endgroup\$ – nutki Dec 25 '14 at 17:17
6
\$\begingroup\$

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.
\$\endgroup\$
  • 2
    \$\begingroup\$ I think the if() and the ; could be replaced with ?: and save some characters. \$\endgroup\$ – Jerry Jeremiah Aug 29 '14 at 11:29
  • 2
    \$\begingroup\$ The character literals can be replaced with their ASCII equivalents to save characters. \$\endgroup\$ – pseudonym117 Aug 29 '14 at 14:25
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ – spocot Aug 29 '14 at 16:06
  • 1
    \$\begingroup\$ You 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. \$\endgroup\$ – es1024 Aug 29 '14 at 22:10
  • 1
    \$\begingroup\$ You 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--; \$\endgroup\$ – es1024 Aug 29 '14 at 22:22
6
\$\begingroup\$

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?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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