Created
April 2, 2016 04:06
-
-
Save jsbueno/1c2a2a74490702215597ea54dccf2a6e to your computer and use it in GitHub Desktop.
Python Piet interpreter - just some slightly modernized code of the one listed in Piet resources at: http://www.dangermouse.net/esoteric/piet/tools.html
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 | |
from __future__ import print_function | |
version = __version__ = '1.1' | |
# Author- Ross Tucker | |
# Thanks to Marc Majcher for his project, Piet.pl | |
from PIL import Image # Python Imaging Library | |
from operator import itemgetter | |
import sys | |
HEX_BLACK = '0x000000' | |
HEX_WHITE = '0xffffff' | |
hex2tuple = { | |
'0xffc0c0':{'color':'light red','abbv':'lR','hue':0,'dark':0}, | |
'0xffffc0':{'color':'light yellow','abbv':'lY','hue':1,'dark':0}, | |
'0xc0ffc0':{'color':'light green','abbv':'lG','hue':2,'dark':0}, | |
'0xc0ffff':{'color':'light cyan','abbv':'lC','hue':3,'dark':0}, | |
'0xc0c0ff':{'color':'light blue','abbv':'lB','hue':4,'dark':0}, | |
'0xffc0ff':{'color':'light magenta','abbv':'lM','hue':5,'dark':0}, | |
'0xff0000':{'color':'red','abbv':' R','hue':0,'dark':1}, | |
'0xffff00':{'color':'yellow','abbv':' Y','hue':1,'dark':1}, | |
'0x00ff00':{'color':'green','abbv':' G','hue':2,'dark':1}, | |
'0x00ffff':{'color':'cyan','abbv':' C','hue':3,'dark':1}, | |
'0x0000ff':{'color':'blue','abbv':' B','hue':4,'dark':1}, | |
'0xff00ff':{'color':'magenta','abbv':' M','hue':5,'dark':1}, | |
'0xc00000':{'color':'dark red','abbv':'dR','hue':0,'dark':2}, | |
'0xc0c000':{'color':'dark yellow','abbv':'dY','hue':1,'dark':2}, | |
'0x00c000':{'color':'dark green','abbv':'dG','hue':2,'dark':2}, | |
'0x00c0c0':{'color':'dark cyan','abbv':'dC','hue':3,'dark':2}, | |
'0x0000c0':{'color':'dark blue','abbv':'dB','hue':4,'dark':2}, | |
'0xc000c0':{'color':'dark magenta','abbv':'dM','hue':5,'dark':2}, | |
'0xffffff':{'color':'white','abbv':'Wt','hue':-1,'dark':-1}, | |
'0x000000':{'color':'black','abbv':'Bk','hue':-1,'dark':-1} | |
} | |
do_arr = [["NOOP", "PUSH", "POP"], | |
["ADD", "SUB", "MULT"], | |
["DIV", "MOD", "NOT"], | |
["GTR", "PNTR", "SWCH"], | |
["DUP", "ROLL", "N_IN"], | |
["C_IN", "NOUT", "COUT"]] | |
class PVM(object): | |
def __init__(self): | |
self.dp = 0 | |
self.cc = -1 | |
self.stack = [] | |
self.block_value = 1 | |
def NOOP(self): | |
pass | |
def PUSH(self): | |
self.stack.append(self.block_value) | |
def POP(self): | |
if len(self.stack) < 1: | |
return | |
self.stack.pop() | |
def ADD(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(next + top) | |
def SUB(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(next - top) | |
def MULT(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(next*top) | |
def DIV(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(next // top) | |
def MOD(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(next % top) | |
def NOT(self): | |
if len(self.stack) < 1: | |
return | |
top = self.stack.pop() | |
self.stack.append(int(not top)) | |
def GTR(self): | |
if len(self.stack) < 2: | |
return | |
top = self.stack.pop() | |
next = self.stack.pop() | |
self.stack.append(int(next > top)) | |
def PNTR(self): | |
if len(self.stack) < 1: | |
return | |
top = self.stack.pop() | |
self.dp = (self.dp + top) % 4 | |
def SWCH(self): | |
if len(self.stack) < 1: | |
return | |
top = self.stack.pop() | |
self.cc *= (-1) ** (top % 2) | |
def DUP(self): | |
if len(self.stack) < 1: | |
return | |
self.stack.append(self.stack[-1]) | |
def ROLL(self): | |
if len(self.stack) < 2: | |
return | |
num = self.stack.pop() | |
depth = self.stack.pop() | |
num %= depth | |
if depth <= 0 or num == 0: | |
return | |
x = -abs(num) + depth * (num < 0) | |
self.stack[-depth:] = self.stack[x:] + self.stack[-depth:x] | |
def N_IN(self): | |
n = int(raw_input("Enter an integer: ")) | |
self.stack.append(n) | |
def C_IN(self): | |
c = ord(raw_input("Enter a character: ")) | |
self.stack.append(c) | |
def NOUT(self): | |
if len(self.stack) < 1: | |
return | |
top = self.stack.pop() | |
sys.stdout.write(str(top)) | |
def COUT(self): | |
if len(self.stack) < 1: | |
return | |
top = self.stack.pop() | |
sys.stdout.write(chr(top)) | |
class Interpreter(object): | |
def __init__(self, filename, pvm, debug=False): | |
self.x, self.y = 0, 0 | |
self.pvm = pvm | |
self.debug = debug | |
self.step_number = 1 | |
self.block = (0,0) | |
self.filename = filename | |
self._image = Image.open(self.filename).convert("RGB") | |
self.cols, self.rows = self._image.size | |
self.matrix = [[0 for x in range(self.cols)] \ | |
for y in range(self.rows)] | |
for j in range(self.rows): | |
for i in range(self.cols): | |
r,g,b = self._image.getpixel((i,j)) | |
self.matrix[j][i] = "0x%02x%02x%02x" % (r,g,b) | |
def _is_valid(self,x,y): | |
return 0 <= x < self.cols and 0 <= y < self.rows and \ | |
self.matrix[y][x] != HEX_BLACK | |
def neighbors(self,x,y): | |
for (dx,dy) in ((0,1),(0,-1),(1,0),(-1,0)): | |
if self._is_valid(x+dx,y+dy) and \ | |
(x+dx,y+dy) not in self.block and \ | |
self.matrix[y][x] == self.matrix[y+dy][x+dx]: | |
self.block.append((x+dx,y+dy)) | |
self.neighbors(x+dx,y+dy) | |
def dmesg(self, mesg): | |
if self.debug: | |
print(mesg, file=sys.stderr) | |
def get_edge(self): | |
k_1 = int(not(self.pvm.dp % 2)) | |
r_1 = int(not(int(self.pvm.dp % 2) - int(self.pvm.cc < 0))) | |
k_2 = int(self.pvm.dp % 2) | |
r_2 = int(self.pvm.dp < 2) | |
self.block.sort(key=itemgetter(k_1), reverse=r_1) | |
self.block.sort(key=itemgetter(k_2), reverse=r_2) | |
return self.block[0] | |
def get_next_valid(self, x, y): | |
if self.pvm.dp == 0: | |
x += 1 | |
elif self.pvm.dp == 1: | |
y += 1 | |
elif self.pvm.dp == 2: | |
x -= 1 | |
elif self.pvm.dp == 3: | |
y -= 1 | |
else: | |
raise ValueError("Invalid DP value") | |
sys.exit(1) | |
return x,y | |
def run(self): | |
for step in self: #zip(self, range(10)): | |
pass | |
def step(self): | |
while True: | |
self.dmesg("\n-- STEP: %s" % self.step_number) | |
self.block = [(self.x, self.y)] | |
self.neighbors(self.x, self.y) # modifies self.block | |
self.pvm.block_value = len(self.block) | |
i = 1 | |
seen_white = 0 | |
ex, ey = self.get_edge() | |
while i <= 8: | |
nx, ny = self.get_next_valid(ex, ey) | |
if not self._is_valid(nx, ny): | |
i += 1 | |
if i % 2: | |
self.pvm.dp = (self.pvm.dp + 1) % 4 | |
else: | |
self.pvm.cc *= -1 | |
self.dmesg("Trying again at %s, %s. DP: %s CC: %s" % \ | |
(nx, ny, self.pvm.dp, self.pvm.cc)) | |
if self.matrix[ey][ex] != HEX_WHITE: | |
self.block = [(ex, ey)] | |
self.neighbors(ex, ey) # modifies self.block | |
ex, ey = self.get_edge() | |
elif self.matrix[ny][nx] == HEX_WHITE: | |
if not seen_white: | |
seen_white = 1 | |
i = 0 | |
self.dmesg("Entering white; sliding thru") | |
ex, ey = nx, ny | |
else: # next color is a color | |
self.dmesg("%s @ (%s,%s) -> %s @ (%s,%s) DP:%s CC:%s" % \ | |
(hex2tuple[self.matrix[self.y][self.x]]['color'], \ | |
self.x, self.y, \ | |
hex2tuple[self.matrix[ny][nx]]['color'], \ | |
nx, ny,\ | |
self.pvm.dp, self.pvm.cc)) | |
if not seen_white: | |
dH = hex2tuple[self.matrix[ny][nx]]['hue'] - \ | |
hex2tuple[self.matrix[self.y][self.x]]['hue'] | |
dD = hex2tuple[self.matrix[ny][nx]]['dark'] - \ | |
hex2tuple[self.matrix[self.y][self.x]]['dark'] | |
op = getattr(self.pvm, do_arr[dH][dD]) | |
op() | |
#exec "self.pvm.%s" % do_arr[dH][dD] | |
self.dmesg("OPER: %s" % (do_arr[dH][dD])) | |
self.dmesg("STACK: %s" % self.pvm.stack) | |
self.x, self.y = nx, ny | |
self.step_number += 1 | |
yield None | |
break | |
else: | |
self.dmesg("Execution trapped, program terminates") | |
return | |
__iter__ = step | |
if __name__ == "__main__": | |
debug = False | |
if "--debug" in sys.argv: | |
debug = True | |
sys.argv.remove("--debug") | |
i = Interpreter(sys.argv[1], PVM(), debug) | |
i.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment