Ndim
Ndim is an esoteric programming language created by User:Schlafhase
In Ndim there are n dimensions. Every program starts with
[number]dim
where number sets the amount of dimensions. So for example
2dim
would be the start of a 2 dimensional ndim program. There is a pointer that points either in the positive or negative direction of an axis in the n dimensional space. Ndim stores 2 values. (similar to a stack). Let's call the first value a and the second value b for this documentation. Every command is stored in a n dimensional coordinate system. You can also store values in the coordinate system. The pointer moves in a specified direction until it hits a command or value. Commands get executed and values get pushed to the stack. The pointer points in the positive direction of the first axis (or `1` in ndim syntax) at the start of every program. And every value is an integer. This language is inspired by befunge
The "stack"
Ndim has a stack-like structure storing two values called a and b. a and b are 0 by default.
Pushing to the stack is done by overwriting the value of b with the current value of a. And then overwriting the value of a with the integer.
Popping from the stack is done by overwriting the value of a with value of b. And then overwriting the value of b with 0.
What does left or right mean?
To get the coordinate to the right of the current coordinate in ndim you use the following code
right = currentCoordinate right[Math.Abs(pointerDirection) % n] += 1
left is the same but with "-="instead of "+=" so
left = currentCoordinate left[Math.Abs(pointerDirection) % n] -= 1
Example
n = 2 currentCoordinate = <10, 20> pointerDirection = -2 right = currentCoordinate //right is <10, 20> after this line right[2 % 2] += 1 //right is <11, 20> after this line
Syntax
Ndim's Syntax looks like this:
[command]<[coordinate]>;
Where command stands for the command and coordinate for the coordinate in the n dimensional coordinate system.
Every line ends with a ";"
Everything behind the ";" will be ignored. Another way to make comments is by writing // at the start of a line.
Note: Every line matching the following regular expression is (probably) a valid line of ndim code
^\s*((-?\d+|\?|jump)|(#\d|pop|swap|duplicate|\+|-|\*|/|\^|&|\||!|<|>)|if\s+\d+|(assignHere|assign|toggleEat|input|printChar|print)|end) *(<)([\d, -]+)(>);
Syntax Highlighting
Download a Highlighting Extension for vscode and use the Ndim configuration file
Commands
Note: Every command needs to have its coordinate specified in <> brackets behind it like described above. The [] brackets stand for parameters of the commands. They are not actually valid syntax.
Command | Description |
---|---|
[number]dim | Specify how many dimensions the program has. Every program must begin with this line. It will throw a Syntax Error if it appears anywhere but on the first line. |
[axis] | Set direction of the pointer to the positive direction of the specified axis. (axis is an integer like everything else) |
-[axis] | Set direction of the pointer to the negative direction of the specified axis. |
? | Set direction of the pointer to a random direction. |
jump | Skip any command that comes immediately after this command. |
#[digit] | Push digit to the stack. |
pop | Pop a value from the stack and discard it. |
swap | Swap the values of a and b. |
duplicate | Overwrite the value of b with a's value. |
+ | Pop the values a and b from the stack and push a + b to the stack. |
- | Pop the values a and b from the stack and push b - a to the stack. |
* | Pop the values a and b from the stack and push a * b to the stack. |
/ | Pop the values a and b from the stack and push b / a to the stack. |
^ | Pop the values a and b from the stack and push b ^ a to the stack. (Math.Pow(b, a) not XOR) |
< | Pop the values a and b from the stack. If b < a push 1 to the stack. |
> | Pop the values a and b from the stack. If b > a push 1 to the stack. |
& | Pop the values a and b from the stack. If a and b are both greater than 0 push 1 to the stack. |
| | Pop the values a and b from the stack. If a or b is greater than 0 push 1 to the stack. |
! | Pop a value a from the stack. If a is greater than 0 push 0 to the stack else push 1. |
if [value] | Pop a value a from the stack. If a is equal to value point the pointer to the right else point the pointer to the left. |
input | Ask for an input and then push it to the stack. Throw Exception if the input is not an integer. |
assign | Pop a value a from the stack and store it to the right of the pointer. (this will overwrite commands and other values stored at that position) |
assignHere | Pop a value a from the stack and store it at the current position of the pointer. (this will overwrite itself) |
toggleEat | Toggles the eat mode. When the eat mode is enabled, commands and values get deleted from the coordinate system after the pointer hit them. (they still get processed one last time) |
Pop a value from the stack and output it. | |
printChar | Pop a value of the stack and output it as a character. |
end | Ends the program. (programs not containing this will run forever) |
Interpreter
You can find a Ndim Interpreter by User:Schlafhase here.
Esoteric IDE
EsotericIDE also supports Ndim. It supports debugging and shows a visualised version of the Ndim program in the Watch window which makes it alot easier to program in Ndim
Examples
Hello, World!
2dim; #9 <0,0>; #8 <1,0>; * <2,0>; //9*8 = 72 assign <3,0>; //store 72 at <3,1> #7 <4,0>; duplicate <5,0>; * <6,0>; //7*7 = 49 #2 <7,0>; * <8,0>; //49*2 = 98 #3 <9,0>; + <10,0>; //98+3 = 101 duplicate <11,0>; assign <12,0>; //store 101 at <12,1> #7 <13,0>; + <14,0>; //101+7 = 108 duplicate <15,0>; assign <16,0>; //store 108 at <16,1> duplicate <17,0>; assign <18,0>; //store 108 at <18,1> #3 <19,0>; + <20,0>; //108+3 = 111 assign <21,0>; //store 111 at <21,1> #6 <22,0>; #7 <23,0>; * <24,0>; //6*7 = 42 #2 <25,0>; + <26,0>; //30+2 = 44 duplicate <27,0>; assign <28, 0>; //store 44 at <28,1> #9 <29,0>; - <30,0>; //44-9 = 35 #3 <31,0>; - <32,0>; //35-3 = 32 assign <33,0>; //store 32 at <33,1> #9 <34,0>; duplicate <35,0>; * <36,0>; //9*9 = 81 #6 <37,0>; + <38,0>; //81+6 = 87 duplicate <39,0>; assign <40,0>; //store 87 at <40,1> #9 <41,0>; + <42,0>; //87+9 = 96 #9 <43,0>; + <44,0>; //96+9 = 105 #6 <45,0>; + <46,0>; //105+6 = 111 duplicate <47,0>; assign <48,0>; //store 111 at <48,1> #3 <49,0>; + <50,0>; //111+3 = 114 duplicate <51,0>; assign <52,0>; //store 114 at <52,1> #6 <53,0>; - <54,0>; //114-6 = 108 duplicate <55,0>; assign <56,0>; //store 108 at <56,1> #8 <57,0>; - <58,0>; //108-8 = 100 assign <59,0>; //store 100 at <59,1> #5 <60,0>; #6 <61,0>; * <62,0>; //5*6 = 30 #3 <63,0>; + <64,0>; //30+3 = 33 assign <65,0>; //store 33 at <65,1> 2 <68,0>; //point the pointer "up" -1 <68,2>; //point the pointer "left" -2 <0,2>; //point the pointer "down" 1 <0,1>; //point the pointer "right" printChar <5,1>; printChar <13,1>; printChar <17,1>; printChar <19,1>; printChar <22,1>; printChar <29,1>; printChar <34,1>; printChar <41,1>; printChar <49,1>; printChar <53,1>; printChar <57,1>; printChar <60,1>; printChar <66,1>; end <67,1>;
readable code
You can use comments to make your code more readable.
2dim; input <0, 0>; if 0 <2, 0>; //{ input <2, 1>; #2 <2, 2>; * <2, 3>; print <2, 4>; end <2, 5>; //} //else //{ input <2, -1>; #3 <2, -2>; * <2, -3>; print <2, -4>; end <2, -5>; //}
But since the order doesn't matter you can arrange the commands however you like!
For example alphabetically:
2dim; //except this line because it has to be at the top #2 <2, 2>; #3 <2, -2>; * <2, 3>; * <2, -3>; end <2, -5>; end <2, 5>; if 0 <2, 0>; input <0, 0>; input <2, -1>; input <2, 1>; print <2, -4>; print <2, 4>;
Factorial
Here is a Ndim program that takes an input x and outputs x! (x factorial). This took me over 5 hours.
3dim; input <0, 0, 0>; //ask for input duplicate <5, 0, 0>; assign <10, 0, 0>; //store input at <10, 1, 0> #2 <15, 0, 0>; < <20, 0, 0>; if 0 <25, 0, 0>; //if input was not smaller than 2 //{ -1 <25, 5, 0>; #1 <24, 5, 0>; //push 1 as starting value 2 <23, 5, 0>; //get previous value -1 <23, 6, 0>; jump <8, 6, 0>; -2 <6, 6, 0>; 1 <6, 4, 0>; 2 <22, 4, 0>; -1 <22, 5, 0>; //add one to previous value #1 <20, 5, 0>; + <15, 5, 0>; duplicate <14, 5, 0>; //store new previous value assign <13, 5, 0>; //<13, 6, 0> //get original input -2 <12, 5, 0>; -1 <12, 1, 0>; 2 <9, 1, 0>; -1 <9, 5, 0>; 2 <8, 5, 0>; > <8, 10, 0>; if 1 <8, 15, 0>; //if the current value is greater than the original input // { //get previous multiplied result and print it -2 <8, 15, 4>; -1 <8, 6, 4>; -3 <-4, 6, 4>; -1 <-4, 6, 0>; print <-6, 6, 0>; end <-7, 6, 0>; // } // else // { //get previous value then go to line <7, 7, 0> -2 <8, 15, -1>; 1 <8, 6, -1>; 3 <13, 6, -1>; -1 <13, 6, 3>; 2 <7, 6, 3>; -3 <7, 7, 3>; //get previous multiplied value -2 <7, 7, 0>; 3 <7, 6, 0>; -1 <7, 6, 1>; -3 <-5, 6, 1>; -1 <-5, 6, -1>; 2 <-6, 6, -1>; 1 <-6, 7, -1>; -2 <1, 7,-1>; 3 <1, 5, -1>; -1 <1, 5, 0>; //multiply both then store the new value * <0, 5, 0>; assign <-5, 5, 0>; //<-5, 6, 0> #1 <-5, 6, 0>; 2 <-13, 5, 0>; 1 <-13, 13, 0>; //go to line 15 -2 <23, 13, 0>; // } //} //else //{ #1 <25, -5, 0>; print <25, -10, 0>; end <25, -15, 0>; //}
You can also do it like this if you like to have your code sorted.
3dim; #1 <-5, 6, 0>; #1 <20, 5, 0>; #1 <24, 5, 0>; #1 <25, -5, 0>; #2 <15, 0, 0>; * <0, 5, 0>; + <15, 5, 0>; -1 <-4, 6, 0>; -1 <-5, 6, -1>; -1 <1, 5, 0>; -1 <12, 1, 0>; -1 <13, 6, 3>; -1 <22, 5, 0>; -1 <23, 6, 0>; -1 <25, 5, 0>; -1 <7, 6, 1>; -1 <8, 6, 4>; -1 <9, 5, 0>; -2 <1, 7,-1>; -2 <12, 5, 0>; -2 <23, 13, 0>; -2 <6, 6, 0>; -2 <7, 7, 0>; -2 <8, 15, -1>; -2 <8, 15, 4>; -3 <-4, 6, 4>; -3 <-5, 6, 1>; -3 <7, 7, 3>; 1 <-13, 13, 0>; 1 <-6, 7, -1>; 1 <6, 4, 0>; 1 <8, 6, -1>; 2 <-13, 5, 0>; 2 <-6, 6, -1>; 2 <22, 4, 0>; 2 <23, 5, 0>; 2 <7, 6, 3>; 2 <8, 5, 0>; 2 <9, 1, 0>; 3 <1, 5, -1>; 3 <13, 6, -1>; 3 <7, 6, 0>; < <20, 0, 0>; > <8, 10, 0>; assign <-5, 5, 0>; assign <10, 0, 0>; assign <13, 5, 0>; duplicate <14, 5, 0>; duplicate <5, 0, 0>; end <-7, 6, 0>; end <25, -15, 0>; if 0 <25, 0, 0>; if 1 <8, 15, 0>; input <0, 0, 0>; jump <8, 6, 0>; print <-6, 6, 0>; print <25, -10, 0>;