Last active
November 19, 2020 04:54
-
-
Save lynn/914087eb06580608d34ca1b83a214baf to your computer and use it in GitHub Desktop.
Cardinal 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 python3 | |
# usage: | |
# python3 cardinal.py code.cardinal < input.txt | |
# to show program execution, pass -d and a time delta: | |
# python3 cardinal.py -d 0.1 code.cardinal < input.txt | |
import sys | |
import time | |
DIRS = [(0, -1), (0, +1), (-1, 0), (+1, 0)] | |
class IP: | |
def __init__(self, pos, direction): | |
self.pos = pos | |
self.direction = direction | |
self.quit = False | |
self.alive = True | |
self.a = self.i = 0 | |
self.wait = 0 | |
self.remove_after = False | |
self.output_mode = False | |
def go(self): | |
if self.wait > 0: | |
self.wait -= 1 | |
return | |
command = code.get(self.pos, ' ') | |
x, y = self.pos | |
dx, dy = self.direction | |
if command == '"': | |
self.output_mode = not self.output_mode | |
elif self.output_mode: | |
sys.stdout.write(command) | |
elif command == ' ': | |
pass | |
elif command == '#': | |
self.alive = False | |
for d in DIRS: | |
if d == (-dx, -dy): | |
continue | |
copy = IP((x + d[0], y + d[1]), d) | |
copy.a = self.a | |
copy.i = self.i | |
copy.remove_after = self.remove_after | |
ips.append(copy) | |
elif command == '^': | |
self.direction = (0, -1) | |
elif command == 'v': | |
self.direction = (0, +1) | |
elif command == '<': | |
self.direction = (-1, 0) | |
elif command == '>': | |
self.direction = (+1, 0) | |
elif command == 'x': | |
self.alive = False | |
elif command == '@': | |
self.quit = True | |
elif command == '?' and self.a == 0: | |
self.alive = False | |
elif command == '!' and self.a != 0: | |
self.alive = False | |
elif command == '/': | |
code[x, y] = '\\' | |
self.direction = (-dy, -dx) | |
elif command == '\\': | |
code[x, y] = '/' | |
self.direction = (dy, dx) | |
elif command == '~': | |
self.a, self.i = self.i, self.a | |
elif command == '+': | |
self.a += 1 | |
elif command == '-': | |
self.a -= 1 | |
elif command == 't': | |
self.a *= self.i | |
elif command == 'd': | |
self.a /= self.i | |
elif command == '*': | |
self.a += self.i | |
elif command == "'": | |
self.a -= self.i | |
elif command == 'M': | |
self.a %= self.i | |
elif command == '&': | |
self.a = 1 if self.a and self.i else 0 | |
elif command == '|': | |
self.a = 1 if self.a or self.i else 0 | |
elif command == 'X': | |
self.a = 1 if (self.a == 0) != (self.i == 0) else 0 | |
elif command == 'O': | |
self.direction = (-dy, dx) | |
elif command == 'o': | |
self.direction = (dy, -dx) | |
elif command == ':': | |
self.a = int(input()) | |
elif command == '.': | |
sys.stdout.write(str(self.a)) | |
elif command == ',': | |
sys.stdout.write(chr(self.a)) | |
elif command == ';': | |
sys.stdout.write('\n') | |
elif command == '=': | |
self.i = self.a | |
elif command in '`': | |
self.remove_after = not self.remove_after | |
elif command in 'nu()': | |
pdx, pdy = DIRS['nu()'.index(command)] | |
code[x + pdx, y + pdy] = chr(self.a) | |
self.a = ord(code[x - pdx, y - pdy]) | |
if self.remove_after: | |
self.alive = False | |
elif command in 'VA}{': | |
if self.direction == DIRS['VA}{'.index(command)]: | |
self.alive = False | |
elif command == '0': | |
self.a = 0 | |
elif command == 'N': | |
self.direction = (-dx, dy) | |
elif command == 'Z': | |
self.direction = (dx, -dy) | |
elif command == 'I': | |
self.direction = (-dx, -dy) | |
elif command in 'UDLR': | |
if self.a > 0: | |
self.direction = DIRS['UDLR'.index(command)] | |
elif command == '8': | |
self.wait = 3 | |
elif command == '$': | |
x, y = self.a, self.i | |
elif command == 'J' and self.a > 0 or command == 'j' and self.a == 0: | |
x += dx | |
y += dy | |
# Move the pointer | |
dx, dy = self.direction | |
x += dx | |
y += dy | |
self.pos = x, y | |
if x < 0 or x > max_x or y < 0 or y > max_y: | |
self.alive = False | |
if len(sys.argv) < 2: | |
sys.stderr.write('usage: {0} code\n'.format(sys.argv[0])) | |
sys.exit(1) | |
debug = False | |
if sys.argv[1] == '-d': | |
time_delta = float(sys.argv[2]) | |
debug = True | |
del sys.argv[1:3] | |
ips = [] | |
code = {} | |
max_x = max_y = 0 | |
with open(sys.argv[1]) as f: | |
for y, line in enumerate(f): | |
for x, char in enumerate(line.rstrip('\n')): | |
code[x, y] = char | |
if char == '%': | |
for d in DIRS: | |
ips.append(IP((x, y), d)) | |
max_x = max(max_x, x) | |
max_y = max(max_y, y) | |
while ips: | |
if debug: | |
sys.stderr.write('\n' * 5) | |
rows = [] | |
for y in range(max_y): | |
row = [] | |
for x in range(max_x): | |
row.append(code.get((x, y), ' ')) | |
rows.append(row) | |
for ip in ips: | |
x, y = ip.pos | |
if 0 <= y < max_y and 0 <= x < max_x: | |
rows[y][x] = '\x1b[31m@\x1b[0m' | |
for row in rows: | |
sys.stderr.write(''.join(row) + '\n') | |
time.sleep(time_delta) | |
for ip in ips[:]: | |
ip.go() | |
if any(ip.quit for ip in ips): | |
break | |
ips = [ip for ip in ips if ip.alive] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment