Befudge

From Esolang
Jump to navigation Jump to search
Befudge
Paradigm(s) unknown
Designed by None1
Appeared in 2023
Memory system Stack-based
Dimensions two-dimensional
Computational class Push-down automata
Major implementations JavaScript (only for Standard Befudge)
Dialects Standard Befudge, Advanced Befudge
Influenced by Befunge
File extension(s) .bfg

Befudge is an esolang created by User:None1 simply because he thinks that the commands ^, <, v, and > in Befunge are unnecessary (since there are | and _).

Note: Unlike Befunge-93, in Befudge the program size can be larger than 80x25 (even if it is to Befunge-93), but the playfield is only as large as the program.

Standard Befudge

Standard Befudge is basically Befunge but without the ^, <, v, and > commands, to change IP direction into a specific direction, you can push a number onto the stack and use | and _ (e.g.: If the IP direction is right, you can use #$1_ to turn it left).

Standard Befudge is to Befunge-93, but adaptations for Befunge-98 could be easily developed.

Note: If the IP direction is not right, you can use:

1
_1
1

to turn it left.

Examples

Hello World

"!!ddllrrooWW  oolllleeHH"0_0$:#,_@

Truth Machine

&#::_.@#

Cat Program (never terminates)

 _~:!|
 0   :
 |0 ,_

Advanced Befudge

Advanced Befudge is also Befunge but uses an all-in-one command - ? to control the IP direction. However, the meaning of that command in Advanced Befudge is:

Pops a number from stack.
If the number is positive, rotate the IP 90 degrees clockwise.
If the number is 0, rotate the IP 90 degrees counterclockwise.
If the number is negative, change the IP direction to random.

So v, ^, <, >, _ and | are unavailable because they're all included in the ? command.

Advanced Befudge is to Befunge-93, but adaptations for Befunge-98 could be easily developed.

Examples

Hello World

"!dlroW olleH",,,,,,,,,,,,@

Programs using the ? command are not shown here, because I can't write one.

Interpreter

The following is the interpreter for Befudge in JavaScript, but unfortunately it only supports Standard Befudge:

function pop(s){
    if(s.length==0){
        return 0;
    }else{
        return s.pop();
    }
}
function befudge(program,input){
    var playfield=[],maxw=0;
    for(let i of program.split('\n')){
        playfield.push(i.split(""));
        if(i.length>maxw){
            maxw=i.length;
        }
    }
    for(let i of playfield){
        while(i.length<maxw){
            i.push(" ");
        }
    }
    var ipx=0,ipy=0,ipdx=0,ipdy=1,output='',stack=[];
    while(1){
        var cmd=playfield[ipx][ipy];
        if('1234567890'.includes(cmd)){
            stack.push(cmd.charCodeAt(0)-48);
        }
        switch(cmd){
            case '@':{
                return output;
                break;
            }
            case '+':{
                var a=pop(stack);
                var b=pop(stack);
                stack.push(b+a);
                break;
            }
            case '-':{
                var a=pop(stack);
                var b=pop(stack);
                stack.push(b-a);
                break;
            }
            case '*':{
                var a=pop(stack);
                var b=pop(stack);
                stack.push(b*a);
                break;
            }
            case '/':{
                var a=pop(stack);
                var b=pop(stack);
                if(a==0){
                    stack.push(0);
                    break;
                }
                stack.push(a<0?Math.ceil(b/a):Math.floor(b/a));
                break;
            }
            case '%':{
                var a=pop(stack);
                var b=pop(stack);
                if(a==0){
                    stack.push(0);
                    break;
                }
                stack.push(b%a);
                break;
            }
            case '!':{
                var a=pop(stack);
                if(a){
                    stack.push(0);
                    break;
                }
                stack.push(1);
                break;
            }
            case '`':{
                var a=pop(stack);
                var b=pop(stack);
                if(b>a){
                    stack.push(1);
                    break;
                }
                stack.push(0);
                break;
            }
            case '?':{
                var x=Math.floor(Math.random()*4);
                ipdx=[0,0,1,-1][x];
                ipdy=[1,-1,0,0][x];
                break;
            }
            case '_':{
                ipdx=0;
                if(pop(stack)){
                    ipdy=-1;
                }else{
                    ipdy=1;
                }
                break;
            }
            case '|':{
                ipdy=0;
                if(pop(stack)){
                    ipdx=-1;
                }else{
                    ipdx=1;
                }
                break;
            }
            case '\"':{
                do{
                    ipx+=ipdx;
                    ipy+=ipdy;
                    while(ipx>=playfield.length){
                        ipx-=playfield.length;
                    }
                    while(ipx<0){
                        ipx+=playfield.length;
                    }
                    while(ipy>=maxw||ipy==-1){
                        ipy-=maxw;
                    }
                    while(ipy<0){
                        ipy+=maxw;
                    }
                    stack.push(playfield[ipx][ipy].charCodeAt(0));
                }while(playfield[ipx][ipy]!='\"');
                pop(stack);
                break;
            }
            case ':':{
                stack.push(stack.length==0?0:stack[stack.length-1]);
                break;
            }
            case '\\':{
                var a=pop(stack);
                var b=pop(stack);
                stack.push(a);
                stack.push(b);
                break;
            }
            case '$':{
                pop(stack);
                break;
            }
            case '.':{
                output+=pop(stack)+' ';
                break;
            }
            case ',':{
                output+=String.fromCharCode(pop(stack));
                break;
            }
            case '#':{
                ipx+=ipdx;
                ipy+=ipdy;
                break;
            }
            case 'g':{
                var b=pop(stack);
                var a=pop(stack);
                if(b>=playfield.length||a>=maxw){
                    stack.push(0);
                }else{
                    stack.push(playfield[b][a].charCodeAt(0));
                }
                break;
            }
            case 'p':{
                var b=pop(stack);
                var a=pop(stack);
                var v=pop(stack);
                playfield[b][a]=String.fromCharCode(v);
                break;
            }
            case '&':{
                var result=0,flag=1;
                if(input[0]=='-'){
                    flag=-1;
                    input=input.slice(1);
                }
                while(input.length>0&&'1234567890'.includes(input[0])){
                    result*=10;
                    result+=input.charCodeAt(0)-48;
                    input=input.slice(1);
                }
                while(input.length>0&&!'1234567890'.includes(input[0])){
                    input=input.slice(1);
                }
                stack.push(result*flag)
                break;
            }
            case '~':{
                stack.push(input[0]);
                input=input.slice(1);
                break;
            }
        }
        ipx+=ipdx;
        ipy+=ipdy;
        while(ipx>=playfield.length){
            ipx-=playfield.length;
        }
        while(ipx<0){
            ipx+=playfield.length;
        }
        while(ipy>=maxw||ipy==-1){
            ipy-=maxw;
        }
        while(ipy<0){
            ipy+=maxw;
        }
    }
}