B1nary
B1NARY
B1nary is a language developed while UtilityHotbar was attempting to create a tally/prediction machine for use as an example introduction to programming. A combination with a desire to see what only two data values could make, a love of complex looking strings of 0s and 1s and a rudimentary attempt at "entanglement" (the state of the first program affects the state of every other program until the interpreter is restarted) led to several other features and the creation of B1nary.
Introduction
Full name: B1nary (stylised as B1NARY)
Type: Imperative programming
Paradigm: Procedural paradigm
Features: Simple flow control, loops, simple arithmetic
Inspiration (Esolang): Brainfuck, Malbolge and Binaryfuck
Inspiration (Concept): Encryption (Enigma), prediction, entanglement, binary sh*t (Phenomenon in movies where all code is treated as strings of 0s and 1s)
Creator: UtilityHotbar
Concepts
Counter manipulation and the trash function
B1nary has 2 counters, named CTR-0 and CTR-1, which hold a maximum value of 255 and wraps around. Each time 0 is inputted, counter 0 goes up. as such, Counter0 = 6 is represented as
000000
Two "hidden" counters, PREF-0 and PREF-1, track every time 0 or 1 is directly inputted. These counters have no memory limit. Thus, after our previous program, this is the state of the interpreter:
CTR-0: 6 CTR-1: 0 PREF-0: 6 PREF-1: 0 PREF: 0 (We will get to this later)
All other non-command inputs are treated as "trash". Trash is dealt with as thus: the interpreter looks in the command string for the last number (1/0) and assigns the trash to that counter. However, the preference counters are not updated since it is not a 0 or 1. For example, the program "0trash" generates this state:
CTR-0: 6 CTR-1: 0 PREF-0: 1 <-One 0 in the program PREF-1: 0 PREF: 0
These five variables, known as the "state", are stored between command blocks (/). The state can never be reset save an interpreter shutdown. This, the "o" in "Hello" and the "o" in "World" would be programmed differently depending on their place in the program. The "o" in "World" would also be different to the "o" in "world" or the second "o" in "Hello world" or the second "o" in "hello world".
Preference generation
A preference is generated with this sequence:
if CTR-0 is larger than CTR-1:
PREF is 1
else if CTR-1 is larger than CTR-0:
PREF is 1
else:
if PREF-0 is larger than PREF-1:
PREF is 0
else if PREF-1 is larger than PREF-0:
PREF is 1
else:
PREF is LAST_INPUTTED_NUMBER of CURRENT_CODE_BLOCK
if CURRENT_CODE_BLOCK has no 0 or 1:
PREF is 0
Output
Output is created with this formula:
CTR-A - CTR-B + PREF-C - PREF-D + PREF (Where CTR-A >= CTR- B and CTR-C >= CTR-D)
The Unicode symbol with this code point is then outputted.
Syntax and Commands
Programs in B1nary are read left-to-right as a pointer travels along the program, interpreting each character in order.
There are 16 valid commands/characters in B1nary. All others are treated as "?" (trash) including WHITESPACE.
All B1nary commands are as follows (written in pseudo assembly style):
Basic commands:
1 INC CTR-1 & PREF-1 0 INC CTR-0 & PREF-0 ? INC CTR-P [WHERE P IS PREV NUM] ! REV INC->DEC & JMP R->JMP L . OUT CHR ( (ROW-A - ROW-B) + (PREF-C- PREF-D) + PREF ) WHERE A >= B AND C >= D
- Note: (!) Reverses all operations (0 becomes CTR-0 - 1, * Jumps backward(see below)) until the program encounters a second (!)
Loops:
[ STR LOOP ] END LOOP
- Note: All loops function like this: [ defines start point, when the pointer reaches ] it moves to start point. The start point, if undefined, is set to 0. Therefore 0] is a valid program, if not very useful.
Conditions
( STR COND ) END COND - DIV COND < LWR COND TYPE > LGR COND TYPE = EQL COND TYPE | NOT COND TYPE # RTN PREF-P IN COND : RTN CTR-P IN COND * TST COND IF FAIL JMP 1 R
- Note: A condition is created like this: (TYPE-VAL.A-VAL.B) VAL.A and VAL.B can be: :0 (CTR-0), :1 (CTR-1), #0 (PREF-0), #1 (PREF-1), and any binary number (1010)
Conditions have three types: >, <, =, and |. (| means not equal) A new condition immediately overrides the old condition. The condition is tested with * (* can be used at any point in the program after the creation of the condition), which executes the next character if true and skips the next character if false. Except when ! appears, which causes the * to skip backwards in case of failure. A simple multiplication method can be created like this:
4 X 6:
(<-:1-110)[00001*]
Explanation: The program adds 4 to CTR-0 until CTR-1 is no longer smaller than 6 i.e. CTR-1 = 6, at which point the * skips the next character ] , the command to send the loop back to the beginning.
Examples:
H: (RUN WHEN STATE IS 0/0/0/0/0)
(<-:0-100100)[0*]/.
Interpreters:
Original Programmable Output Machine project. Python 3.5.2 (With simple Tkinter interface):
from tkinter import *
import sys
root = Tk()
class b1nary:
def __init__(self,master):
self.rec = {"0":0,"1":0,"p0":0,"p1":0}
self.pref = 0
self.inp = 0 # All inputs
self.cyc = 0 # All valid inputs
self.jump = 0
self.loop = [0,0]
self.cond = []
self.flag = False
self.cgrab = False
self.reverse = False
self.testing = False
self.history = []
self.master = master
master.title("Programmable Output Machine")
mainframe = Frame(master)
mainframe.grid(row=0)
in_field = Entry(master)
def get_in_field():
data = in_field.get()
in_field.delete(0,"end")
self.process(data)
def reset():
self.rec = {"0":0,"1":0,"p0":0,"p1":0}
self.pref = 0
self.inp = 0 # All inputs
self.cyc = 0 # All valid inputs
self.jump = 0
self.loop = [0,0]
self.cond = []
self.flag = False
self.cgrab = False
self.reverse = False
def toggle_test():
if self.testing == False:
self.testing = True
print ('Testing mode is now TRUE')
else:
self.testing = False
print ('Testing mode is now FALSE')
# UI Element definitions
description = Label(master, text="Programmable Output Machine v.1")
get_button = Button(master, text="Submit", command=get_in_field)
tester = Button(master, text="Toggle testing mode", command=toggle_test)
self.status = Label(master, text="Inputs: {} Cycles: {}".format(self.inp,self.cyc))
self.output = Button(master, text="State", command=self.readout)
self.clear = Button(master, text="Reset", command=reset)
# UI Element placement
description.grid(row=0,column=0,columnspan=3,sticky="w")
in_field.grid(row=1,column=0,columnspan=2,sticky="w")
get_button.grid(row=1,column=2,sticky="w")
self.status.grid(row=3,column=2)
self.output.grid(row=2,column=0,sticky="w")
self.clear.grid(row=2,column=1,sticky="w")
tester.grid(row=3,columnspan=2,sticky="w")
self.cycle_update()
def readout(self):
print ('CTR-0: {}'.format(self.rec["0"]))
print ('CTR-1: {}'.format(self.rec["1"]))
print ('PREF-0: {}'.format(self.rec["p0"]))
print ('PREF-1: {}'.format(self.rec["p1"]))
print ('Pref: {}'.format(self.pref))
print ('Cond: {}'.format(self.cond))
def process(self,data):
self.jump = 0
self.loop = [0,0]
self.flag = False
self.cgrab = False
if data == "":
try:
data = self.history[len(self.history)-1]
except:
data = ' '
self.history.append(data)
if self.testing == True:
print ('Data: {}'.format(data))
datalist = data.split('/')
for chunk in datalist:
chunk = list(chunk)
i = 0
while True:
chunk[i] = self.crunch(chunk,chunk[i])
if self.jump > 0:
if self.testing == True:
print ('jumped')
if self.reverse == False:
i += self.jump
else:
i -= self.jump + 2
self.jump = 0
if self.loop[1] > self.loop[0] and self.flag == True:
if self.testing == True:
print ('looping')
self.readout()
i = self.loop[0]
self.flag = False
continue
i += 1
if i > len(chunk)-1:
break
self.update(chunk)
def findnum(self,thing):
n = None
for _ in thing:
if _ in ["1","0"]:
n = _
return n
def prtout(self):
out = 0
if self.rec["0"] > self.rec["1"]:
out += self.rec["0"] - self.rec["1"]
elif self.rec["0"] < self.rec["1"]:
out += self.rec["1"] - self.rec["0"]
if self.rec["p0"] > self.rec["p1"]:
out += self.rec["p0"] - self.rec["p1"]
elif self.rec["p0"] < self.rec["p1"]:
out += self.rec["p1"] - self.rec["p0"]
out += self.pref
return chr(out)
def verify(self):
if self.rec["0"] > 255:
self.rec["0"] -= 255
if self.rec["1"] > 255:
self.rec["1"] -= 255
def crunch(self,chunk,t):
self.inp += 1
self.cyc += 1
if self.testing == True:
print ("Unit: {}".format(t))
if self.cgrab == True and t != ')':
self.cond.append(t)
return t
#0
if t == "0":
if self.reverse == False:
self.rec["0"] += 1
self.rec["p0"] += 1
else:
self.rec["0"] -= 1
self.rec["p0"] += 1
#1
elif t == "1":
if self.reverse == False:
self.rec["1"] += 1
self.rec["p1"] += 1
else:
self.rec["1"] -= 1
self.rec["p1"] += 1
#Output
elif t == '.':
sys.stdout.writelines(self.prtout())
#Loop commands
elif t == '[':
self.loop[0] = chunk.index(t)
elif t == ']':
self.loop[1] = chunk.index(t)
self.flag = True
elif t == "(":
self.cond = []
self.cgrab = True
elif t == ')':
self.cgrab = False
elif t == '*':
if len(self.cond) >= 5:
if self.check(self.cond) == False:
self.jump += 1
elif t == '!':
if self.reverse == False:
self.reverse = True
else:
self.reverse = False
else:
if self.testing == True:
print ('Referring back...')
self.cyc -= 1
getnm = self.findnum(chunk[:chunk.index(t)])
if getnm != None:
if self.reverse == False:
self.rec[getnm] += 1
else:
self.rec[getnm] -= 1
else:
pass
self.verify()
return t
def ref(self,thing):
if thing == ':0':
return self.rec["0"]
elif thing == ':1':
return self.rec["1"]
elif thing == '#0':
return self.rec["p0"]
elif thing == '#1':
return self.rec["p1"]
else:
return int(thing, 2)
def check(self,cnd):
cnd = .join(cnd)
cnd = cnd.split('-')
if self.testing == True:
print (cnd)
a = self.ref(cnd[1])
b = self.ref(cnd[2])
if cnd[0] == '>':
if a > b:
return True
elif cnd[0] == '<':
if a < b:
return True
elif cnd[0] == '=':
if a == b:
return True
elif cnd[0] == '|':
if a != b:
return True
return False
def update(self,chunk):
if self.rec["0"] > self.rec["1"]:
larger = '0'
elif self.rec["1"] > self.rec["0"]:
larger = '1'
else:
if self.rec["p0"] > self.rec["p1"]:
larger = '0'
elif self.rec["p1"] > self.rec["p0"]:
larger = '1'
else:
if self.testing == True:
print ('Defaulting to last num...')
if self.findnum(chunk) != None:
larger = self.findnum(chunk)
else:
if self.testing == True:
print ('Defaulting to 0...')
larger = "0"
if larger == '0':
self.pref = 0
else:
self.pref = 1
def cycle_update(self):
self.status.configure(text="Inputs: {} Cycles: {}".format(self.inp,self.cyc))
self.master.after(1000, self.cycle_update)
print ('Programmable Output Machine (Tk-based B1nary Interpreter) 1.0.0')
print ('Made by UtilityHotbar in 2017')
ai = b1nary(root)