Marbelous

Designed by Stack Exchange Community 2014 two-dimensional Linear bounded automaton marbelous.py `.mbl`

Marbelous is a two-dimensional esoteric programming language based on numbered marbles falling down a Rube-Goldberg-like board full of devices that move and manipulate the marbles.

History

Creation of this language was inspired by conversation in the Programming Puzzles & Code Golf Stack Exchange chat room, forked to a dedicated chat room later.

Credit for the original idea goes to cjfaure. Additional language design input from Martin Büttner, Nathan Merrill, overactor, sparr, githubphagocyte, es1024, VisualMelon.

Etymology

Marbelous is a portmanteu of "marble" and "marvelous".

Language overview

A Marbelous program consists of one or more two-dimensional "boards". Each board represents a function that can be called during execution, and the first board is called when the program is starte.

Boards may begin with some pre-defined marbles in specific locations, as well as marbles based on parameters passed to the function. There is also a provision for producing a marble containing the value of a byte from stdin. During execution, marbles will fall down a board and interact with the devices that they encounter, sometimes moving in directions other than downwards, sometimes having their value changed.

Instructions

Marbelous has the following devices:

Device Description
`\/` trash bin, which just removes all marbles.
`/\` cloner, which splits any marble and places two identical copies in the cell to its left and to its right.
`\\ //` deflectors which displace any marble one cell to the right or left, respectively.
`++` increments the marble on it and lets it fall through
`--` decrements the marble on it and lets it fall through
`+n` adds n to the marble
`-n` subtracts n from the marble
`>>` shifts bits right (divide by two)
`<<` shifts bits left (multiply by two)
`^n` returns 1 if the nth bit of the marble is 1 and 0 if it's 0. Where ^0 is the least significant bit.
`~~` invert bits (binary not)
`=n` lets marbles equal to n fall through, sends others to the right
`>n` lets marbles greater than to n fall through, sends others to the right
`<n` lets marbles less than to n fall through, sends others to the right
`@n` portal, which transports a marble to the cell beneath a random other portal with the same n
`&n` synchroniser, which stalls a marble until there is a marble on every synchroniser with the same n, when they all fall through
`?n` generates a random marble 0-n
`??` generates a random marble 0 through the value of the input marble
`!!` return from the current board immediately
`}n` will contain the n-th input when a function is invoked. Duplicates of the same }n result in duplicated input values.
`{n` act like a group of synchronisers to collect the outputs. The function terminates when all outputs are filled with a marble (or the termination device, !!, is used). Each {n may be used multiple times, and only one of each n needs to be filled for the function to terminate. If multiple cells are filled, the marbles will be added to give the output.
`{< {>` are additional outputs which appear to the sides of the function device. If present, these need to be filled too, for the board to terminate. They have no effect on the main board.
`]]` reads one byte from stdin which falls, or outputs the input marble to the right

Any device whose defined name ends with "n" actually has 36 variations, from _0 to _Z With the exception of ^n, which has 8 variations, form ^0 to ^7.

Computational class

It is believed that Marbelous is not currently Turing Complete, despite allowing recursion. It is probably a Linear bounded automaton.

Interpretation

The marbelous.py interpreter will run a .mbl program taken from a file. Parameters to the main board may be provided as decimal integers in additional command line arguments. The interpreter also handles stdin and stdout for the program.

Examples

```# prints out "Hello, world!"
48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21

# {0 = }0 + }1
}0 .. }1
\\ {0 //

# {0 = }0 * }1
# masks out bits of }1
# shifts copies of }0 left that many times
# sums shifted copies
.. }1 }1 }1 }1 }1 }1 }1 }1
00 ^7 ^6 ^5 ^4 ^3 ^2 ^1 ^0
.. =1 =1 =1 =1 =1 =1 =1 =1
.. &7 &6 &5 &4 &3 &2 &1 &0
.. }0 .. .. .. .. .. .. ..
.. &7 }0 .. .. .. .. .. ..
.. << &6 }0 .. .. .. .. ..
.. << << &5 }0 .. .. .. ..
.. << << << &4 }0 .. .. ..
.. << << << << &3 }0 .. ..
.. << << << << << &2 }0 ..
.. << << << << << << &1 }0
.. << << << << << << << &0
{0 // // // // // // // //

# calculates the nth fibonacci number, recursively.
:Fb
}0 }0 }0 .. # three copies of }0, call them A B C
-- &0 >1 {0 # decrement A, hold B for sync, return C if it's <2
&0 -- >4 -- # hold A for sync, decrement B, divert and decrement C if it's <5
-- Fb &0 {0 # decrement A, recurse with B, release sync or return C-1
Fb .. \/ .. # recurse with A, do nothing with B, trash C
\\ {0 .. .. # add A to B and return it
# pseudocode equivalent:
# fib(x):
#   A=B=C=x
#   A--
#   if C<2:
#     return C
#   B--
#   if C<5:
#     C--
#     return C
#   A--
#   B=fib(B)
#   A=fib(A)
#   return A+B```