Last active
January 10, 2023 23:36
-
-
Save hornc/7860821f7642e58c9bf217d663ea655e to your computer and use it in GitHub Desktop.
G_arD^EN CorUtY@rD esolang interpreter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Esoteric programming language interpreter for | |
G_arD^EN CorUtY@rD | |
https://esolangs.org/wiki/G_arD%5EEN_CorUtY@rD | |
Interpreter by Salpynx, 2022. | |
""" | |
import sys | |
import re | |
from time import sleep | |
NAME = 'G_arD^EN CorUtY@rD' | |
ARROWS = '>v<^' | |
PAUSE = 0.1 # pause time between frames in seconds | |
DEBUG = False | |
LIMIT = 3000 | |
PRE = '\033[' | |
RST = PRE + '0m' | |
CLR = '\033c' | |
WHITE = '1;37m' | |
BROWN = '0;33m' | |
SOIL = BROWN | |
FENCE = WHITE | |
LCYAN = '1;36m' | |
RED = '1;31m' | |
GREEN = '0;32m' | |
LG = '1;32m' | |
BLUE = '0;34m' | |
PATH = '1;33m' | |
LGREY = '1;37m' | |
GREY = '1;30m' | |
MAGENTA = '1;35m' | |
COLORS = { | |
'x': FENCE, | |
'X': FENCE, | |
'K': FENCE, | |
'L': LCYAN, | |
'#': RED, | |
'~': GREEN, | |
'=': SOIL, | |
'+': BLUE, | |
'-': PATH, | |
':': GREY, | |
'E': GREY, | |
'T': WHITE, | |
'_': RED, | |
'>': LG, | |
'<': LG, | |
'^': LG, | |
'v': LG, | |
'@': MAGENTA, | |
} | |
def color(s): | |
"""Return an ANSI colored string based on first symbol.""" | |
c = COLORS.get(s[0], '0m') | |
return PRE + c + s + RST | |
class GardenCourtyard: | |
def __init__(self, source): | |
self.source = source | |
self.width = len(source[0]) | |
self.height = min([n for n,v in enumerate(source) if '_' in v]) | |
self.ip = self.findfirstchair() | |
self.dir = 0 # 0: right (down, left, up) | |
self.soil = self.source[0][:self.source[0].find('K')].replace('x', '0').replace('X', '1') | |
self.cq = '' # Command queue | |
self.oq = '' # Output queue | |
self.output = '' | |
def findfirstchair(self): | |
for y, line in enumerate(self.source): | |
for x, c in enumerate(line): | |
if c == 'L': | |
return [x, y] | |
def show(self): | |
print(CLR + PRE + MAGENTA + NAME + RST) | |
for j, line in enumerate(self.source): | |
if j == 0: # soil / datastring / fence | |
if len(self.soil) < self.width: | |
line = self.soil + 'K' + line[len(self.soil) + 1:] | |
else: | |
line = self.soil | |
line = line.replace('0', 'x').replace('1', 'X') | |
if j == self.ip[1]: | |
x = self.ip[0] | |
c = line[x] | |
line = line[:x] + '@' + line[x+1:] | |
runs = re.findall(r'((.)\2*)', line) | |
for run in runs: | |
block, symbol = run | |
print(color(block), end='') | |
print() | |
def process(self, c): | |
if c == '~': | |
self.cq += '0' | |
self.dir = 1 | |
elif c == '+': | |
self.cq += '1' | |
self.dir = 0 | |
elif c == '-': | |
if self.soil[-1] == '0': | |
self.dir = 0 | |
else: | |
self.dir = 1 | |
elif c == ':': | |
self.cq += c | |
self.dir = 1 | |
elif c == '=': | |
cc = self.cq[0] | |
self.cq = self.cq[1:] | |
if cc == ':': | |
self.soil = self.soil[1:] | |
else: | |
if self.soil[0] == '1': | |
self.soil = self.soil + cc | |
elif c == 'E': | |
self.oq += self.soil[0] | |
self.soil = self.soil[1:] | |
if len(self.oq) == 8: | |
self.output += chr(int(self.oq, 2)) | |
self.oq = '' | |
#self.dir = 0 | |
elif c in ARROWS: | |
self.dir = ARROWS.find(c) | |
d = self.dir | |
x, y = self.ip | |
if d & 1: | |
y += 1 - (d - 1) | |
else: | |
x += 1 - d | |
self.ip = [x, y] | |
def run(self): | |
running = True | |
i = 0 | |
while running: | |
x, y = self.ip | |
if y == self.height: | |
break | |
self.show() | |
c = self.source[y][x] | |
self.process(c) | |
if DEBUG: | |
print('Current command:', c) | |
print(self.ip, self.dir) | |
print('DATA STRING:', self.soil) | |
print(i) | |
print('CQ:', self.cq) | |
print('OQ:', self.oq) | |
print(f'>:{self.output}') | |
sleep(PAUSE) | |
i += 1 | |
if i > LIMIT: | |
break | |
if __name__ == '__main__': | |
sourcefile = sys.argv[1] | |
source = [] | |
width = 0 | |
with open(sourcefile, 'r') as f: | |
for line in f.readlines(): | |
line = line.strip("\n") | |
width = len(line) | |
source.append(line) | |
gc = GardenCourtyard(source) | |
gc.run() |
I've figured out what is wrong with the reversed output. I mis-interpreted K
as ignorable padding. It actually ends the initial datastring. That makes more sense and I know what to fix. Won't happen today though.
UPDATE: FIXED K:
I've also made the first fence row update to represent the current datastring / 'soil' as the program runs to indicate the current internal state.
The 'soil' modifies the 'fence' -- not sure that makes sense, but it's more to look at.
The command queue is not represented on screen, that might be nice, but all the current examples never get beyong one item in the command queue anyway.
Moved to a repo, now part of: https://github.com/hornc/esointerpreters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is my attempt at an animated ANSI graphics version of an interpreter for G_arD^EN CorUtY@rD
The input command
T
is not yet implemented, and there may be issues with the spec and/or my interpretation of it.The language was designed by https://esolangs.org/wiki/User:BoundedBeans , not me.
Currently the one exampleUPDATE: FIXEDHi
program printsiH
using this 🤷 , but it still looks pretty,The language appealed to me because it was a bitwise cyclic tag variant, and I have been working with BCT a bit so thought it'd be easy to figure out how it was supposed to work, and because the ASCII garden / grid layout has a pleasing game-like feel, and I could see it working with ANSI colours.
I hope someone enjoys this. I'll consider working on it further or moving the code to a proper repo if there is any interest.