# Write a (simplified) BitCycle interpreter

Implement a function or program that can run simplified BitCycle code. The functions you must implement are:

<^>v: Change the direction of a bit to the direction this is pointing.

+: Turn all 0s left and all 1s right.

\ and /: Reflect one bit 90 degrees, then become inactive. In regular BitCycle, this is displayed as - or |, but that isn't required here. There are no collectors in this implementation, so these will never reset.

?: Take one bit at a time from input and send it east until all input is gone. You only need to worry about one input here. Bits only input from ?.

!: Output and delete the bit present here. Only one output is required.

~: Send the inputted bit right and a negated version of it left.

@: When a bit hits this device, terminate the program.

The =, 0, and 1 operations, multiple inputs/outputs, and collectors are not included in this specification. Other than that, everything should behave the same as in regular BitCycle.

## Basic BitCycle Rules

The program itself forms a rectangular grid. A list of bits, either 0 or 1, will be taken as input, and a potentially-empty list of bits will be given as output. Bits travel rightwards at a rate of 1 character per cycle (which is the term I will try to use for each "tick" of the program) until they hit some sort of operation character. In those cases, they will behave as specified by the operator. Code will stop running upon hitting a @ character, or, depending on your output specification, also after some amount of time.

Left-right turns (from +) are relative to the direction of input. For example, if the character entered from the right, 0s will head downwards and 1s upward.

In standard BitCycle, values output as soon as they reach a ! character. However you may instead save all the bits and output them at the end, as long as your interpreter will stop evaluation after some amount of time. Any bit which leaves the grid is destroyed.

For the purpose of this challenge, if it doesn't otherwise interfere with your code (ignoring integer overflow of their position), you may choose to not destroy the bits and just have them continue moving in the direction they were.

All undefined characters are no-ops.

## Example Programs (mostly taken from the BitCycle github)

?!


Cat program

v ~
!+~
?^<


Truth Machine

?  v
~ /
>! <


Negate the first bit, output the rest

?~
@+!


Output all 0s before the first 1

## Rules

This is , so lowest byte count wins.

Standard I/O rules apply for both the bits and the program.

You may choose whether to output as bits, a signed integer, or an unsigned integer, however, you must always be able to handle a case with only 1 or 0 bits as output AND if you don't output as bits, your program must meet the output-at-end rules. This is because any integer-output version wouldn't output anything on an infinite loop unless there was some form of max round number.

If you are outputting all bits at the end, your code must stop after some number of rounds. You may handle this in any "reasonable" way, as long as most simple programs will fully evaluate before your code automatically halts them.

A few examples of a valid method for halting the code:

• A button that shows the round number, and when pressed, outputs all bits and halts the program.
• A program which halts in n cycles, where n based on the number of flags it is given (as long as the max size of n isn't unreasonably small)
• A third input which specifies the number of cycles it should do.
• A program that always halts after 1000 cycles.
• A function which halts after going 100 cycles with no new I/O.
• An overview of how the language works in the post would make it all so much clearer. May 13 at 22:38
• Will the inputted programs be ran normally, under the -u flag (unsigned integers), or under the -U flag (signed integers)? Reason why I'm asking is because programs will have different outputs based on what flag the program is ran under. May 13 at 23:27
• For example, the program 11! will output 11 when ran normally, but will output 2 when ran under the -u or -U flag. May 13 at 23:32
• I would assume that the program is ran normally, as indicated by the truth machine example (it would not output an infinite stream of 1's if under any of the flags). If so, please specify that in the post. May 13 at 23:45
• Undefined behavior, I think. May 17 at 1:01

# Python 3, 442 bytes

def f(s,I):
if[0]>I:return[]
N='\n';l=s.split(N);W=max(map(len,l))+1;s=[*N.join(i.ljust(W-1)for i in l)+N*W];Q=s.index('?');B=[(Q,I.pop(0),1)];O=[];R=999;L=[-1,-W,1,W]
while B*R:
C=[];R-=1
for p,v,d in B:p+=d;c=s[p];z=L[L.index(d)-3];d=dict(zip('<^>v+~\/',L+[z*2*v-z,z,W//d,-W//d])).get(c,d);O+=[v]*(c=='!');R*=c!='@';s[p]=[c,' '][c in'\/'];C+=[(p,1-v,-d)]*(c=='~')+[(p,v,d)]*(c not in'!?\n')
if I:C+=[(Q,I.pop(0),1)]
B=C
return O


Try it online!

Ungolfed:

def f(s, I):
if I == []: return []
l = s.split('\n')
width = max(map(len, l))+1 # including newline
s = list('\n'.join(i.ljust(width-1) for i in l) + '\n'*width)
Q = s.index('?') # location input bits start at
# directions are 1, -1, width, -width corresponding to right, left, down, up
bits = [(Q, I.pop(0), 1)]
O = [] # output
R = 999 # rounds remaining
directions = [-1, -width, 1, width]
while bits and R:
C = []
R -= 1
for pos, val, dir in bits:
pos += dir
char = s[pos]
z = directions[directions.index(dir) - 3] # dir turned right
dir = {'<':-1, '^':-width, '>':1, 'v':width, '+':z*(2*val - 1), '~':z, '\\':width//dir, '/':-width//dir}.get(char, dir)
if char == '!':
O.append(val)
if char == '@':
R = 0
if char in '\/':
s[pos] = ' '
if char == '~':
C.append((pos, 1-val, -dir))
if char not in '!?\n':
C.append((pos, val, dir))
if I:
C.append((Q, I.pop(0), 1))
bits = C
return O


# Python3, 789 bytes:

E=enumerate
def f(p,s):
b=[*map(list,p.split('\n'))]
x,y=[(x,y)for x,a in E(b)for y,c in E(a)if'?'==c][0]
q,C,s,D=[(x,y,0,1,a,[(x,y)],i)for i,a in E(s)],[],[],{(0,1):[(-1,0),(1,0)],(0,-1):[(1,0),(-1,0)],(-1,0):[(0,-1),(0,1)],(1,0):[(0,1),(0,-1)]}
while q:
x,y,X,Y,B,p,I=q.pop(0)
if(p,I)not in s and 0<=(x:=x+X)<len(b)and 0<=(y:=y+Y)<len(b[0]):
s+=[(p,I)]
if(O:=b[x][y])in(L:={'>':(0,1),'<':(0,-1),'v':(1,0),'^':(-1,0)}):q+=[(x,y,*L[O],B,p+[(x,y)],I)]
if'+'==O:q+=[(x,y,*D[(X,Y)][B],B,p+[(x,y)],I)]
if O in['\\','/']:q+=[(x,y,*((Y,X)if X==0 else(0,[1,-1][X==1])),B,p+[(x,y)],I)];b[x][y]=' '
if'~'==O:q+=[(x,y,*D[(X,Y)][0],not B,[(x,y)],I)];q+=[(x,y,*D[(X,Y)][1],B,[(x,y)],I)]
if'!'==O:C+=[int(B)]
if'@'==O:q=[]
if' '==O:q+=[(x,y,X,Y,B,p+[(x,y)],I)]
return C


Try it online!