Interpreter
This commit is contained in:
commit
1d0858c545
57
GUI/TKinter/canvasManager.py
Normal file
57
GUI/TKinter/canvasManager.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
|
||||||
|
|
||||||
|
class canvasManager():
|
||||||
|
def __init__(self, canvas, image, programState, scaleSize):
|
||||||
|
self.canvas = canvas
|
||||||
|
self.image = image
|
||||||
|
self.programState = programState
|
||||||
|
self.scaleSize = scaleSize
|
||||||
|
|
||||||
|
def updateImage(self, newImage):
|
||||||
|
self.image = newImage
|
||||||
|
|
||||||
|
def updateScaleSize(self, scaleSize):
|
||||||
|
self.scaleSize = scaleSize
|
||||||
|
|
||||||
|
def updateProgramState(self, newProgramState):
|
||||||
|
self.programState = newProgramState
|
||||||
|
|
||||||
|
def pixelToHexString(self, pixel) -> str:
|
||||||
|
return '#%02x%02x%02x' %(pixel[0], pixel[1], pixel[2])
|
||||||
|
|
||||||
|
def updateCanvas(self):
|
||||||
|
if self.image is None or self.canvas is None or self.programState is None or self.scaleSize is None:
|
||||||
|
return False
|
||||||
|
self.drawImage()
|
||||||
|
self.highlightCodel()
|
||||||
|
# Draw breakpoint
|
||||||
|
return True
|
||||||
|
|
||||||
|
def drawImage(self):
|
||||||
|
self.clearCanvas()
|
||||||
|
for raw_y, row in enumerate(self.image):
|
||||||
|
for raw_x, pixel in enumerate(row):
|
||||||
|
x = raw_x * self.scaleSize
|
||||||
|
y = raw_y * self.scaleSize
|
||||||
|
color = self.pixelToHexString(pixel)
|
||||||
|
self.canvas.create_rectangle(x,y, x+self.scaleSize, y+self.scaleSize, fill=color, outline=color)
|
||||||
|
|
||||||
|
|
||||||
|
def clearCanvas(self):
|
||||||
|
width = self.canvas.winfo_width()
|
||||||
|
height = self.canvas.winfo_height()
|
||||||
|
self.canvas.create_rectangle(0,0, width, height, fill="#FFFFFF")
|
||||||
|
|
||||||
|
|
||||||
|
def highlightCodel(self):
|
||||||
|
codel = imageWrapper.getCodel(self.image, self.programState.position)
|
||||||
|
pixel = imageWrapper.getPixel(self.image, self.programState.position)
|
||||||
|
color = self.pixelToHexString(pixel)
|
||||||
|
self.colorCodel(codel, color, "#000000")
|
||||||
|
|
||||||
|
def colorCodel(self, codel, fill, outline):
|
||||||
|
for position in codel:
|
||||||
|
x = position[0] * self.scaleSize
|
||||||
|
y = position[1] * self.scaleSize
|
||||||
|
self.canvas.create_rectangle(x,y, x+self.scaleSize - 1, y+self.scaleSize - 1, fill=fill, outline=outline)
|
79
GUI/TKinter/infoManager.py
Normal file
79
GUI/TKinter/infoManager.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.colors as colors
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
import interpreter.movement as movement
|
||||||
|
|
||||||
|
class infoManager():
|
||||||
|
def __init__(self, builder, generalInfoFrame, programStateInfoFrame):
|
||||||
|
self.builder = builder
|
||||||
|
self.generalInfo = generalInfoFrame
|
||||||
|
self.programStateInfoFrame = programStateInfoFrame
|
||||||
|
|
||||||
|
def updateInfo(self, image, graph, programState):
|
||||||
|
self.updateGeneralinfo(image, graph, programState)
|
||||||
|
self.updateProgramStateInfo(programState)
|
||||||
|
|
||||||
|
def updateGeneralinfo(self, image, graph, programState):
|
||||||
|
self.updateCodelInfo(image, programState.position)
|
||||||
|
self.updateEdgesInfo(image, graph, programState)
|
||||||
|
|
||||||
|
def updateProgramStateInfo(self, programState):
|
||||||
|
self.updateStackInfo(programState.dataStack)
|
||||||
|
self.updatePointersInfo(programState.position, programState.pointers)
|
||||||
|
|
||||||
|
def updateCodelInfo(self, image, newPosition):
|
||||||
|
infoMessage = self.builder.get_object('positionInfoMessage', self.generalInfo)
|
||||||
|
if colors.isBlack(imageWrapper.getPixel(image, newPosition)):
|
||||||
|
infoMessage.configure(text="Black pixels are no codel, and have no edges")
|
||||||
|
return None
|
||||||
|
|
||||||
|
baseString = "Selected codel contains:\n"
|
||||||
|
codel = imageWrapper.getCodel(image, newPosition)
|
||||||
|
for position in codel:
|
||||||
|
baseString += "{}\n".format(position)
|
||||||
|
|
||||||
|
infoMessage.configure(text=baseString.strip('\n'))
|
||||||
|
|
||||||
|
|
||||||
|
def updateEdgesInfo(self, image, graph, programState):
|
||||||
|
edgesInfo = self.builder.get_object('codelEdgesMessage', self.generalInfo)
|
||||||
|
|
||||||
|
if colors.isBlack(imageWrapper.getPixel(image, programState.position)):
|
||||||
|
edgesInfo.configure(text = "Black pixels are no codel, and have no edges")
|
||||||
|
return None
|
||||||
|
|
||||||
|
codel = imageWrapper.getCodel(image, programState.position)
|
||||||
|
baseString = "Next step will be:\n"
|
||||||
|
edge = graph[hash(frozenset(codel))][hash(programState.pointers)]
|
||||||
|
baseString += self.getEdgeDescription(edge, programState.pointers)
|
||||||
|
|
||||||
|
baseString += "\nCodel edges are as follows:\n"
|
||||||
|
#Generate pointers
|
||||||
|
edgePointers = list(map(lambda i: (i%4, int(i/4)), iter(range(8))))
|
||||||
|
for edgePointer in edgePointers:
|
||||||
|
edge = graph[hash(frozenset(codel))][hash(edgePointer)]
|
||||||
|
baseString += self.getEdgeDescription(edge, edgePointer)
|
||||||
|
edgesInfo.configure(text = baseString)
|
||||||
|
|
||||||
|
def getEdgeDescription(self, edge, pointer):
|
||||||
|
if isinstance(edge[0], lexerTokens.toColorToken) and edge[0].type == "push":
|
||||||
|
return "{}/{},{} -> {}({})\n".format(edge[1], movement.getDP(pointer[0]), movement.getCC(pointer[1]), edge[0].type, edge[0].codelSize)
|
||||||
|
else:
|
||||||
|
return "{}/{},{} -> {}\n".format(edge[1], movement.getDP(pointer[0]), movement.getCC(pointer[1]), edge[0].type)
|
||||||
|
|
||||||
|
def updateStackInfo(self, stack):
|
||||||
|
baseString = ""
|
||||||
|
for item in reversed(stack):
|
||||||
|
baseString += "{}\n".format(item)
|
||||||
|
baseString.strip("\n")
|
||||||
|
|
||||||
|
stackInfoMessage = self.builder.get_object("stackContents", self.programStateInfoFrame)
|
||||||
|
stackInfoMessage.configure(text=baseString)
|
||||||
|
|
||||||
|
def updatePointersInfo(self, position, pointers):
|
||||||
|
print("Update pointers: {} -> Arrow: {}".format(pointers, movement.getArrow(pointers)))
|
||||||
|
baseString = "Pos: ({},{})\n".format(position[0], position[1])
|
||||||
|
baseString += u"DP: {} ({},{})".format(movement.getArrow(pointers), movement.getDP(pointers[0]), movement.getCC(pointers[1]))
|
||||||
|
|
||||||
|
pointersInfoMessage = self.builder.get_object("pointerMessage", self.programStateInfoFrame)
|
||||||
|
pointersInfoMessage.configure(text=baseString)
|
156
GUI/TKinter/main.py
Normal file
156
GUI/TKinter/main.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
# helloworld.py
|
||||||
|
from time import sleep
|
||||||
|
import threading
|
||||||
|
import tkinter as tk
|
||||||
|
import pygubu
|
||||||
|
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.lexer as lexer
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
import interpreter.colors as colors
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.programState as programState
|
||||||
|
import interpreter.main as main
|
||||||
|
import threading
|
||||||
|
|
||||||
|
import infoManager
|
||||||
|
import canvasManager
|
||||||
|
|
||||||
|
|
||||||
|
class GUI:
|
||||||
|
def __init__(self):
|
||||||
|
# In pixelWidth/height per pixel. scaleSize = 25 means that every pixel will show as a 25x25 square
|
||||||
|
self.scaleSize = 25
|
||||||
|
# In percentage
|
||||||
|
self.executionSpeed = 15
|
||||||
|
|
||||||
|
# In seconds
|
||||||
|
self.maxWait = 5
|
||||||
|
|
||||||
|
self.image = None
|
||||||
|
self.graph = None
|
||||||
|
self.programState = None
|
||||||
|
self.selectedPosition = None
|
||||||
|
|
||||||
|
self.optionBar = None
|
||||||
|
self.actionBar = None
|
||||||
|
self.content = None
|
||||||
|
self.canvas = None
|
||||||
|
|
||||||
|
#1: Create a builder
|
||||||
|
self.builder = builder = pygubu.Builder()
|
||||||
|
|
||||||
|
#2: Load an ui file
|
||||||
|
builder.add_from_file('../assets/tkinterLayout.ui')
|
||||||
|
|
||||||
|
#3: Create the mainwindow
|
||||||
|
self.mainwindow = builder.get_object('rootWindow')
|
||||||
|
|
||||||
|
self.initializeFrames()
|
||||||
|
self.initializeCallbacks()
|
||||||
|
self.infoManager = infoManager.infoManager(self.builder, self.generalInfoFrame, self.programStateInfoFrame)
|
||||||
|
self.canvasManager = canvasManager.canvasManager(self.canvas, self.image, self.programState, self.scaleSize)
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.mainwindow.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
def initializeCallbacks(self):
|
||||||
|
self.builder.connect_callbacks({
|
||||||
|
'loadFile': self.loadFile,
|
||||||
|
'setScale': self.setScale,
|
||||||
|
'takeStep': self.takeStep,
|
||||||
|
'setExecutionSpeed': self.setExecutionSpeed,
|
||||||
|
'setBreakpoint': self.setBreakpoint,
|
||||||
|
'runProgram': self.runProgram
|
||||||
|
})
|
||||||
|
|
||||||
|
self.canvas.bind("<Button-1>", self.canvasPressed)
|
||||||
|
|
||||||
|
def initializeFrames(self):
|
||||||
|
self.optionBar = self.builder.get_object('optionBar', self.mainwindow)
|
||||||
|
self.content = self.builder.get_object('content', self.mainwindow)
|
||||||
|
self.actionBar = self.builder.get_object('actionBar', self.mainwindow)
|
||||||
|
self.generalInfoFrame = self.builder.get_object("generalInfoFrame", self.content)
|
||||||
|
self.programStateInfoFrame = self.builder.get_object("programStateInfoFrame", self.content)
|
||||||
|
canvasFrame = self.builder.get_object('canvasFrame', self.content)
|
||||||
|
self.canvas = self.builder.get_object('canvas', canvasFrame)
|
||||||
|
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.infoManager.updateInfo(self.image, self.graph, self.programState)
|
||||||
|
self.canvasManager.updateScaleSize(self.scaleSize)
|
||||||
|
self.canvasManager.updateImage(self.image)
|
||||||
|
self.canvasManager.updateProgramState(self.programState)
|
||||||
|
self.canvasManager.updateCanvas()
|
||||||
|
|
||||||
|
|
||||||
|
def takeStep(self):
|
||||||
|
if self.image is None or self.programState is None or self.graph is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
newProgramState = main.takeStep(self.image, self.programState)
|
||||||
|
if isinstance(newProgramState, bool):
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.programState = newProgramState
|
||||||
|
self.selectedPosition = self.programState.position
|
||||||
|
self.update()
|
||||||
|
print("Take step!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def setBreakpoint(self):
|
||||||
|
print("BREAKPOINT")
|
||||||
|
|
||||||
|
|
||||||
|
def setExecutionSpeed(self, pos):
|
||||||
|
if 0 < float(pos) < 100:
|
||||||
|
self.executionSpeed = float(pos)
|
||||||
|
|
||||||
|
def getWaitTime(self):
|
||||||
|
return self.executionSpeed/100*self.maxWait
|
||||||
|
|
||||||
|
def runProgram(self):
|
||||||
|
if self.graph is None or self.image is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
step = self.takeStep()
|
||||||
|
if step:
|
||||||
|
timer = threading.Timer(self.getWaitTime(), self.runProgram)
|
||||||
|
timer.start()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def setScale(self):
|
||||||
|
scaleValue = int(self.builder.get_object('scaleEntry', self.optionBar).get())
|
||||||
|
if 0 < scaleValue < 100:
|
||||||
|
self.scaleSize = int(scaleValue)
|
||||||
|
self.update()
|
||||||
|
print("SCALE")
|
||||||
|
|
||||||
|
|
||||||
|
def loadFile(self):
|
||||||
|
fileName = self.builder.get_object('fileNameEntry', self.optionBar).get()
|
||||||
|
self.image = imageWrapper.getImage(fileName)
|
||||||
|
self.graph = lexer.graphImage(self.image)
|
||||||
|
self.programState = programState.programState(self.graph, (0,0), (0,0))
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
print("LOAD FILE!")
|
||||||
|
|
||||||
|
|
||||||
|
def canvasPressed(self, event):
|
||||||
|
unscaled_x = int(event.x / self.scaleSize)
|
||||||
|
unscaled_y = int(event.y / self.scaleSize)
|
||||||
|
|
||||||
|
self.selectedPosition = (unscaled_x, unscaled_y)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = GUI()
|
||||||
|
app.run()
|
0
GUI/__init__.py
Normal file
0
GUI/__init__.py
Normal file
337
GUI/assets/tkinterLayout - kopie.ui
Normal file
337
GUI/assets/tkinterLayout - kopie.ui
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<interface>
|
||||||
|
<object id="rootWindow" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="optionBar" class="ttk.Frame">
|
||||||
|
<property name="borderwidth">2</property>
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="weight">0</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="loadFileButton" class="ttk.Button">
|
||||||
|
<property name="command">loadFile</property>
|
||||||
|
<property name="text" translatable="yes">Open File</property>
|
||||||
|
<property name="width">7.5</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="ipadx">5</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="padx">10</property>
|
||||||
|
<property name="pady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="fileNameEntry" class="ttk.Entry">
|
||||||
|
<property name="exportselection">false</property>
|
||||||
|
<property name="text" translatable="yes">../../Add.png</property>
|
||||||
|
<property name="width">44</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">w</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="setScale" class="ttk.Button">
|
||||||
|
<property name="command">setScale</property>
|
||||||
|
<property name="text" translatable="yes">Set scale</property>
|
||||||
|
<property name="textvariable">int:scaleSize</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="ipadx">5</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="padx">10</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="scaleEntry" class="ttk.Entry">
|
||||||
|
<property name="text" translatable="yes">25</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">3</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="actionBar" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="padx">7</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="pad">5</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
<columns>
|
||||||
|
<column id="0">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</column>
|
||||||
|
<column id="1">
|
||||||
|
<property name="pad">10</property>
|
||||||
|
</column>
|
||||||
|
<column id="2">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</column>
|
||||||
|
</columns>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="runProgram" class="ttk.Button">
|
||||||
|
<property name="command">runProgram</property>
|
||||||
|
<property name="text" translatable="yes">Run program</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="executionSpeed" class="ttk.Scale">
|
||||||
|
<property name="command">setExecutionSpeed</property>
|
||||||
|
<property name="from_">0</property>
|
||||||
|
<property name="orient">horizontal</property>
|
||||||
|
<property name="to">100</property>
|
||||||
|
<property name="value">15</property>
|
||||||
|
<property name="variable">int:pos</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="takeStep" class="ttk.Button">
|
||||||
|
<property name="command">takeStep</property>
|
||||||
|
<property name="text" translatable="yes">takeStep</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="padx">15</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">e</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="content" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="1">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="generalInfoFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">n</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="pad">5</property>
|
||||||
|
</row>
|
||||||
|
<row id="1">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="2">
|
||||||
|
<property name="pad">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="3">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="codelInfoLabel" class="ttk.Label">
|
||||||
|
<property name="text" translatable="yes">Codel info:</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="positionInfoMessage" class="tk.Message">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="text" translatable="yes">Selected codel contains the following positions:
|
||||||
|
- (0,0)
|
||||||
|
- (0,1)</property>
|
||||||
|
<property name="width">150</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="padx">5</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="codelEdgesMessage" class="tk.Message">
|
||||||
|
<property name="background">#FFFFFF</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="text" translatable="yes">Codel edges are as follows:
|
||||||
|
|
||||||
|
(0,1) -> (1,0) push 0</property>
|
||||||
|
<property name="width">150</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="setBreakPoint" class="ttk.Button">
|
||||||
|
<property name="command">setBreakpoint</property>
|
||||||
|
<property name="text" translatable="yes">Set breakpoint</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">3</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="stackInfoFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">n</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="stackInfo" class="ttk.Label">
|
||||||
|
<property name="anchor">center</property>
|
||||||
|
<property name="text" translatable="yes">Stack</property>
|
||||||
|
<property name="width">15</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="Message_4" class="tk.Message">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="text" translatable="yes">2
|
||||||
|
15
|
||||||
|
4
|
||||||
|
0</property>
|
||||||
|
<property name="width">150</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="canvasFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="canvas" class="tk.Canvas">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="height">400</property>
|
||||||
|
<property name="highlightbackground">#8a8a8a</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="width">700</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="Scrollbar_1" class="ttk.Scrollbar">
|
||||||
|
<property name="orient">vertical</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="Scrollbar_2" class="ttk.Scrollbar">
|
||||||
|
<property name="orient">horizontal</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
371
GUI/assets/tkinterLayout.ui
Normal file
371
GUI/assets/tkinterLayout.ui
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<interface>
|
||||||
|
<object id="rootWindow" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="optionBar" class="ttk.Frame">
|
||||||
|
<property name="borderwidth">2</property>
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="weight">0</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="loadFileButton" class="ttk.Button">
|
||||||
|
<property name="command">loadFile</property>
|
||||||
|
<property name="text" translatable="yes">Open File</property>
|
||||||
|
<property name="width">7.5</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="ipadx">5</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="padx">10</property>
|
||||||
|
<property name="pady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="fileNameEntry" class="ttk.Entry">
|
||||||
|
<property name="exportselection">false</property>
|
||||||
|
<property name="text" translatable="yes">../../Add.png</property>
|
||||||
|
<property name="width">44</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">w</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="setScale" class="ttk.Button">
|
||||||
|
<property name="command">setScale</property>
|
||||||
|
<property name="text" translatable="yes">Set scale</property>
|
||||||
|
<property name="textvariable">int:scaleSize</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="ipadx">5</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="padx">10</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="scaleEntry" class="ttk.Entry">
|
||||||
|
<property name="text" translatable="yes">75</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">3</property>
|
||||||
|
<property name="ipady">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="actionBar" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="padx">7</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="pad">5</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
<columns>
|
||||||
|
<column id="0">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</column>
|
||||||
|
<column id="1">
|
||||||
|
<property name="pad">10</property>
|
||||||
|
</column>
|
||||||
|
<column id="2">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</column>
|
||||||
|
</columns>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="runProgram" class="ttk.Button">
|
||||||
|
<property name="command">runProgram</property>
|
||||||
|
<property name="text" translatable="yes">Run program</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="executionSpeed" class="ttk.Scale">
|
||||||
|
<property name="command">setExecutionSpeed</property>
|
||||||
|
<property name="from_">1</property>
|
||||||
|
<property name="orient">horizontal</property>
|
||||||
|
<property name="to">100</property>
|
||||||
|
<property name="value">15</property>
|
||||||
|
<property name="variable">int:pos</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="takeStep" class="ttk.Button">
|
||||||
|
<property name="command">takeStep</property>
|
||||||
|
<property name="text" translatable="yes">takeStep</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="padx">15</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">e</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="content" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="1">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="generalInfoFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">250</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="padx">5</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">n</property>
|
||||||
|
<rows>
|
||||||
|
<row id="0">
|
||||||
|
<property name="pad">5</property>
|
||||||
|
</row>
|
||||||
|
<row id="1">
|
||||||
|
<property name="minsize">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="2">
|
||||||
|
<property name="pad">0</property>
|
||||||
|
</row>
|
||||||
|
<row id="3">
|
||||||
|
<property name="pad">15</property>
|
||||||
|
</row>
|
||||||
|
</rows>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="codelInfoLabel" class="ttk.Label">
|
||||||
|
<property name="text" translatable="yes">Codel info:</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="positionInfoMessage" class="tk.Message">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="text" translatable="yes">Selected codel contains the following positions:
|
||||||
|
- (0,0)
|
||||||
|
- (0,1)</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="padx">5</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="codelEdgesMessage" class="tk.Message">
|
||||||
|
<property name="background">#FFFFFF</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="text" translatable="yes">Codel edges are as follows:
|
||||||
|
|
||||||
|
(0,1) -> (1,0) push 0</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="setBreakPoint" class="ttk.Button">
|
||||||
|
<property name="command">setBreakpoint</property>
|
||||||
|
<property name="text" translatable="yes">Set breakpoint</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">3</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="programStateInfoFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
<property name="sticky">n</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="stackInfo" class="ttk.Label">
|
||||||
|
<property name="anchor">center</property>
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="text" translatable="yes">Stack</property>
|
||||||
|
<property name="width">15</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="stackContents" class="tk.Message">
|
||||||
|
<property name="anchor">center</property>
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="highlightcolor">#a7a7a7</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="programStateLabel" class="ttk.Label">
|
||||||
|
<property name="text" translatable="yes">Program state:</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="columnspan">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="currentPointer" class="ttk.Label">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="text" translatable="yes">Current direction</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="pointerMessage" class="tk.Message">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">2</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="canvasFrame" class="ttk.Frame">
|
||||||
|
<property name="height">200</property>
|
||||||
|
<property name="width">200</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">2</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
<child>
|
||||||
|
<object id="canvas" class="tk.Canvas">
|
||||||
|
<property name="background">#ffffff</property>
|
||||||
|
<property name="height">400</property>
|
||||||
|
<property name="highlightbackground">#8a8a8a</property>
|
||||||
|
<property name="highlightthickness">1</property>
|
||||||
|
<property name="width">700</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="ipadx">5</property>
|
||||||
|
<property name="ipady">5</property>
|
||||||
|
<property name="padx">5</property>
|
||||||
|
<property name="pady">5</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="Scrollbar_1" class="ttk.Scrollbar">
|
||||||
|
<property name="orient">vertical</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">1</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="Scrollbar_2" class="ttk.Scrollbar">
|
||||||
|
<property name="orient">horizontal</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">0</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">1</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
68
GUI/kivy/Debugger.kv
Normal file
68
GUI/kivy/Debugger.kv
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<GeneralLayout>:
|
||||||
|
rows : 3
|
||||||
|
row_default_height: 25
|
||||||
|
canvas:
|
||||||
|
Color:
|
||||||
|
rgb: [1, 1, 1, 1]
|
||||||
|
Rectangle:
|
||||||
|
pos:self.pos
|
||||||
|
size:self.size
|
||||||
|
OptionBar
|
||||||
|
ToolBar
|
||||||
|
ContentLayout
|
||||||
|
|
||||||
|
|
||||||
|
<OptionBar>:
|
||||||
|
spacing:5
|
||||||
|
padding: (3,1)
|
||||||
|
BoxLayout:
|
||||||
|
size: root.width*0.70, root.height
|
||||||
|
size_hint: None, None
|
||||||
|
Button:
|
||||||
|
id: myFileButton
|
||||||
|
text: "Open file:"
|
||||||
|
on_press: root.setFile(filePath.text)
|
||||||
|
TextInput:
|
||||||
|
id: filePath
|
||||||
|
hint_text: "File path"
|
||||||
|
cursor_color: (0,1,0,1)
|
||||||
|
multiline: False
|
||||||
|
|
||||||
|
BoxLayout:
|
||||||
|
Button:
|
||||||
|
id: myOptionsButton
|
||||||
|
text: "Set pixel scale"
|
||||||
|
on_press: root.setScale(scaleSize.text)
|
||||||
|
TextInput:
|
||||||
|
id: scaleSize
|
||||||
|
input_type: "number"
|
||||||
|
hint_text: "10"
|
||||||
|
|
||||||
|
<ToolBar>:
|
||||||
|
Button:
|
||||||
|
id: myMiddleButton
|
||||||
|
text: "Next step"
|
||||||
|
|
||||||
|
|
||||||
|
<ContentLayout>:
|
||||||
|
rows: 1
|
||||||
|
cols: 3
|
||||||
|
size_hint_y : 100
|
||||||
|
Button:
|
||||||
|
size: root.width*0.15, root.height
|
||||||
|
size_hint: None, None
|
||||||
|
id: myLeftBottomButton
|
||||||
|
text: "Left Bottom"
|
||||||
|
|
||||||
|
ImageCanvas
|
||||||
|
|
||||||
|
|
||||||
|
Button:
|
||||||
|
size: root.width*0.15, root.height
|
||||||
|
size_hint: None, None
|
||||||
|
id: myRightBottmButton
|
||||||
|
text: "Right Bottom"
|
||||||
|
|
||||||
|
|
||||||
|
<ImageCanvas>:
|
||||||
|
id: imageCanvas
|
74
GUI/kivy/kivyWindow.py
Normal file
74
GUI/kivy/kivyWindow.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
from kivy.app import App
|
||||||
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.gridlayout import GridLayout
|
||||||
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
|
from kivy.graphics.vertex_instructions import Line
|
||||||
|
from kivy.graphics.context_instructions import Color
|
||||||
|
from kivy.properties import ObjectProperty
|
||||||
|
|
||||||
|
import interpreter.lexer as lexer
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
|
||||||
|
|
||||||
|
class GeneralLayout(GridLayout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ContentLayout(GridLayout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ImageCanvas(BoxLayout):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
image = None
|
||||||
|
|
||||||
|
|
||||||
|
def drawImage(self, image, scale):
|
||||||
|
app = App.get_running_app()
|
||||||
|
self.image = app.loadImage(image)
|
||||||
|
max_height = self.size
|
||||||
|
print(max_height)
|
||||||
|
with self.canvas:
|
||||||
|
for y_axis, row in enumerate(image):
|
||||||
|
for x_axis, pixel in enumerate(row):
|
||||||
|
x = x_axis*scale
|
||||||
|
y = y_axis*scale
|
||||||
|
|
||||||
|
# with self.:
|
||||||
|
# Color([x/255 for x in pixel])
|
||||||
|
# Line(points = [x_axis, x, y_axis, y])
|
||||||
|
|
||||||
|
|
||||||
|
class OptionBar(BoxLayout):
|
||||||
|
def setFile(self, value):
|
||||||
|
app = App.get_running_app()
|
||||||
|
app.loadImage(value)
|
||||||
|
self.ids["filePath"].hint_text = value
|
||||||
|
self.ids['filePath'].text = ""
|
||||||
|
|
||||||
|
def setScale(self, value):
|
||||||
|
app = App.get_running_app()
|
||||||
|
self.ids['scaleSize'].hint_text = value
|
||||||
|
self.ids['scaleSize'].text = ""
|
||||||
|
app.pixelScale = value
|
||||||
|
|
||||||
|
class ToolBar(BoxLayout):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DebuggerApp(App):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.pixelScale = 10
|
||||||
|
self.canvas = ObjectProperty()
|
||||||
|
|
||||||
|
|
||||||
|
def loadImage(self, filepath):
|
||||||
|
image = imageWrapper.getImage(filepath)
|
||||||
|
return image
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
return GeneralLayout()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
GUI = DebuggerApp()
|
||||||
|
GUI.run()
|
0
interpreter/__init__.py
Normal file
0
interpreter/__init__.py
Normal file
67
interpreter/colors.py
Normal file
67
interpreter/colors.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
class possiblePixels:
|
||||||
|
def __init__(self):
|
||||||
|
self.colors = [
|
||||||
|
[255, 192, 192], # Light red
|
||||||
|
[255, 0, 0], # Red
|
||||||
|
[192, 0, 0], # Dark red
|
||||||
|
[255, 255, 192], # Light yellow
|
||||||
|
[255, 255, 0], # Yellow
|
||||||
|
[192, 192, 0], # Dark yellow
|
||||||
|
[192, 255, 192], # Light green
|
||||||
|
[0, 255, 0], # Green
|
||||||
|
[0, 192, 0], # Dark green
|
||||||
|
[192, 255, 255], # Light cyan
|
||||||
|
[0, 255, 255], # Cyan
|
||||||
|
[0, 192, 192], # Dark cyan
|
||||||
|
[192, 192, 255], # Light blue
|
||||||
|
[0, 0, 255], # Blue
|
||||||
|
[0, 0, 192], # Dark blue
|
||||||
|
[255, 192, 255], # Light magenta
|
||||||
|
[255, 0, 255], # Magenta
|
||||||
|
[192, 0, 192] # Dark magenta
|
||||||
|
]
|
||||||
|
self.white = [255, 255, 255]
|
||||||
|
self.black = [0, 0, 0]
|
||||||
|
|
||||||
|
|
||||||
|
def getPixelChange(colorStart: np.ndarray, colorEnd: np.ndarray) -> Dict[str, int]:
|
||||||
|
pixelsColors = possiblePixels()
|
||||||
|
|
||||||
|
|
||||||
|
if isWhite(colorStart) or isWhite(colorEnd):
|
||||||
|
return {"hueChange": 0, "lightChange": 0}
|
||||||
|
|
||||||
|
# Converting np arrays to common lists
|
||||||
|
colorStart = list(colorStart)[:3]
|
||||||
|
colorEnd = list(colorEnd)[:3]
|
||||||
|
indexStart = pixelsColors.colors.index(colorStart)
|
||||||
|
indexEnd = pixelsColors.colors.index(colorEnd)
|
||||||
|
|
||||||
|
# Calculating hue and lightness changes
|
||||||
|
hueChange = (int(indexEnd / 3) - int(indexStart / 3)) % 6
|
||||||
|
lightChange = (indexEnd - indexStart) % 3
|
||||||
|
|
||||||
|
return {"hueChange": hueChange, "lightChange": lightChange}
|
||||||
|
|
||||||
|
|
||||||
|
def isWhite(testColor: np.ndarray) -> bool:
|
||||||
|
colors = possiblePixels()
|
||||||
|
testColor = list(testColor)[:3]
|
||||||
|
return testColor == colors.white
|
||||||
|
|
||||||
|
|
||||||
|
def isBlack(testColor: np.ndarray) -> bool:
|
||||||
|
colors = possiblePixels()
|
||||||
|
testColor = list(testColor)[:3]
|
||||||
|
return testColor == colors.black
|
||||||
|
|
||||||
|
|
||||||
|
def isColor(testColor: np.ndarray) -> bool:
|
||||||
|
colors = possiblePixels()
|
||||||
|
testColor = list(testColor)[:3]
|
||||||
|
return testColor in colors.colors
|
126
interpreter/imageWrapper.py
Normal file
126
interpreter/imageWrapper.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
from typing import Tuple, Union, Set, List
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.colors as colors
|
||||||
|
|
||||||
|
|
||||||
|
def boundsChecker(image: np.ndarray, position: Tuple[int, int]) -> bool:
|
||||||
|
# Position 0 = x-axis, while matrix[0] = y-axis. This is why we compare position[0] with matrix[1]
|
||||||
|
return 0 <= position[0] < image.shape[1] and \
|
||||||
|
0 <= position[1] < image.shape[0]
|
||||||
|
|
||||||
|
|
||||||
|
def getPixel(image: np.ndarray, position: Tuple[int, int]) -> Union[np.ndarray, bool]:
|
||||||
|
"""
|
||||||
|
This function the pixel at a specific location
|
||||||
|
:param image: np.ndarray of image
|
||||||
|
:param position: wanted position
|
||||||
|
:return: either a cell or False, if the cell is not inside the image
|
||||||
|
"""
|
||||||
|
if boundsChecker(image, position):
|
||||||
|
return image[position[1]][position[0]]
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def getImage(fileName: str) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Returns an np.ndarray of the image found at the given file location
|
||||||
|
:param fileName: Complete filename (including extension)
|
||||||
|
:return: np.ndarray of the image
|
||||||
|
"""
|
||||||
|
image = Image.open(fileName)
|
||||||
|
if fileName.split('.')[-1] == "gif":
|
||||||
|
image = image.convert("RGB")
|
||||||
|
return np.array(image)
|
||||||
|
|
||||||
|
|
||||||
|
def getCodel(image: np.ndarray, position: Tuple[int, int], foundPixels: Set[Tuple[int, int]] = None) -> Set[Tuple[int, int]]:
|
||||||
|
"""
|
||||||
|
This function finds all adjacent pixels with the same color as the pixel on the given position
|
||||||
|
|
||||||
|
If you pass a white pixel, this will return a set with only the white pixel in it.
|
||||||
|
|
||||||
|
:param image: The image with all pixel values
|
||||||
|
:param position: Starting position
|
||||||
|
:param foundPixels: currently found pixels
|
||||||
|
:return: A Set with all positions of same-colored pixels (Also known as a codel)
|
||||||
|
"""
|
||||||
|
if foundPixels is None:
|
||||||
|
foundPixels = set()
|
||||||
|
|
||||||
|
# If this position is already in the set, it has already been traversed
|
||||||
|
if position in foundPixels:
|
||||||
|
return foundPixels
|
||||||
|
|
||||||
|
if colors.isWhite(getPixel(image, position)):
|
||||||
|
foundPixels.add(position)
|
||||||
|
return foundPixels
|
||||||
|
|
||||||
|
x = position[0]
|
||||||
|
y = position[1]
|
||||||
|
|
||||||
|
foundPixels.add(position)
|
||||||
|
|
||||||
|
# right
|
||||||
|
if boundsChecker(image, (x + 1, y)) and np.all(image[y][x + 1] == image[y][x]):
|
||||||
|
newPosition = (position[0] + 1, position[1])
|
||||||
|
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
||||||
|
|
||||||
|
# below
|
||||||
|
if boundsChecker(image, (x, y - 1)) and np.all(image[y - 1][x] == image[y][x]):
|
||||||
|
newPosition = (position[0], position[1] - 1)
|
||||||
|
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
||||||
|
|
||||||
|
# left
|
||||||
|
if boundsChecker(image, (x - 1, y)) and np.all(image[y][x - 1] == image[y][x]):
|
||||||
|
newPosition = (position[0] - 1, position[1])
|
||||||
|
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
||||||
|
|
||||||
|
# above
|
||||||
|
if boundsChecker(image, (x, y + 1)) and np.all(image[y + 1][x] == image[y][x]):
|
||||||
|
newPosition = (position[0], position[1] + 1)
|
||||||
|
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
||||||
|
|
||||||
|
return foundPixels
|
||||||
|
|
||||||
|
|
||||||
|
def getWhiteLine(image: np.ndarray, startPosition: Tuple[int, int], directionPointer: int, foundPixels: List[Tuple[int, int]] = None) -> List[Tuple[int, int]]:
|
||||||
|
"""
|
||||||
|
Finds all adjacent white pixels in the same direction
|
||||||
|
:param image: base image
|
||||||
|
:param startPosition: Starting position from which the white line starts
|
||||||
|
:param directionPointer: Direction in which the line goes
|
||||||
|
:param foundPixels: already found pixels
|
||||||
|
:return: A list of white pixels found
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Can't give mutable values as default parameter
|
||||||
|
if foundPixels is None:
|
||||||
|
foundPixels = []
|
||||||
|
|
||||||
|
# If it is already found, skip
|
||||||
|
if startPosition in foundPixels:
|
||||||
|
return foundPixels
|
||||||
|
|
||||||
|
foundPixels.append(startPosition)
|
||||||
|
|
||||||
|
# Get the new position, and check if the colors match
|
||||||
|
newPos = movement.getNextPosition(startPosition, directionPointer)
|
||||||
|
if boundsChecker(image, newPos) and colors.isWhite(image[newPos[1]][newPos[0]]):
|
||||||
|
return getWhiteLine(image, newPos, directionPointer, foundPixels)
|
||||||
|
else:
|
||||||
|
return foundPixels
|
||||||
|
|
||||||
|
|
||||||
|
def getNewWhiteDirection(image: np.ndarray, startPosition: Tuple[int, int], directionPointer: int) -> int:
|
||||||
|
newPosition = movement.getNextPosition(startPosition, directionPointer)
|
||||||
|
|
||||||
|
if boundsChecker(image, newPosition) and (not colors.isBlack(getPixel(image, newPosition))):
|
||||||
|
return directionPointer
|
||||||
|
else:
|
||||||
|
return getNewWhiteDirection(image, startPosition, movement.flipDP(directionPointer))
|
||||||
|
|
138
interpreter/lexer.py
Normal file
138
interpreter/lexer.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
from typing import List, Tuple, Set, Dict, Union
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.colors as colors
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
import interpreter.movement as movement
|
||||||
|
|
||||||
|
|
||||||
|
def cyclePosition(image: np.ndarray, startPosition: Tuple[int, int]) -> Union[Tuple[int, int], bool]:
|
||||||
|
"""
|
||||||
|
:param image: numpy image array
|
||||||
|
:param startPosition: from where to go to Tuple (x,y)
|
||||||
|
:return: newPosition (x,y), or false if new position would fall out of bounds
|
||||||
|
"""
|
||||||
|
if not imageWrapper.boundsChecker(image, startPosition):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if startPosition[0] == image.shape[1] - 1:
|
||||||
|
if startPosition[1] < image.shape[0] - 1:
|
||||||
|
return (0, startPosition[1] + 1)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return (startPosition[0] + 1, startPosition[1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getCodelsEfficient(image: np.ndarray, positionList: List[Tuple[int, int]]) -> List[Set[Tuple[int, int]]]:
|
||||||
|
if len(positionList) == 0:
|
||||||
|
return []
|
||||||
|
copiedList = positionList.copy()
|
||||||
|
newPosition = copiedList.pop(0)
|
||||||
|
|
||||||
|
|
||||||
|
if colors.isBlack(imageWrapper.getPixel(image, newPosition)):
|
||||||
|
return getCodelsEfficient(image, copiedList)
|
||||||
|
|
||||||
|
newCodel = imageWrapper.getCodel(image, newPosition)
|
||||||
|
|
||||||
|
# print("Original positionList: {}".format(positionList))
|
||||||
|
# print("Codel found: {}".format(newCodel))
|
||||||
|
# Remove found positions from position list
|
||||||
|
copiedList = list(set(copiedList) - newCodel)
|
||||||
|
# print("New positionList: {}".format(copiedList))
|
||||||
|
codelList = getCodelsEfficient(image, copiedList)
|
||||||
|
|
||||||
|
codelList.append(newCodel)
|
||||||
|
return codelList
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def getAllCodels(image: np.ndarray, position: Tuple[int, int] = (0, 0),
|
||||||
|
foundCodels: List[Set[Tuple[int, int]]] = None) -> List[Set[Tuple[int, int]]]:
|
||||||
|
if foundCodels is None:
|
||||||
|
foundCodels = []
|
||||||
|
|
||||||
|
# Checks if the current position is already in a found codel, and also if the current pixel is white or black
|
||||||
|
if (True in map(lambda codelSet, lambdaPosition=position: lambdaPosition in codelSet, foundCodels)) or colors.isBlack(imageWrapper.getPixel(image, position)):
|
||||||
|
nextPosition = cyclePosition(image, position)
|
||||||
|
if type(nextPosition) == bool and not nextPosition:
|
||||||
|
return foundCodels
|
||||||
|
return getAllCodels(image, nextPosition, foundCodels)
|
||||||
|
|
||||||
|
newCodel = imageWrapper.getCodel(image, position)
|
||||||
|
foundCodels.append(newCodel)
|
||||||
|
|
||||||
|
nextPosition = cyclePosition(image, position)
|
||||||
|
if type(nextPosition) == bool and nextPosition is False:
|
||||||
|
return foundCodels
|
||||||
|
else:
|
||||||
|
return getAllCodels(image, nextPosition, foundCodels)
|
||||||
|
|
||||||
|
|
||||||
|
def edgesToCodeldict(image: np.ndarray, edges: List[Tuple[Tuple[int, int], Tuple[int, int]]]) -> Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]:
|
||||||
|
"""
|
||||||
|
Constructs a dictionary with each pointer possibility as key and (token, position) as value
|
||||||
|
:param image: Image required to find calculate tokens
|
||||||
|
:param edges: List[Tuple[position, pointers]]
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return dict(map(lambda x, lambdaImage=image: (hash(x[1]), (lexerTokens.edgeToToken(lambdaImage, x), x[0])), edges))
|
||||||
|
|
||||||
|
|
||||||
|
def isCodeldictTerminate(codelDict: Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]) -> bool:
|
||||||
|
return all(map(lambda x: isinstance(x[1][0], lexerTokens.toBlackToken), codelDict.items()))
|
||||||
|
|
||||||
|
|
||||||
|
def codelDictToTerminate(codelDict: Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]) -> Dict[int, Tuple[lexerTokens.terminateToken, Tuple[int, int]]]:
|
||||||
|
return dict(map(lambda x: (x[0], (lexerTokens.terminateToken(), x[1][1])), codelDict.items()))
|
||||||
|
|
||||||
|
|
||||||
|
def codelToCodelDict(image: np.ndarray, codel: Set[Tuple[int, int]], edgePointers: List[Tuple[int, int]]) -> Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]:
|
||||||
|
"""
|
||||||
|
:param image: image
|
||||||
|
:param codel: set of positions within the same color
|
||||||
|
:param edgePointers: list of pointers to find tokens for
|
||||||
|
:return: A dictionary with each pointer possibility as key and (token, position) as value
|
||||||
|
"""
|
||||||
|
# make codel immutable
|
||||||
|
copiedCodel = frozenset(codel)
|
||||||
|
# Find all edges along the codel and edgepointers
|
||||||
|
edges = list(map(lambda pointers, lambdaCodel=copiedCodel: (movement.findEdge(lambdaCodel, pointers), pointers), edgePointers))
|
||||||
|
codelDict = edgesToCodeldict(image, edges)
|
||||||
|
|
||||||
|
if isCodeldictTerminate(codelDict):
|
||||||
|
codelDict = codelDictToTerminate(codelDict)
|
||||||
|
|
||||||
|
return codelDict
|
||||||
|
|
||||||
|
|
||||||
|
def graphImage(image: np.ndarray, position: Tuple[int, int] = (0, 0)) -> Dict[int, Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]]:
|
||||||
|
"""
|
||||||
|
Returns a dict with hashes of each codel as keys, and a codelDict as value. That codelDict contains hashed pointers (Tuple[int, int]) as keys to tokens as values.
|
||||||
|
:param image:
|
||||||
|
:param position:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# allCodels = getAllCodels(image, position)
|
||||||
|
allPositions = []
|
||||||
|
whiteCodels = []
|
||||||
|
print(image)
|
||||||
|
for y, row in enumerate(image):
|
||||||
|
for x, pixel in enumerate(row):
|
||||||
|
if not colors.isBlack(pixel):
|
||||||
|
if colors.isWhite(pixel):
|
||||||
|
whiteCodels.append((x,y))
|
||||||
|
else:
|
||||||
|
allPositions.append((x,y))
|
||||||
|
print(len(allPositions))
|
||||||
|
|
||||||
|
|
||||||
|
allCodels = getCodelsEfficient(image, allPositions)
|
||||||
|
# Get an iterator of all possible pointers
|
||||||
|
edgePointers = list(map(lambda i: (i % 4, int(i / 4)), iter(range(8))))
|
||||||
|
return dict(map(lambda x: (hash(frozenset(x)), codelToCodelDict(image, x, edgePointers)), allCodels))
|
77
interpreter/lexerTokens.py
Normal file
77
interpreter/lexerTokens.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
from typing import Tuple, Union
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.colors as colors
|
||||||
|
|
||||||
|
|
||||||
|
class baseLexerToken():
|
||||||
|
def __init__(self, tokenType: str):
|
||||||
|
self.tokenType = tokenType
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Token tokenType = {}".format(self.tokenType)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
|
class toBlackToken(baseLexerToken):
|
||||||
|
def __init__(self, tokenType: str = "toBlack"):
|
||||||
|
super().__init__(tokenType)
|
||||||
|
|
||||||
|
|
||||||
|
class toWhiteToken(baseLexerToken):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("toWhite")
|
||||||
|
|
||||||
|
|
||||||
|
class terminateToken(baseLexerToken):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("exit")
|
||||||
|
|
||||||
|
|
||||||
|
class toColorToken(baseLexerToken):
|
||||||
|
def __init__(self, tokenType: str, codelSize: int):
|
||||||
|
super().__init__(tokenType)
|
||||||
|
self.codelSize = codelSize
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}, codelSize = {}".format(super().__str__(), self.codelSize)
|
||||||
|
|
||||||
|
|
||||||
|
def getToken(hueChange: int, lightChange: int) -> str:
|
||||||
|
tokens = [
|
||||||
|
["noop", "push", "pop"],
|
||||||
|
["add", "subtract", "multiply"],
|
||||||
|
["divide", "mod", "not"],
|
||||||
|
["greater", "pointer", "switch"],
|
||||||
|
["duplicate", "roll", "inN"],
|
||||||
|
["inC", "outN", "outC"],
|
||||||
|
]
|
||||||
|
return tokens[hueChange][lightChange]
|
||||||
|
|
||||||
|
|
||||||
|
def edgeToToken(image: np.ndarray, edge: Tuple[Tuple[int, int], Tuple[int, int]]) -> Union[baseLexerToken, bool]:
|
||||||
|
"""
|
||||||
|
:param image:
|
||||||
|
:param edge: (position, direction)
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
if not imageWrapper.boundsChecker(image, edge[0]):
|
||||||
|
return False
|
||||||
|
|
||||||
|
nextPosition = movement.getNextPosition(edge[0], edge[1][0])
|
||||||
|
if not imageWrapper.boundsChecker(image, nextPosition):
|
||||||
|
return toBlackToken("edge")
|
||||||
|
|
||||||
|
elif colors.isBlack(imageWrapper.getPixel(image, nextPosition)):
|
||||||
|
return toBlackToken("toBlack")
|
||||||
|
|
||||||
|
if colors.isWhite(imageWrapper.getPixel(image, nextPosition)):
|
||||||
|
return toWhiteToken()
|
||||||
|
|
||||||
|
colorChange = colors.getPixelChange(imageWrapper.getPixel(image, edge[0]), imageWrapper.getPixel(image, nextPosition))
|
||||||
|
tokenType = getToken(colorChange['hueChange'], colorChange['lightChange'])
|
||||||
|
return toColorToken(tokenType, len(imageWrapper.getCodel(image, edge[0])))
|
96
interpreter/main.py
Normal file
96
interpreter/main.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import copy
|
||||||
|
from typing import Union
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.lexer as lexer
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.programState as programState
|
||||||
|
import interpreter.runner as runner
|
||||||
|
|
||||||
|
|
||||||
|
def interpret(image: np.ndarray):
|
||||||
|
graph = lexer.graphImage(im)
|
||||||
|
position = (0, 0)
|
||||||
|
pointers = (0, 0)
|
||||||
|
PS = programState.programState(graph, position, pointers)
|
||||||
|
|
||||||
|
runProgram(image, PS)
|
||||||
|
|
||||||
|
|
||||||
|
def runProgram(image: np.ndarray, PS: programState) -> programState:
|
||||||
|
newState = PS
|
||||||
|
currentCodel = imageWrapper.getCodel(image, newState.position)
|
||||||
|
|
||||||
|
frozencodel = frozenset(currentCodel)
|
||||||
|
newToken = newState.graph[hash(frozencodel)][hash(newState.pointers)][0]
|
||||||
|
|
||||||
|
if isinstance(newToken, lexerTokens.terminateToken):
|
||||||
|
print("")
|
||||||
|
print("TERMINATE!")
|
||||||
|
return newState
|
||||||
|
|
||||||
|
newState = takeStep(image, newState)
|
||||||
|
|
||||||
|
return runProgram(image, newState)
|
||||||
|
|
||||||
|
|
||||||
|
def takeStep(image: np.ndarray, PS: programState.programState) -> Union[programState.programState, bool]:
|
||||||
|
newState = copy.deepcopy(PS)
|
||||||
|
currentCodel = imageWrapper.getCodel(image, newState.position)
|
||||||
|
|
||||||
|
frozencodel = frozenset(currentCodel)
|
||||||
|
newToken = newState.graph[hash(frozencodel)][hash(newState.pointers)][0]
|
||||||
|
edgePosition = newState.graph[hash(frozencodel)][hash(newState.pointers)][1]
|
||||||
|
result = runner.executeToken(newToken, newState.pointers, newState.dataStack)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
print("TERMINATE")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if isinstance(newToken, lexerTokens.toWhiteToken) or isinstance(newToken, lexerTokens.toColorToken):
|
||||||
|
newState.position = movement.getNextPosition(edgePosition, newState.pointers[0])
|
||||||
|
|
||||||
|
newState.pointers = result[0]
|
||||||
|
newState.dataStack = result[1]
|
||||||
|
|
||||||
|
return newState
|
||||||
|
|
||||||
|
|
||||||
|
class run:
|
||||||
|
def __init__(self, image: np.ndarray):
|
||||||
|
self.image = image
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
self.run_program(self.image, programState.programState(lexer.graphImage(self.image), (0,0), (0,0)) )
|
||||||
|
|
||||||
|
|
||||||
|
def run_program(self,image: np.ndarray, PS: programState) -> programState:
|
||||||
|
currentCodel = imageWrapper.getCodel(image, PS.position)
|
||||||
|
|
||||||
|
frozencodel = frozenset(currentCodel)
|
||||||
|
newToken = PS.graph[hash(frozencodel)][hash(PS.pointers)][0]
|
||||||
|
|
||||||
|
if isinstance(newToken, lexerTokens.terminateToken):
|
||||||
|
print("")
|
||||||
|
print("TERMINATE!")
|
||||||
|
return PS
|
||||||
|
return self.run_program(image, takeStep(image, PS))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
im = imageWrapper.getImage("../brainfuck_interpreter_black.png")
|
||||||
|
interpret(im)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
sys.setrecursionlimit(0x100000)
|
||||||
|
threading.stack_size(256000000) #set stack to 256mb
|
||||||
|
t = threading.Thread(target=run(im))
|
||||||
|
t.start()
|
||||||
|
t.join()
|
168
interpreter/movement.py
Normal file
168
interpreter/movement.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
from typing import Tuple, Set, Union
|
||||||
|
|
||||||
|
|
||||||
|
def getDP(directionPointer: int) -> str:
|
||||||
|
if directionPointer == 0:
|
||||||
|
return 'r'
|
||||||
|
elif directionPointer == 1:
|
||||||
|
return 'd'
|
||||||
|
elif directionPointer == 2:
|
||||||
|
return 'l'
|
||||||
|
else:
|
||||||
|
return 'u'
|
||||||
|
|
||||||
|
|
||||||
|
def getCC(codelChooser: int) -> str:
|
||||||
|
if codelChooser == 0:
|
||||||
|
return 'l'
|
||||||
|
else:
|
||||||
|
return 'r'
|
||||||
|
|
||||||
|
|
||||||
|
def getArrow(pointers: Tuple[int, int]) -> str:
|
||||||
|
if pointers[0] == 0:
|
||||||
|
if pointers[1] == 0:
|
||||||
|
return "\u2197"
|
||||||
|
elif pointers[1] == 1:
|
||||||
|
return "\u2198"
|
||||||
|
elif pointers[0] == 1:
|
||||||
|
if pointers[1] == 0:
|
||||||
|
return "\u2198"
|
||||||
|
elif pointers[1] == 1:
|
||||||
|
return "\u2199"
|
||||||
|
elif pointers[0] == 2:
|
||||||
|
if pointers[1] == 0:
|
||||||
|
return "\u2199"
|
||||||
|
elif pointers[1] == 1:
|
||||||
|
return "\u2196"
|
||||||
|
elif pointers[0] == 3:
|
||||||
|
if pointers[1] == 0:
|
||||||
|
return "\u2196"
|
||||||
|
elif pointers[1] == 1:
|
||||||
|
return "\u2197"
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def flipCC(codelChooser: int) -> int:
|
||||||
|
"""
|
||||||
|
Flips the codelChooser 0 -> 1, 1 -> 0
|
||||||
|
:param codelChooser: unflipped codelChooser
|
||||||
|
:return: flipped codelChooser
|
||||||
|
"""
|
||||||
|
return int(not codelChooser)
|
||||||
|
|
||||||
|
|
||||||
|
def flipDP(directionPointer: int) -> int:
|
||||||
|
"""
|
||||||
|
Cycles the directionpointer 0 -> 1, 1 -> 2, 2 -> 3, 3 -> 0
|
||||||
|
:param directionPointer: unflipped directionPointer
|
||||||
|
:return: new DirectionPointer
|
||||||
|
"""
|
||||||
|
if directionPointer != 3:
|
||||||
|
return directionPointer + 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def flip(pointers: Tuple[int, int]) -> Tuple[int, int]:
|
||||||
|
"""
|
||||||
|
Chooses what part of the general pointer to flip, by DP%2 == CC rule, providing the following flow:
|
||||||
|
(0,0) -> (0,1)
|
||||||
|
(0,1) -> (1,1)
|
||||||
|
(1,1) -> (1,0)
|
||||||
|
(1,0) -> (2,0)
|
||||||
|
(2,0) -> (2,1)
|
||||||
|
(2,1) -> (3,1)
|
||||||
|
(3,1) -> (3,0)
|
||||||
|
(3,0) -> (0,0)
|
||||||
|
:param pointers: Original state of the pointers
|
||||||
|
:return: Tuple of ints containing new pointers
|
||||||
|
"""
|
||||||
|
if pointers[0] % 2 == pointers[1]:
|
||||||
|
return (pointers[0], flipCC(pointers[1]))
|
||||||
|
else:
|
||||||
|
return (flipDP(pointers[0]), pointers[1])
|
||||||
|
|
||||||
|
|
||||||
|
# TODO FIX KEYERROR
|
||||||
|
def getNextPosition(startPosition: Tuple[int, int], directionPointer: int) -> Union[Tuple[int, int], KeyError]:
|
||||||
|
if directionPointer == 0:
|
||||||
|
return (startPosition[0] + 1, startPosition[1])
|
||||||
|
elif directionPointer == 1:
|
||||||
|
return (startPosition[0], startPosition[1] + 1)
|
||||||
|
elif directionPointer == 2:
|
||||||
|
return (startPosition[0] - 1, startPosition[1])
|
||||||
|
elif directionPointer == 3:
|
||||||
|
return (startPosition[0], startPosition[1] - 1)
|
||||||
|
else:
|
||||||
|
return KeyError("Given key {} is no valid Direction Pointer (0, 1, 2, or 3)".format(directionPointer))
|
||||||
|
|
||||||
|
|
||||||
|
def getPreviousPosition(startPosition: Tuple[int, int], directionPointer: int) -> Tuple[int, int]:
|
||||||
|
if directionPointer == 0:
|
||||||
|
return getNextPosition(startPosition, 2)
|
||||||
|
elif directionPointer == 1:
|
||||||
|
return getNextPosition(startPosition, 3)
|
||||||
|
elif directionPointer == 2:
|
||||||
|
return getNextPosition(startPosition, 0)
|
||||||
|
return getNextPosition(startPosition, 1)
|
||||||
|
# TODO: make the else return an error, and elif return 'd' position
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Error handling
|
||||||
|
def findEdge(codel: Set[Tuple[int, int]], pointers: Tuple[int, int]) -> Union[Tuple[int, int], bool]:
|
||||||
|
"""
|
||||||
|
Finds the edge of the codel according to the direction pointer and the codel chooser
|
||||||
|
:param codel: Set of adjacent positions with the same color
|
||||||
|
:param pointers: Tuple where pointers[0] = DP and pointers[1] = CC
|
||||||
|
:return: Position within the codel that is adjacent to the next pixel to go to
|
||||||
|
"""
|
||||||
|
dp = pointers[0]
|
||||||
|
cc = pointers[1]
|
||||||
|
|
||||||
|
if dp == 0:
|
||||||
|
edgePosition = max(codel, key=lambda lambdaPos: lambdaPos[0])
|
||||||
|
for pos in codel:
|
||||||
|
if pos[0] == edgePosition[0]:
|
||||||
|
# -> ^ Right and up
|
||||||
|
if cc == 0 and pos[1] < edgePosition[1]:
|
||||||
|
edgePosition = pos
|
||||||
|
# -> V Right and down
|
||||||
|
elif cc == 1 and pos[1] > edgePosition[1]:
|
||||||
|
edgePosition = pos
|
||||||
|
return edgePosition
|
||||||
|
elif dp == 1:
|
||||||
|
edgePosition = max(codel, key=lambda lambdaPos: lambdaPos[1])
|
||||||
|
for pos in codel:
|
||||||
|
if pos[1] == edgePosition[1]:
|
||||||
|
# V -> Down and right
|
||||||
|
if cc == 0 and pos[0] > edgePosition[0]:
|
||||||
|
edgePosition = pos
|
||||||
|
# V <- Down and left
|
||||||
|
elif cc == 1 and pos[0] < edgePosition[0]:
|
||||||
|
edgePosition = pos
|
||||||
|
return edgePosition
|
||||||
|
elif dp == 2:
|
||||||
|
edgePosition = min(codel, key=lambda lambdaPos: lambdaPos[0])
|
||||||
|
for pos in codel:
|
||||||
|
if pos[0] == edgePosition[0]:
|
||||||
|
# <- V Left and down
|
||||||
|
if cc == 0 and pos[1] > edgePosition[1]:
|
||||||
|
edgePosition = pos
|
||||||
|
# <- ^ left and up
|
||||||
|
elif cc == 1 and pos[1] < edgePosition[1]:
|
||||||
|
edgePosition = pos
|
||||||
|
return edgePosition
|
||||||
|
elif dp == 3:
|
||||||
|
edgePosition = min(codel, key=lambda lambdaPos: lambdaPos[1])
|
||||||
|
for pos in codel:
|
||||||
|
if pos[1] == edgePosition[1]:
|
||||||
|
# ^ <- Up and left
|
||||||
|
if cc == 0 and pos[0] < edgePosition[0]:
|
||||||
|
edgePosition = pos
|
||||||
|
# ^ -> Up and right
|
||||||
|
elif cc == 1 and pos[0] > edgePosition[0]:
|
||||||
|
edgePosition = pos
|
||||||
|
return edgePosition
|
||||||
|
else:
|
||||||
|
raise SyntaxError("DirectionPointer '{}' is unknown".format(dp))
|
24
interpreter/programState.py
Normal file
24
interpreter/programState.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from typing import Dict, List, Tuple
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
|
||||||
|
|
||||||
|
class programState():
|
||||||
|
def __init__(self, graph: Dict[int, Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]], position: Tuple[int, int], pointers: Tuple[int, int], dataStack: List[int] = None):
|
||||||
|
if dataStack is None:
|
||||||
|
dataStack = []
|
||||||
|
|
||||||
|
self.graph = graph
|
||||||
|
self.pointers = pointers
|
||||||
|
self.position = position
|
||||||
|
self.dataStack = dataStack
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{pos} / {pointers}. Stack: {stack}".format(pos=self.position, pointers=self.pointers, stack=self.dataStack)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memodict):
|
||||||
|
return programState(self.graph, deepcopy(self.position), deepcopy(self.pointers), deepcopy(self.dataStack))
|
277
interpreter/runner.py
Normal file
277
interpreter/runner.py
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
import interpreter.lexerTokens as lexerTokens
|
||||||
|
import interpreter.movement as movement
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Nettere afhandeling errors (Union[Tuple[List[int], Tuple[int, int]], bool])
|
||||||
|
# TODO Test cases maken per token
|
||||||
|
def executeToken(token: lexerTokens.baseLexerToken, pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
if isinstance(token, lexerTokens.toBlackToken):
|
||||||
|
newPointers = movement.flip(pointers)
|
||||||
|
return (newPointers, dataStack)
|
||||||
|
elif isinstance(token, lexerTokens.toWhiteToken):
|
||||||
|
return (pointers, dataStack)
|
||||||
|
elif isinstance(token, lexerTokens.toColorToken):
|
||||||
|
result = executeColorToken(token, pointers, dataStack)
|
||||||
|
return (result[0], result[1])
|
||||||
|
|
||||||
|
|
||||||
|
def executeColorToken(token: lexerTokens.toColorToken, pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
if token.tokenType == "noop":
|
||||||
|
return noopOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "push":
|
||||||
|
# Needs the codelsize to push
|
||||||
|
return pushOperator(token, pointers, dataStack)
|
||||||
|
elif token.tokenType == "pop":
|
||||||
|
return popOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "add":
|
||||||
|
return addOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "subtract":
|
||||||
|
return subtractOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "multiply":
|
||||||
|
return multiplyOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "divide":
|
||||||
|
return divideOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "mod":
|
||||||
|
return modOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "not":
|
||||||
|
return notOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "greater":
|
||||||
|
return greaterOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "pointer":
|
||||||
|
return pointerOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "switch":
|
||||||
|
return switchOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "duplicate":
|
||||||
|
return duplicateOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "roll":
|
||||||
|
return rollOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "inN":
|
||||||
|
return inNOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "inC":
|
||||||
|
return inCOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "outN":
|
||||||
|
return outNOperator(pointers, dataStack)
|
||||||
|
elif token.tokenType == "outC":
|
||||||
|
return outCOperator(pointers, dataStack)
|
||||||
|
else:
|
||||||
|
# TODO Elegantere manier van afhandelen
|
||||||
|
print("Type niet gevonden, noop uitgevoerd")
|
||||||
|
return noopOperator(pointers, dataStack)
|
||||||
|
|
||||||
|
|
||||||
|
def noopOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
"""
|
||||||
|
Does nothing
|
||||||
|
:param pointers: The tuple with the direction pointer and codel chooser
|
||||||
|
:param dataStack: input dataStack
|
||||||
|
:return: Tuple of a copy of the dataStack and the endpointers of the token
|
||||||
|
"""
|
||||||
|
return (pointers, list(dataStack))
|
||||||
|
|
||||||
|
|
||||||
|
def addOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
"""
|
||||||
|
Pops the two values from the stack and add them together, then pushes the result
|
||||||
|
:param pointers: The tuple with the direction pointer and codel chooser
|
||||||
|
:param dataStack: input datastack
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
newStack.append(newStack.pop() + newStack.pop())
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def subtractOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
first = newStack.pop()
|
||||||
|
second = newStack.pop()
|
||||||
|
newStack.append(second - first)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def multiplyOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
newStack.append(newStack.pop() * newStack.pop())
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def divideOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
"""
|
||||||
|
Provides integer division (//)
|
||||||
|
:param pointers: The tuple with the direction pointer and codel chooser
|
||||||
|
:param dataStack: A list of ints as stack. last entry is the top
|
||||||
|
:return: Tuple with the new data stack and new pointers
|
||||||
|
"""
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
first = newStack.pop()
|
||||||
|
second = newStack.pop()
|
||||||
|
if second == 0:
|
||||||
|
raise ZeroDivisionError("{} / {} ".format(first, second))
|
||||||
|
newStack.append(newStack.pop() // newStack.pop())
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def modOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
valA = newStack.pop()
|
||||||
|
valB = newStack.pop()
|
||||||
|
if valB == 0:
|
||||||
|
return (pointers, newStack)
|
||||||
|
newStack.append(valA % valB)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def greaterOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
"""
|
||||||
|
Compares the second value of the stack with the first value of the stack. If the stack is empty, this gets ignored
|
||||||
|
:param pointers: The tuple with the direction pointer and codel chooser
|
||||||
|
:param dataStack: The list of values as the stack, last entry is the top of the stack
|
||||||
|
:return: A tuple of pointers and new data stack
|
||||||
|
"""
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
newStack.append(int(newStack.pop() < newStack.pop()))
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def notOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
"""
|
||||||
|
Compares the second value of the stack with the first value of the stack
|
||||||
|
:param pointers: The tuple with the direction pointer and codel chooser
|
||||||
|
:param dataStack: The input list of ints as stcak. Last entry is the top of the stack
|
||||||
|
:return: A tuple of pointers and new data stack
|
||||||
|
"""
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
result = 1 if newStack.pop() == 0 else 0
|
||||||
|
newStack.append(result)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def pointerOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
dpTurnCount = newStack.pop() % 4
|
||||||
|
newDp = (pointers[0] + dpTurnCount) % 4
|
||||||
|
return ((newDp, pointers[1]), newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def switchOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
ccTurnCount = newStack.pop() % 2
|
||||||
|
newCC = (pointers[1] + ccTurnCount) % 2
|
||||||
|
return ((pointers[0], newCC), newStack)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO BETERE IO
|
||||||
|
def inNOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
newVal = int(input("Input number: "))
|
||||||
|
newStack.append(newVal)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def inCOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
newVal = input("Input character")
|
||||||
|
if len(newVal) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
appendedStack = pushCharacters(newStack, newVal)
|
||||||
|
return (pointers, appendedStack)
|
||||||
|
|
||||||
|
|
||||||
|
def pushCharacters(dataStack: List[int], characters: str) -> List[int]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(characters) < 1:
|
||||||
|
return newStack
|
||||||
|
else:
|
||||||
|
newStack.append(ord(characters[0]))
|
||||||
|
return pushCharacters(newStack, characters[1:])
|
||||||
|
|
||||||
|
|
||||||
|
def outNOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
print(newStack.pop(), end="")
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def outCOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
print(chr(newStack.pop()), end="")
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def pushOperator(token: lexerTokens.toColorToken, pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
newStack.append(token.codelSize)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def popOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
newStack.pop()
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def duplicateOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
val = newStack.pop()
|
||||||
|
newStack.append(val)
|
||||||
|
newStack.append(val)
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def rollOperator(pointers: Tuple[int, int], dataStack: List[int]) -> Tuple[Tuple[int, int], List[int]]:
|
||||||
|
newStack = list(dataStack)
|
||||||
|
if len(newStack) < 3:
|
||||||
|
return (pointers, newStack)
|
||||||
|
rolls = newStack.pop()
|
||||||
|
depth = newStack.pop()
|
||||||
|
insertIndex = len(newStack) - depth
|
||||||
|
|
||||||
|
if depth <= 0 or insertIndex < 0 or insertIndex >= len(newStack) or rolls == 0 or depth == rolls:
|
||||||
|
return (pointers, newStack)
|
||||||
|
|
||||||
|
# TODO could also do rolls % depth times, instead of rolls times
|
||||||
|
if rolls < 0:
|
||||||
|
for i in range(abs(rolls)):
|
||||||
|
newStack.append(newStack.pop(insertIndex))
|
||||||
|
else:
|
||||||
|
for i in range(rolls):
|
||||||
|
newStack.insert(insertIndex, newStack.pop())
|
||||||
|
|
||||||
|
return (pointers, newStack)
|
Loading…
x
Reference in New Issue
Block a user