THROBOL is an esolang by User:BoundedBeans inspired by bowling.
It is laid out in a 2d grid, much like Befunge.
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.
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 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 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.
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.
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. |
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.
=======
.
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
<%
o|
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:
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|
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.
IDENTIFICATION DIVISION.
PROGRAM-ID. THROBOL.
*COBOL-THROBOL BY BOUNDED-BEANS/KRONOSTA
*FEATURES:
*- CODE SPACE UP TO 999 LINES OF 999 CHARACTERS EACH
*- UP TO 9999 SCOREBOARD ENTRIES
*- VELOCITY AND POWER UP TO 999 SINCE ANY MORE WOULDN'T DO MUCH
* WITH THE CODE SIZE LIMITS.
*- UP TO 50 BALLS (THREADS)
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CODE-FILE ASSIGN TO CODE-FILENAME
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD CODE-FILE.
01 CODE-FILE-DATA.
05 CODE-FILE-LINE PIC X(999) VALUE SPACES.
WORKING-STORAGE SECTION.
01 ARGV PIC X(7) VALUE SPACES.
01 DEBUG-ON PIC 9 VALUE 0.
01 CODE-FILENAME PIC X(100).
01 CODE-EOF PIC 9 VALUE 0.
01 CI PIC 999 VALUE 1.
01 CJ PIC 999 VALUE 1.
01 CODE-SPACE.
05 CODE-CURRENT-ARG-LINE PIC X(999).
*AN ELEMENT OF CODE-LINES IS A ROW (A Y INDEX)
*AN ELEMENT OF CODE-CHARS IS A CHARACTER (AN X INDEX)
05 CODE-LINES OCCURS 999 TIMES.
10 CODE-CHARS OCCURS 999 TIMES PIC X.
01 SI PIC 9999 VALUE 1.
01 SCOREBOARD.
05 SI-2 PIC 9999.
05 SCOREBOARD-ENTRY OCCURS 9999 TIMES.
10 SCOREBOARD-DATA.
15 SCOREBOARD-POWER PIC 9(3).
15 SCOREBOARD-VELOCITY PIC 9(3).
10 SCOREBOARD-EXISTS PIC 9 VALUE 0.
05 SCOREBOARD-HOLDER-DATA.
10 SCOREBOARD-HOLDER-POWER PIC 9(3).
10 SCOREBOARD-HOLDER-VELOCITY PIC 9(3).
05 SCOREBOARD-LENGTH PIC 9999 VALUE 0.
05 SCOREBOARD-ADDED-TO PIC 9 VALUE 0.
01 BI PIC 99 VALUE 1.
01 BALLS.
05 BALLS-CURRENT-RETURN-POSSIBLE PIC 9.
*SINCE NEW BALLS CAN NEVER BE CREATED, WE CAN OPTIMIZE SOME
*OF THE BALL TURN-TAKING TO RUN LESS THAN 50 ITERATIONS IN MOST
*SCENARIOS. HOWEVER, BALLS WITHOUT A RETURN SYSTEM DISAPPEAR
*QUICKLY, SO SOME BALLS MIGHT NOT EXIST IN THE MIDDLE, WHICH
*IS TRICKIER TO OPTIMIZE. THOUGH YOU PROBABLY COULD OPTIMIZE THAT,
*I WON'T.
05 BALLS-LAST-INDEX PIC 99.
05 BSPI PIC 9.
05 BALL OCCURS 50 TIMES.
10 BALL-DATA.
15 BALL-POWER PIC 9(3) VALUE 3.
15 BALL-VELOCITY PIC 9(3) VALUE 100.
15 BALL-SAVED-POWER PIC 9(3).
15 BALL-SAVED-VELOCITY PIC 9(3).
15 BALL-POINTER PIC 9(4) VALUE 1.
10 BALL-SCORE.
15 BALL-SCORE-PAD OCCURS 2 TIMES PIC 9(3) VALUE 0.
15 BALL-SCORE-INDEX PIC 9 VALUE 1.
10 BALL-ENDING-ROUND PIC 9 VALUE 0.
10 BALL-ROUND-DISCARDED PIC 9 VALUE 0.
10 BALL-POSITION.
15 BALL-X PIC 9(3).
15 BALL-Y PIC 9(3).
10 BALL-RETURN.
15 BALL-RETURN-X PIC 9(3).
15 BALL-RETURN-Y PIC 9(3).
15 BALL-RETURN-EXISTS PIC 9 VALUE 0.
10 BALL-EXISTS PIC 9 VALUE 0.
01 PINS-KNOCKED PIC 999.
01 VELOCITY-COUNTER PIC 999.
01 POWER-COUNTER PIC 999.
01 IO-CHAR USAGE BINARY-CHAR.
01 IO-SHORT USAGE BINARY-SHORT.
PROCEDURE DIVISION.
MAIN.
MOVE 1 TO CI.
PERFORM PARSE-ARGS.
PERFORM FIND-BALLS.
PERFORM EXECUTE.
STOP RUN.
PARSE-ARGS.
PERFORM UNTIL NOT ARGV > LOW-VALUES
MOVE LOW-VALUES TO ARGV
ACCEPT ARGV FROM ARGUMENT-VALUE
EVALUATE TRUE
WHEN ARGV = '-F'
IF DEBUG-ON = 1 THEN
DISPLAY 'THROBOL FROM FILE'
END-IF
ACCEPT CODE-FILENAME FROM ARGUMENT-VALUE
IF DEBUG-ON = 1 THEN
DISPLAY 'THROBOL FILE: ' CODE-FILENAME
END-IF
PERFORM READ-FILE
WHEN ARGV = '-L'
IF DEBUG-ON = 1 THEN
DISPLAY 'THROBOL FROM ARGS'
END-IF
PERFORM READ-ARGS
WHEN ARGV = '-D'
MOVE 1 TO DEBUG-ON
END-EVALUATE
END-PERFORM.
READ-FILE.
IF DEBUG-ON = 1 THEN
DISPLAY 'START READING FILE'
END-IF.
OPEN INPUT CODE-FILE.
PERFORM UNTIL CODE-EOF = 1
READ CODE-FILE
AT END
MOVE 1 TO CODE-EOF
NOT AT END
MOVE CODE-FILE-LINE TO CODE-LINES(CI)
ADD 1 TO CI
END-READ
END-PERFORM.
CLOSE CODE-FILE.
IF DEBUG-ON = 1 THEN
DISPLAY 'FINISH READING FILE'
END-IF.
READ-ARGS.
IF DEBUG-ON = 1 THEN
DISPLAY 'START READING ARGS'
END-IF.
ACCEPT CODE-CURRENT-ARG-LINE FROM ARGUMENT-VALUE.
PERFORM UNTIL CODE-CURRENT-ARG-LINE = 'END'
MOVE CODE-CURRENT-ARG-LINE TO CODE-LINES(CI)
ADD 1 TO CI
ACCEPT CODE-CURRENT-ARG-LINE FROM ARGUMENT-VALUE
END-PERFORM.
IF DEBUG-ON = 1 THEN
DISPLAY 'FINISH READING ARGS'
END-IF.
FIND-BALLS.
IF DEBUG-ON = 1 THEN
DISPLAY 'START FINDING BALLS'
END-IF
MOVE 1 TO BI.
MOVE 1 TO CJ.
MOVE 1 TO CI.
PERFORM UNTIL CI = 0 OR BI > 50
IF CODE-CHARS(CI,CJ) = 'o' THEN
MOVE 1 TO BALLS-CURRENT-RETURN-POSSIBLE
MOVE 1 TO BALL-EXISTS(BI)
MOVE CI TO BALL-Y(BI)
MOVE CJ TO BALL-X(BI)
IF CI > 1 AND CJ < 999 THEN
ADD 1 TO CJ
IF NOT CODE-CHARS(CI,CJ) = '|' THEN
MOVE 0 TO BALLS-CURRENT-RETURN-POSSIBLE
END-IF
SUBTRACT 1 FROM CI
IF NOT CODE-CHARS(CI,CJ) = '%' THEN
MOVE 0 TO BALLS-CURRENT-RETURN-POSSIBLE
END-IF
SUBTRACT 1 FROM CJ
ADD 1 TO CI
ELSE
MOVE 0 TO BALLS-CURRENT-RETURN-POSSIBLE
END-IF
IF BALLS-CURRENT-RETURN-POSSIBLE = 1 THEN
MOVE CI TO BALL-RETURN-Y(BI)
MOVE CJ TO BALL-RETURN-X(BI)
MOVE 1 TO BALL-RETURN-EXISTS(BI)
MOVE 2 TO BALL-POWER(BI)
MOVE 4 TO BALL-VELOCITY(BI)
MOVE 2 TO BALL-SAVED-POWER(BI)
MOVE 4 TO BALL-SAVED-VELOCITY(BI)
END-IF
ADD 1 TO BI
IF DEBUG-ON = 1 THEN
DISPLAY 'FOUND BALL AT X = ' CJ ', Y = ' CI
WITH NO ADVANCING
IF BALLS-CURRENT-RETURN-POSSIBLE = 1 THEN
DISPLAY ' WITH RETURN SYSTEM'
WITH NO ADVANCING
END-IF
DISPLAY ' '
END-IF
END-IF
ADD 1 TO CJ
IF CJ = 0 THEN
MOVE 1 TO CJ
ADD 1 TO CI
END-IF
END-PERFORM.
MOVE BI TO BALLS-LAST-INDEX.
IF DEBUG-ON = 1 THEN
DISPLAY 'FINISHED FINDING BALLS'
END-IF.
EXECUTE.
PERFORM EXECUTE-ALL-TURNS UNTIL SCOREBOARD-LENGTH = 0 AND
SCOREBOARD-ADDED-TO = 1.
EXECUTE-ALL-TURNS.
PERFORM EXECUTE-TURN VARYING BI FROM 1 BY 1 UNTIL BI =
BALLS-LAST-INDEX.
EXECUTE-TURN.
IF SCOREBOARD-LENGTH = 0 AND SCOREBOARD-ADDED-TO = 1 THEN
GOBACK
END-IF.
IF BALL-EXISTS(BI) = 0 THEN
GOBACK
END-IF.
IF BALL-ENDING-ROUND(BI) = 1 OR BALL-ROUND-DISCARDED(BI) = 1
THEN
IF BALL-ENDING-ROUND(BI) = 1 THEN
IF DEBUG-ON = 1 THEN
DISPLAY 'ROUND ENDED AT X = ' BALL-X(BI) ' Y = '
BALL-Y(BI)
END-IF
MOVE 0 TO BALL-ENDING-ROUND(BI)
IF BALL-RETURN-EXISTS(BI) = 1 THEN
MOVE BALL-RETURN-X(BI) TO BALL-X(BI)
MOVE BALL-RETURN-Y(BI) TO BALL-Y(BI)
ELSE
MOVE 0 TO BALL-EXISTS(BI)
END-IF
IF BALL-SCORE-INDEX(BI) = 1 THEN
MOVE 2 TO BALL-SCORE-INDEX(BI)
MOVE BALL-SAVED-VELOCITY(BI) TO BALL-VELOCITY(BI)
MOVE BALL-SAVED-POWER(BI) TO BALL-POWER(BI)
ADD 1 TO BALL-VELOCITY(BI)
SUBTRACT 1 FROM BALL-POWER(BI)
ELSE
ADD 1 TO SCOREBOARD-LENGTH
MOVE SCOREBOARD-LENGTH TO SI
MOVE BALL-SCORE-INDEX(BI) TO BSPI
MOVE BALL-SCORE-PAD(BI,1) TO
SCOREBOARD-POWER(SI)
MOVE BALL-SCORE-PAD(BI,2) TO
SCOREBOARD-VELOCITY(SI)
MOVE 1 TO BALL-SCORE-INDEX(BI)
MOVE 1 TO SCOREBOARD-ADDED-TO
MOVE BALL-POINTER(BI) TO SI
MOVE SCOREBOARD-POWER(SI) TO BALL-POWER(BI)
MOVE SCOREBOARD-VELOCITY(SI) TO BALL-VELOCITY(BI)
MOVE BALL-POWER(BI) TO BALL-SAVED-POWER(BI)
MOVE BALL-VELOCITY(BI) TO BALL-SAVED-VELOCITY(BI)
MOVE 0 TO BALL-SCORE-PAD(BI,1)
MOVE 0 TO BALL-SCORE-PAD(BI,2)
END-IF
ELSE
MOVE 0 TO BALL-ROUND-DISCARDED(BI)
IF BALL-RETURN-EXISTS(BI) = 1 THEN
MOVE BALL-RETURN-X(BI) TO BALL-X(BI)
MOVE BALL-RETURN-Y(BI) TO BALL-Y(BI)
ELSE
MOVE 0 TO BALL-EXISTS(BI)
END-IF
MOVE 1 TO BALL-SCORE-INDEX(BI)
END-IF
IF DEBUG-ON = 1 THEN
DISPLAY 'SCOREBOARD:' WITH NO ADVANCING
PERFORM VARYING SI FROM 1 BY 1
UNTIL SI=10
DISPLAY "[" SCOREBOARD-POWER(SI) ","
SCOREBOARD-VELOCITY(SI) "]"
WITH NO ADVANCING
END-PERFORM
DISPLAY " "
END-IF
ELSE
SUBTRACT 1 FROM BALL-Y(BI)
IF BALL-Y(BI) = 0 THEN
DISPLAY "ERROR: BALL FELL OFF THE TOP EDGE OF THE " &
"PROGRAM"
END-IF
MOVE BALL-Y(BI) TO CI
MOVE BALL-X(BI) TO CJ
IF DEBUG-ON = 1 THEN
DISPLAY X"0A"
"BALL AT X = " BALL-X(BI) " Y = " BALL-Y(BI)
"CHAR IS '" CODE-CHARS(CI,CJ) "'"
END-IF
EVALUATE TRUE
WHEN CODE-CHARS(CI,CJ) = 'A'
IF NOT BALL-VELOCITY(BI) = 0 THEN
MOVE 1 TO PINS-KNOCKED
MOVE BALL-X(BI) TO CJ
MOVE BALL-POWER(BI) TO POWER-COUNTER
ADD 1 TO POWER-COUNTER
PERFORM UNTIL CJ = 0 OR NOT CODE-CHARS(CI,CJ)
= 'A' OR POWER-COUNTER = 0
SUBTRACT 1 FROM POWER-COUNTER
ADD 1 TO CJ
ADD 1 TO PINS-KNOCKED
END-PERFORM
MOVE BALL-X(BI) TO CJ
MOVE BALL-POWER(BI) TO POWER-COUNTER
ADD 1 TO POWER-COUNTER
PERFORM UNTIL CJ = 0 OR NOT CODE-CHARS(CI,CJ)
= 'A' OR POWER-COUNTER = 0
SUBTRACT 1 FROM POWER-COUNTER
SUBTRACT 1 FROM CJ
ADD 1 TO PINS-KNOCKED
END-PERFORM
SUBTRACT 2 FROM PINS-KNOCKED
MOVE BALL-SCORE-INDEX(BI) TO BSPI
ADD PINS-KNOCKED TO BALL-SCORE-PAD(BI,BSPI)
SUBTRACT 1 FROM BALL-VELOCITY(BI)
IF DEBUG-ON = 1 THEN
DISPLAY "KNOCKED " PINS-KNOCKED "PINS!"
END-IF
END-IF
WHEN CODE-CHARS(CI,CJ) = '>'
MOVE BALL-VELOCITY(BI) TO VELOCITY-COUNTER
ADD 1 TO VELOCITY-COUNTER
PERFORM UNTIL VELOCITY-COUNTER = 0 OR
CODE-CHARS(CI,CJ) = '|' OR CJ = 0
ADD 1 TO BALL-X(BI)
MOVE BALL-X(BI) TO CJ
SUBTRACT 1 FROM VELOCITY-COUNTER
END-PERFORM
SUBTRACT 1 FROM BALL-X(BI)
WHEN CODE-CHARS(CI,CJ) = '<'
MOVE BALL-VELOCITY(BI) TO VELOCITY-COUNTER
ADD 1 TO VELOCITY-COUNTER
PERFORM UNTIL VELOCITY-COUNTER = 0 OR
CODE-CHARS(CI,CJ) = '|' OR CJ = 0
SUBTRACT 1 FROM BALL-X(BI)
MOVE BALL-X(BI) TO CJ
SUBTRACT 1 FROM VELOCITY-COUNTER
END-PERFORM
ADD 1 TO BALL-X(BI)
WHEN CODE-CHARS(CI,CJ) = '.'
MOVE BALL-POWER(BI) TO IO-CHAR
CALL "printf" USING X"256300" BY VALUE IO-CHAR
WHEN CODE-CHARS(CI,CJ) = ':'
MOVE BALL-POWER(BI) TO IO-SHORT
CALL "printf" USING X"25640A00"
BY VALUE IO-SHORT
END-CALL
WHEN CODE-CHARS(CI,CJ) = ','
CALL "scanf" USING
X"256300"
BY REFERENCE IO-CHAR
END-CALL
MOVE IO-CHAR TO BALL-VELOCITY(BI)
WHEN CODE-CHARS(CI,CJ) = ';'
CALL "scanf" USING
X"25642000"
BY REFERENCE IO-SHORT
END-CALL
MOVE IO-CHAR TO BALL-VELOCITY(BI)
WHEN CODE-CHARS(CI,CJ) = '-'
IF BALL-VELOCITY(BI) = 0 THEN
MOVE 1 TO BALL-ENDING-ROUND(BI)
END-IF
WHEN CODE-CHARS(CI,CJ) = '='
MOVE 1 TO BALL-ENDING-ROUND(BI)
WHEN CODE-CHARS(CI,CJ) = ')'
ADD 1 TO BALL-POINTER(BI)
ON SIZE ERROR
SUBTRACT 1 FROM BALL-POINTER(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = '('
SUBTRACT 1 FROM BALL-POINTER(BI)
ON SIZE ERROR
ADD 1 TO BALL-POINTER(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = ']'
ADD 1 TO BALL-X(BI)
ON SIZE ERROR
SUBTRACT 1 FROM BALL-X(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = '['
SUBTRACT 1 FROM BALL-X(BI)
ON SIZE ERROR
ADD 1 TO BALL-X(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = '^'
ADD 1 TO BALL-POWER(BI)
ON SIZE ERROR
SUBTRACT 1 FROM BALL-POWER(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = 'v'
SUBTRACT 1 FROM BALL-POWER(BI)
ON SIZE ERROR
ADD 1 TO BALL-POWER(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = 'n'
ADD 1 TO BALL-VELOCITY(BI)
ON SIZE ERROR
SUBTRACT 1 FROM BALL-VELOCITY(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = 'u'
SUBTRACT 1 FROM BALL-VELOCITY(BI)
ON SIZE ERROR
ADD 1 TO BALL-VELOCITY(BI)
END-ADD
WHEN CODE-CHARS(CI,CJ) = '"'
MOVE BALL-POINTER(BI) TO SI
PERFORM UNTIL SCOREBOARD-EXISTS(SI)=0 OR
SI = SCOREBOARD-LENGTH
ADD 1 TO SI
MOVE SCOREBOARD-DATA(SI) TO
SCOREBOARD-HOLDER-DATA
SUBTRACT 1 FROM SI
MOVE SCOREBOARD-HOLDER-DATA TO
SCOREBOARD-DATA(SI)
END-PERFORM
SUBTRACT 1 FROM SCOREBOARD-LENGTH
WHEN CODE-CHARS(CI,CJ) = '?'
MOVE 1 TO BALL-ROUND-DISCARDED(BI)
END-EVALUATE
END-IF.