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)