THROBOL

From Esolang
Jump to navigation Jump to search

THROBOL is an esolang by User:BoundedBeans inspired by bowling.

Syntax

It is laid out in a 2d grid, much like Befunge.

Mechanics

Ball

A ball is defined using 'o'. A ball starts moving up. A ball may have a return system written like:

%
|

with the ball directly left of the vertical bar.

Balls have two unbounded non-negative accumulators, power and velocity, a scoreboard, and a pointer to the scoreboard. If the ball does not have a return system, it starts with power 3 and velocity 100, and is deleted once it runs for the first time. A ball with a return system starts with power 2 and velocity 4, and continues doing rounds until both velocity and power are zero.

The pointer always starts at the first scoreboard cell. The ball must run a game before the scoreboard will contain anything, and the second game will always use the first score. Beyond that, the pointer can actually be used. Attempts to move the pointer out of bounds will silently fail, unless the scoreboard contains nothing.

Concurrency

You can have multiple balls for concurrency. They will have different power, velocity, and pointer, but will share the same scoreboard. Each move one tile up in the order they appear in the code in standard English reading order. Ending a round counts as a separate "tick" from getting to the end, so after a ball reaches the command that ends the round, there will be one extra no-op tick. Each ball has its own round schedule (some balls could be on the first game, others could be on the second, some could be on the no-op tick).

Power

Power determines how many pins to each side the ball will score, if they exist, when the ball goes into a tile containing a pin ('A'). Power is saved at the start of the first game, and returns to that value minus one.


Velocity

Velocity decrements every time the ball crosses over a pin. If velocity is zero, the ball will still move, but will no longer score when it hits a pin (including the pins to the side). Velocity is saved at the start of the first game, and returns to that value plus one.

Scoreboard and rounds

The scoreboard contains pairs of unbounded nonnegative integers The ball moves two times each round. The second time, the power is decreased by 1 and the velocity is increased by 1. It then appends the two scores to the scoreboard. The ball then reads the two scores at the pointer, and changes power to the first, and velocity to the second. (If the scoreboard is empty and it is not the first round, the program halts.) It then repeats the process, unless both scores are zero, in which the ball halts.

A ball can run through various commands, allowing things to actually happen.

Commands

Anything that a ball never moves to acts like a comment. Restricting the ball in with a column of vertical bars does the trick as long as no square brackets directly point into it.

A A pin, triggers scoring.
> Move the ball right x cells, where x is the velocity of the ball. If there is '|'s along the way, go directly to the left of the nearest. Remember: the ball always moves up; this only changes the column.
< Move the ball left x cells, where x is the velocity of the ball. If there is '|'s along the way, go directly to the right of the nearest. Remember: the ball always moves up; this only changes the column.
. print the power as an unicode character
: print the power as a number
, input an unicode character into the velocity
; input a number into the velocity
- stop the roll if the number of pins it can hit and score for the roll is zero
= stop the roll no matter what
) move the pointer right
( move the pointer left
] move the ball right one column, no matter the velocity
[ move the ball left one column, no matter the velocity
^ increments the power
v decrements the power
n increments the velocity
u decrements the velocity
" forgets the scoreboard entry at the pointer. Normally changes the current cell to be the one originally more recent, but if the current cell is the last, moves the pointer to the previous score.
? discards the round if the power is zero. The scoreboard will not be added to, but any manual deletion of scoreboard entries will remain.

Additional command guidelines

Any custom commands added by an implementation should be taken from extended ASCII or other Unicode, not 7-bit code points. If two commands absolutely need to share the same character, the implementation should look at whether the character below it is 'W' (the escape character, with no particular significance) to decide which command to use. 'W' does not escape commands unless the ball specifically goes over it; it puts the next command into a different "mode". 'W' can also be layered; for example, you could have four commands, ¥, W¥, WW¥ and WWW¥. 'W' should not be used for any other purpose. Custom escaped 'W' commands should not use 7-bit code points as the non-'W' part.

Examples

Print 'A'

=======
 .
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
 ^
     <%
     o|


Computational class

This proof is incorrect because dequeueing also enqueues a garbage 0 power 2 velocity value which will mess things up when it's at the front. This is tricky to solve because:

  • The garbage value goes at the back of the queue and looping can't be done in one turn (making it difficult to get the pointer to the back, delete it, and return to the front)
  • The garbage value has the same velocity as a normal queue element, and testing power isn't really possible without scoring.
  • While we can discard the round if the power is zero, that doesn't accomplish the need to remove the element conditionally.
  • Multithreading might help, but it would still be tricky to detect the power from another thread.

If there was a way for the net effect of multiple rounds to act like a single round without scoring, that would fix this issue.

We can initialize the first score to 2 2 with a lane that looks like:


    =
  ] AA
>    |
 %
o|

Then in the next round, the lane will always be in the same column regardless of whether the velocity is 2 or 3, and we can continue the lane upwards.

We can then input a numerical command each round from the console. First we'll check that the velocity is 2 (making sure it's the first roll), and make sure it's two for the next round if it's not.

   =
   A
   A
>   |

We'll then do the actual inputting using ;

Then we check if 1 was inputted (dequeue):


 =
 "
>  |


Then we check if 2 (enqueue 1) or 3 (enqueue 2) was inputted.

  ==
   A
  AA
  AA
  ??
  vv
  vv
>   |


This is the full sequential tag interpreter:


  ==
   A
  AA
  AA
  ??
  vv
  vv
>   |
 [
  [
 =
 "
>  |
   =
 [ A
  [A
>   |
 [
  [
   [
   ;=
  ] AA
>    |
 %
o|

Notes

  • 0 is stored as 2 2, 1 is stored as 3 2.
  • This never uses the commands .,;-()^vnu so these are unnecessary for Turing-completeness. It's likely it could be minimized even more, but I'm not sure how.

THROBOL-2

THROBOL-2 is a variation of THROBOL with two more instructions:

} Move the ball right x cells, where x is the power of the ball. If there is '|'s along the way, go directly to the left of the nearest. Remember: the ball always moves up; this only changes the column.
{ Move the ball left x cells, where x is the power of the ball. If there is '|'s along the way, go directly to the right of the nearest. Remember: the ball always moves up; this only changes the column.

These two instructions make THROBOL-2 much easier to prove Turing-complete, using this sequential tag interpreter based on the one in the incorrect proof above. In fact, only one is needed, just to insert the red marked code into the sequential tag interpreter to make it actually work.

  ==
   A
  AA
  AA
  ??
  vv
  vv
>   |
 [
  [
 =
 "
>  |
   =
 [ A
  [A
>   |
 [
  [
   [
   ;=
  ] AA
>    |
 [
=
"
} |
 %
o|

This means the most minimal Turing-complete subset of THROBOL-2 currently known is =A?v>[";]}. That is, {<.:,-()^nu are unnecessary for Turing-completeness.