It works
This commit is contained in:
parent
0576145b10
commit
afa67b21ac
BIN
GUI/assets/play_button.png
Normal file
BIN
GUI/assets/play_button.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
GUI/assets/play_button.xcf
Normal file
BIN
GUI/assets/play_button.xcf
Normal file
Binary file not shown.
@ -51,7 +51,7 @@ class canvasManager():
|
|||||||
self.colorCodel(codel, color, "#000000")
|
self.colorCodel(codel, color, "#000000")
|
||||||
|
|
||||||
def colorCodel(self, codel, fill, outline):
|
def colorCodel(self, codel, fill, outline):
|
||||||
for position in codel:
|
for position in codel.codel:
|
||||||
x = position[0] * self.scaleSize
|
x = position.coords[0] * self.scaleSize
|
||||||
y = position[1] * self.scaleSize
|
y = position.coords[1] * self.scaleSize
|
||||||
self.canvas.create_rectangle(x,y, x+self.scaleSize - 1, y+self.scaleSize - 1, fill=fill, outline=outline)
|
self.canvas.create_rectangle(x,y, x+self.scaleSize - 1, y+self.scaleSize - 1, fill=fill, outline=outline)
|
@ -1,7 +1,8 @@
|
|||||||
import interpreter.imageWrapper as imageWrapper
|
import interpreter.imageWrapper as imageWrapper
|
||||||
import interpreter.colors as colors
|
import interpreter.colors as colors
|
||||||
import interpreter.lexerTokens as lexerTokens
|
import interpreter.tokens as lexerTokens
|
||||||
import interpreter.movement as movement
|
import interpreter.movement as movement
|
||||||
|
from interpreter.dataStructures import direction
|
||||||
|
|
||||||
class infoManager():
|
class infoManager():
|
||||||
def __init__(self, builder, generalInfoFrame, programStateInfoFrame):
|
def __init__(self, builder, generalInfoFrame, programStateInfoFrame):
|
||||||
@ -19,7 +20,7 @@ class infoManager():
|
|||||||
|
|
||||||
def updateProgramStateInfo(self, programState):
|
def updateProgramStateInfo(self, programState):
|
||||||
self.updateStackInfo(programState.dataStack)
|
self.updateStackInfo(programState.dataStack)
|
||||||
self.updatePointersInfo(programState.position, programState.pointers)
|
self.updatePointersInfo(programState.position, programState.direction)
|
||||||
|
|
||||||
def updateCodelInfo(self, image, newPosition):
|
def updateCodelInfo(self, image, newPosition):
|
||||||
infoMessage = self.builder.get_object('positionInfoMessage', self.generalInfo)
|
infoMessage = self.builder.get_object('positionInfoMessage', self.generalInfo)
|
||||||
@ -29,13 +30,13 @@ class infoManager():
|
|||||||
|
|
||||||
baseString = "Selected codel contains:\n"
|
baseString = "Selected codel contains:\n"
|
||||||
codel = imageWrapper.getCodel(image, newPosition)
|
codel = imageWrapper.getCodel(image, newPosition)
|
||||||
for position in codel:
|
for position in codel.codel:
|
||||||
baseString += "{}\n".format(position)
|
baseString += "{}\n".format(position)
|
||||||
|
|
||||||
infoMessage.configure(text=baseString.strip('\n'))
|
infoMessage.configure(text=baseString.strip('\n'))
|
||||||
|
|
||||||
|
|
||||||
def updateEdgesInfo(self, image, graph, programState):
|
def updateEdgesInfo(self, image, inputGraph, programState):
|
||||||
edgesInfo = self.builder.get_object('codelEdgesMessage', self.generalInfo)
|
edgesInfo = self.builder.get_object('codelEdgesMessage', self.generalInfo)
|
||||||
|
|
||||||
if colors.isBlack(imageWrapper.getPixel(image, programState.position)):
|
if colors.isBlack(imageWrapper.getPixel(image, programState.position)):
|
||||||
@ -44,22 +45,25 @@ class infoManager():
|
|||||||
|
|
||||||
codel = imageWrapper.getCodel(image, programState.position)
|
codel = imageWrapper.getCodel(image, programState.position)
|
||||||
baseString = "Next step will be:\n"
|
baseString = "Next step will be:\n"
|
||||||
edge = graph[hash(frozenset(codel))][hash(programState.pointers)]
|
|
||||||
baseString += self.getEdgeDescription(edge, programState.pointers)
|
graphNode = inputGraph.graph[codel]
|
||||||
|
|
||||||
|
edge = graphNode.graphNode[programState.direction]
|
||||||
|
baseString += self.getEdgeDescription(edge, programState.direction)
|
||||||
|
|
||||||
baseString += "\nCodel edges are as follows:\n"
|
baseString += "\nCodel edges are as follows:\n"
|
||||||
#Generate pointers
|
#Generate pointers
|
||||||
edgePointers = list(map(lambda i: (i%4, int(i/4)), iter(range(8))))
|
edgePointers = list(map(lambda i: direction((i%4, int(i/4))), iter(range(8))))
|
||||||
for edgePointer in edgePointers:
|
for edgePointer in edgePointers:
|
||||||
edge = graph[hash(frozenset(codel))][hash(edgePointer)]
|
edge = graphNode.graphNode[edgePointer]
|
||||||
baseString += self.getEdgeDescription(edge, edgePointer)
|
baseString += self.getEdgeDescription(edge, edgePointer)
|
||||||
edgesInfo.configure(text = baseString)
|
edgesInfo.configure(text = baseString)
|
||||||
|
|
||||||
def getEdgeDescription(self, edge, pointer):
|
def getEdgeDescription(self, edge, pointer):
|
||||||
if isinstance(edge[0], lexerTokens.toColorToken) and edge[0].type == "push":
|
if isinstance(edge[0], lexerTokens.toColorToken) and edge[0].tokenType == "push":
|
||||||
return "{}/{},{} -> {}({})\n".format(edge[1], movement.getDP(pointer[0]), movement.getCC(pointer[1]), edge[0].type, edge[0].codelSize)
|
return "{}/{},{} -> {}({})\n".format(edge[1], movement.getDP(pointer.pointers[0]), movement.getCC(pointer.pointers[1]), edge[0].tokenType, edge[0].codelSize)
|
||||||
else:
|
else:
|
||||||
return "{}/{},{} -> {}\n".format(edge[1], movement.getDP(pointer[0]), movement.getCC(pointer[1]), edge[0].type)
|
return "{}/{},{} -> {}\n".format(edge[1], movement.getDP(pointer.pointers[0]), movement.getCC(pointer.pointers[1]), edge[0].tokenType)
|
||||||
|
|
||||||
def updateStackInfo(self, stack):
|
def updateStackInfo(self, stack):
|
||||||
baseString = ""
|
baseString = ""
|
||||||
@ -70,10 +74,10 @@ class infoManager():
|
|||||||
stackInfoMessage = self.builder.get_object("stackContents", self.programStateInfoFrame)
|
stackInfoMessage = self.builder.get_object("stackContents", self.programStateInfoFrame)
|
||||||
stackInfoMessage.configure(text=baseString)
|
stackInfoMessage.configure(text=baseString)
|
||||||
|
|
||||||
def updatePointersInfo(self, position, pointers):
|
def updatePointersInfo(self, position, direction):
|
||||||
print("Update pointers: {} -> Arrow: {}".format(pointers, movement.getArrow(pointers)))
|
# print("Update pointers: {} -> Arrow: {}".format(direction, movement.getArrow(direction)))
|
||||||
baseString = "Pos: ({},{})\n".format(position[0], position[1])
|
baseString = "Pos: ({},{})\n".format(position.coords[0], position.coords[1])
|
||||||
baseString += u"DP: {} ({},{})".format(movement.getArrow(pointers), movement.getDP(pointers[0]), movement.getCC(pointers[1]))
|
baseString += u"DP: {} ({},{})".format(movement.getArrow(direction), movement.getDP(direction.pointers[0]), movement.getCC(direction.pointers[1]))
|
||||||
|
|
||||||
pointersInfoMessage = self.builder.get_object("pointerMessage", self.programStateInfoFrame)
|
pointersInfoMessage = self.builder.get_object("pointerMessage", self.programStateInfoFrame)
|
||||||
pointersInfoMessage.configure(text=baseString)
|
pointersInfoMessage.configure(text=baseString)
|
@ -1,68 +0,0 @@
|
|||||||
<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
|
|
@ -1,74 +0,0 @@
|
|||||||
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()
|
|
@ -1,20 +1,20 @@
|
|||||||
# helloworld.py
|
# helloworld.py
|
||||||
from time import sleep
|
|
||||||
import threading
|
|
||||||
import tkinter as tk
|
|
||||||
import pygubu
|
import pygubu
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
import interpreter.imageWrapper as imageWrapper
|
sys.path.insert(0, "GUI/TKinter/.")
|
||||||
import interpreter.lexer as lexer
|
from interpreter import imageWrapper as imageWrapper
|
||||||
import interpreter.lexerTokens as lexerTokens
|
from interpreter import lexer as lexer
|
||||||
import interpreter.colors as colors
|
from interpreter import tokens as lexerTokens
|
||||||
import interpreter.movement as movement
|
from interpreter import colors as colors
|
||||||
import interpreter.programState as programState
|
from interpreter import movement as movement
|
||||||
import interpreter.main as main
|
from interpreter import executionFunctions as main
|
||||||
|
from interpreter.dataStructures import programState, direction, position
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import infoManager
|
from GUI import infoManager
|
||||||
import canvasManager
|
from GUI import canvasManager
|
||||||
|
|
||||||
|
|
||||||
class GUI:
|
class GUI:
|
||||||
@ -41,7 +41,7 @@ class GUI:
|
|||||||
self.builder = builder = pygubu.Builder()
|
self.builder = builder = pygubu.Builder()
|
||||||
|
|
||||||
#2: Load an ui file
|
#2: Load an ui file
|
||||||
builder.add_from_file('../assets/tkinterLayout.ui')
|
builder.add_from_file("{}/tkinterLayout.ui".format(os.path.abspath(os.path.dirname(__file__))))
|
||||||
|
|
||||||
#3: Create the mainwindow
|
#3: Create the mainwindow
|
||||||
self.mainwindow = builder.get_object('rootWindow')
|
self.mainwindow = builder.get_object('rootWindow')
|
||||||
@ -63,7 +63,8 @@ class GUI:
|
|||||||
'takeStep': self.takeStep,
|
'takeStep': self.takeStep,
|
||||||
'setExecutionSpeed': self.setExecutionSpeed,
|
'setExecutionSpeed': self.setExecutionSpeed,
|
||||||
'setBreakpoint': self.setBreakpoint,
|
'setBreakpoint': self.setBreakpoint,
|
||||||
'runProgram': self.runProgram
|
'runProgram': self.runProgram,
|
||||||
|
'updateHighlight': self.toggleHighlight
|
||||||
})
|
})
|
||||||
|
|
||||||
self.canvas.bind("<Button-1>", self.canvasPressed)
|
self.canvas.bind("<Button-1>", self.canvasPressed)
|
||||||
@ -104,11 +105,19 @@ class GUI:
|
|||||||
def setBreakpoint(self):
|
def setBreakpoint(self):
|
||||||
print("BREAKPOINT")
|
print("BREAKPOINT")
|
||||||
|
|
||||||
|
def setFileText(self, filePath):
|
||||||
|
print("Filepath: {}".format(filePath))
|
||||||
|
self.builder.get_object("fileNameEntry", self.optionBar).delete(0, len(self.builder.get_object("fileNameEntry", self.optionBar).get()))
|
||||||
|
self.builder.get_object("fileNameEntry", self.optionBar).insert(0, filePath)
|
||||||
|
print("Get filepath: {}".format(self.builder.get_object("fileNameEntry", self.optionBar).get()))
|
||||||
|
|
||||||
def setExecutionSpeed(self, pos):
|
def setExecutionSpeed(self, pos):
|
||||||
if 0 < float(pos) < 100:
|
if 0 < float(pos) < 100:
|
||||||
self.executionSpeed = float(pos)
|
self.executionSpeed = float(pos)
|
||||||
|
|
||||||
|
def toggleHighlight(self):
|
||||||
|
print(self.builder.get_object("highlightEdgeCheck", self.actionBar).instate(['selected']))
|
||||||
|
|
||||||
def getWaitTime(self):
|
def getWaitTime(self):
|
||||||
return self.executionSpeed/100*self.maxWait
|
return self.executionSpeed/100*self.maxWait
|
||||||
|
|
||||||
@ -135,9 +144,12 @@ class GUI:
|
|||||||
|
|
||||||
def loadFile(self):
|
def loadFile(self):
|
||||||
fileName = self.builder.get_object('fileNameEntry', self.optionBar).get()
|
fileName = self.builder.get_object('fileNameEntry', self.optionBar).get()
|
||||||
|
if len(fileName) < 1:
|
||||||
|
return None
|
||||||
|
|
||||||
self.image = imageWrapper.getImage(fileName)
|
self.image = imageWrapper.getImage(fileName)
|
||||||
self.graph = lexer.graphImage(self.image)
|
self.graph = lexer.graphImage(self.image)[0]
|
||||||
self.programState = programState.programState(self.graph, (0,0), (0,0))
|
self.programState = programState(self.graph, position((0,0)), direction((0,0)))
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
print("LOAD FILE!")
|
print("LOAD FILE!")
|
@ -42,7 +42,8 @@
|
|||||||
<child>
|
<child>
|
||||||
<object id="fileNameEntry" class="ttk.Entry">
|
<object id="fileNameEntry" class="ttk.Entry">
|
||||||
<property name="exportselection">false</property>
|
<property name="exportselection">false</property>
|
||||||
<property name="text" translatable="yes">../../Add.png</property>
|
<property name="state">normal</property>
|
||||||
|
<property name="text" translatable="yes">Add.png</property>
|
||||||
<property name="width">44</property>
|
<property name="width">44</property>
|
||||||
<layout>
|
<layout>
|
||||||
<property name="column">1</property>
|
<property name="column">1</property>
|
||||||
@ -146,6 +147,18 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object id="highlightEdgeCheck" class="ttk.Checkbutton">
|
||||||
|
<property name="command">updateHighlight</property>
|
||||||
|
<property name="text" translatable="yes">Highlight edges</property>
|
||||||
|
<property name="variable">int:0</property>
|
||||||
|
<layout>
|
||||||
|
<property name="column">4</property>
|
||||||
|
<property name="propagate">True</property>
|
||||||
|
<property name="row">0</property>
|
||||||
|
</layout>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
BIN
Info/poster.png
Normal file
BIN
Info/poster.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 520 KiB |
BIN
Info/poster.xcf
Normal file
BIN
Info/poster.xcf
Normal file
Binary file not shown.
BIN
interpreter/__init__.pyc
Normal file
BIN
interpreter/__init__.pyc
Normal file
Binary file not shown.
@ -1,7 +1,8 @@
|
|||||||
from typing import Dict
|
from typing import Dict, Union
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.errors as errors
|
||||||
|
|
||||||
class possiblePixels:
|
class possiblePixels:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -29,16 +30,38 @@ class possiblePixels:
|
|||||||
self.black = [0, 0, 0]
|
self.black = [0, 0, 0]
|
||||||
|
|
||||||
|
|
||||||
def getPixelChange(colorStart: np.ndarray, colorEnd: np.ndarray) -> Dict[str, int]:
|
def getPixelChange(colorStart: np.ndarray, colorEnd: np.ndarray) -> Union[Dict[str, int], BaseException]:
|
||||||
pixelsColors = possiblePixels()
|
"""
|
||||||
|
Gets the Hue change and the light change from two different colors
|
||||||
|
:param colorStart: Starting color
|
||||||
|
:param colorEnd: Final color
|
||||||
|
:return: Either a dictionary {'hueChange': int, 'lightChange': int}, or an Exception
|
||||||
|
"""
|
||||||
|
if type(colorStart) is not np.ndarray:
|
||||||
|
return TypeError("Start color is not of type np.ndarray, but {}".format(type(colorStart)))
|
||||||
|
if type(colorEnd) is not np.ndarray:
|
||||||
|
return TypeError("End color is not of type np.ndarray, but {}".format(type(colorStart)))
|
||||||
|
if len(colorStart) < 3:
|
||||||
|
return ValueError("Start color does contain at least 3 values, but {}".format(colorStart))
|
||||||
|
if len(colorEnd) < 3:
|
||||||
|
return ValueError("Start color does contain at least 3 values, but {}".format(colorEnd))
|
||||||
|
|
||||||
|
|
||||||
|
# If either the starting or leaving color is white, there is no change (It is considered a noop)
|
||||||
if isWhite(colorStart) or isWhite(colorEnd):
|
if isWhite(colorStart) or isWhite(colorEnd):
|
||||||
return {"hueChange": 0, "lightChange": 0}
|
return {"hueChange": 0, "lightChange": 0}
|
||||||
|
|
||||||
|
pixelsColors = possiblePixels()
|
||||||
# Converting np arrays to common lists
|
# Converting np arrays to common lists
|
||||||
colorStart = list(colorStart)[:3]
|
colorStart = list(colorStart)[:3]
|
||||||
colorEnd = list(colorEnd)[:3]
|
colorEnd = list(colorEnd)[:3]
|
||||||
|
|
||||||
|
|
||||||
|
if colorStart not in pixelsColors.colors:
|
||||||
|
return errors.UnknownColorError("Color {} is not recognized as a correct color".format(colorStart))
|
||||||
|
if colorEnd not in pixelsColors.colors:
|
||||||
|
return errors.UnknownColorError("Color {} is not recognized as a correct color".format(colorEnd))
|
||||||
|
|
||||||
indexStart = pixelsColors.colors.index(colorStart)
|
indexStart = pixelsColors.colors.index(colorStart)
|
||||||
indexEnd = pixelsColors.colors.index(colorEnd)
|
indexEnd = pixelsColors.colors.index(colorEnd)
|
||||||
|
|
||||||
@ -50,18 +73,33 @@ def getPixelChange(colorStart: np.ndarray, colorEnd: np.ndarray) -> Dict[str, in
|
|||||||
|
|
||||||
|
|
||||||
def isWhite(testColor: np.ndarray) -> bool:
|
def isWhite(testColor: np.ndarray) -> bool:
|
||||||
|
"""
|
||||||
|
Compares the color to white
|
||||||
|
:param testColor: Input color
|
||||||
|
:return: Boolean whether the input color is white (255, 255, 255)
|
||||||
|
"""
|
||||||
colors = possiblePixels()
|
colors = possiblePixels()
|
||||||
testColor = list(testColor)[:3]
|
testColor = list(testColor)[:3]
|
||||||
return testColor == colors.white
|
return testColor == colors.white
|
||||||
|
|
||||||
|
|
||||||
def isBlack(testColor: np.ndarray) -> bool:
|
def isBlack(testColor: np.ndarray) -> bool:
|
||||||
|
"""
|
||||||
|
Compares the color to black
|
||||||
|
:param testColor: Input color
|
||||||
|
:return: Boolean whether the input color is black (0, 0, 0)
|
||||||
|
"""
|
||||||
colors = possiblePixels()
|
colors = possiblePixels()
|
||||||
testColor = list(testColor)[:3]
|
testColor = list(testColor)[:3]
|
||||||
return testColor == colors.black
|
return testColor == colors.black
|
||||||
|
|
||||||
|
|
||||||
def isColor(testColor: np.ndarray) -> bool:
|
def isColor(testColor: np.ndarray) -> bool:
|
||||||
|
"""
|
||||||
|
Compares the color to the 18 pre-defined Piet colors
|
||||||
|
:param testColor: Input color
|
||||||
|
:return: Boolean whether the input color is a Piet-color
|
||||||
|
"""
|
||||||
colors = possiblePixels()
|
colors = possiblePixels()
|
||||||
testColor = list(testColor)[:3]
|
testColor = list(testColor)[:3]
|
||||||
return testColor in colors.colors
|
return testColor in colors.colors
|
||||||
|
145
interpreter/dataStructures.py
Normal file
145
interpreter/dataStructures.py
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
from typing import Set, Tuple, Dict, List
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import interpreter.tokens as tokens
|
||||||
|
|
||||||
|
class position():
|
||||||
|
"""
|
||||||
|
A coords is a tuple of x and y coordinates
|
||||||
|
"""
|
||||||
|
def __init__(self, newPosition: Tuple[int, int]):
|
||||||
|
self.coords = newPosition
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.coords)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memodict):
|
||||||
|
return position(copy.deepcopy(self.coords))
|
||||||
|
|
||||||
|
|
||||||
|
# Functions to allow this datatype to behave in sets
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.coords)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return other.coords == self.coords
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
|
||||||
|
class direction():
|
||||||
|
"""
|
||||||
|
A direction is made up of a Direction Pointer (DP) at .pointers[0] and a Codel Chooser (CC) at .pointers[1].
|
||||||
|
"""
|
||||||
|
def __init__(self, newPointers: Tuple[int, int]):
|
||||||
|
self.pointers = newPointers
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.pointers)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "{}".format(self.pointers)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memodict):
|
||||||
|
return direction(copy.deepcopy(self.pointers))
|
||||||
|
|
||||||
|
# Functions to allow this datatype to behave in sets
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.pointers == other.pointers
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.pointers)
|
||||||
|
|
||||||
|
class codel():
|
||||||
|
"""
|
||||||
|
A codel is a set of positions adjacent to each other and with the same color as each other
|
||||||
|
"""
|
||||||
|
def __init__(self, newCodel: Set[position]):
|
||||||
|
self.codel = newCodel
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.codel)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __copy__(self):
|
||||||
|
return codel(copy.copy(self.codel))
|
||||||
|
|
||||||
|
# Functions to allow this datatype to behave in sets
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(frozenset(self.codel))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return other.codel == self.codel
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
class edge():
|
||||||
|
"""
|
||||||
|
The edge contains a position and direction (DP and CC)
|
||||||
|
"""
|
||||||
|
def __init__(self, newEdge: Tuple[position, direction]):
|
||||||
|
self.edge = newEdge
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.edge)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
|
class graphNode():
|
||||||
|
"""
|
||||||
|
The key to the token and coords is a direction
|
||||||
|
"""
|
||||||
|
def __init__(self, newNode: Dict[direction, Tuple[tokens.baseLexerToken, position]]):
|
||||||
|
self.graphNode = newNode
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.graphNode)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
|
class graph():
|
||||||
|
"""
|
||||||
|
Each codel has a node of directions and tokens associated with those directions (and where the edge will start)
|
||||||
|
"""
|
||||||
|
def __init__(self, newGraph: Dict[codel, graphNode]):
|
||||||
|
self.graph = newGraph
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}".format(self.graph)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
class programState():
|
||||||
|
def __init__(self, newGraph: graph, newPosition: position, newDirection: direction, dataStack: List[int] = None):
|
||||||
|
if dataStack is None:
|
||||||
|
dataStack = []
|
||||||
|
|
||||||
|
self.graph = newGraph
|
||||||
|
self.position = newPosition
|
||||||
|
self.direction = newDirection
|
||||||
|
self.dataStack = dataStack
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{pos} / {pointers}. Stack: {stack}".format(pos=self.position, pointers=self.direction, stack=self.dataStack)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __deepcopy__(self, memodict):
|
||||||
|
# Don't copy the graph, because it is not intended to be edited, and it is a slow process
|
||||||
|
return programState(self.graph, copy.deepcopy(self.position), copy.deepcopy(self.direction), copy.deepcopy(self.dataStack))
|
13
interpreter/errors.py
Normal file
13
interpreter/errors.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class UnknownColorError(BaseException):
|
||||||
|
"""Raise this when a color is found that is not one of the 18 allowed colors"""
|
||||||
|
|
||||||
|
class CommandNotFoundError(BaseException):
|
||||||
|
"""Raise this when a command of an token is unknown"""
|
||||||
|
|
||||||
|
class UnknownTokenError(BaseException):
|
||||||
|
"""Raise this when a token is unknown"""
|
||||||
|
|
||||||
|
class inBlackPixelError(BaseException):
|
||||||
|
"""Raise this when a programstate begins inside a black pixel"""
|
110
interpreter/executionFunctions.py
Normal file
110
interpreter/executionFunctions.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import copy
|
||||||
|
from typing import Union, List, Callable
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# sys.path.insert(0, "../")
|
||||||
|
from interpreter import imageWrapper as imageWrapper
|
||||||
|
from interpreter import lexer as lexer
|
||||||
|
from interpreter import tokens as tokens
|
||||||
|
from interpreter import movement as movement
|
||||||
|
from interpreter import colors as colors
|
||||||
|
from interpreter import tokenFunctions as runner
|
||||||
|
from interpreter import errors as errors
|
||||||
|
from interpreter.dataStructures import programState, position, direction
|
||||||
|
|
||||||
|
|
||||||
|
def interpret(image: np.ndarray) -> Union[programState, List[BaseException]]:
|
||||||
|
"""
|
||||||
|
Interprets and executes a Piet image
|
||||||
|
:param image: Input image
|
||||||
|
:return: Either the final state of the program, or a list of exceptions
|
||||||
|
"""
|
||||||
|
graph = lexer.graphImage(image)
|
||||||
|
if len(graph[1]) > 0:
|
||||||
|
print("The following exceptions occured while making the graph:\n{}".format("".join(list(map(lambda x: "\t{}\n".format(x), graph[1])))))
|
||||||
|
return graph[1]
|
||||||
|
|
||||||
|
startPosition = position((0, 0))
|
||||||
|
pointers = direction((0, 0))
|
||||||
|
PS = programState(graph[0], startPosition, pointers)
|
||||||
|
|
||||||
|
result = runProgram(image, PS)
|
||||||
|
if isinstance(result, BaseException):
|
||||||
|
print("The following exceptions occured while executing the next step:\n{}".format(result))
|
||||||
|
return [result]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def runProgram(image: np.ndarray, PS: programState) -> Union[programState, BaseException]:
|
||||||
|
"""
|
||||||
|
Executes all steps from the image
|
||||||
|
:param image: input image
|
||||||
|
:param PS: current program state with which to make the next step
|
||||||
|
:return: Either the last program state, or a runtime exception
|
||||||
|
"""
|
||||||
|
newState = copy.deepcopy(PS)
|
||||||
|
|
||||||
|
if colors.isBlack(imageWrapper.getPixel(image, newState.position)):
|
||||||
|
return errors.inBlackPixelError("Programstate starts in black pixel at {}".format(newState.position))
|
||||||
|
|
||||||
|
currentCodel = imageWrapper.getCodel(image, newState.position)
|
||||||
|
newGraph = newState.graph.graph
|
||||||
|
graphNode = newGraph[currentCodel]
|
||||||
|
newToken = graphNode.graphNode[newState.direction][0]
|
||||||
|
|
||||||
|
if isinstance(newToken, tokens.terminateToken):
|
||||||
|
return newState
|
||||||
|
|
||||||
|
newState = takeStep(image, newState)
|
||||||
|
if isinstance(newState, BaseException):
|
||||||
|
return newState
|
||||||
|
|
||||||
|
return runProgram(image, newState)
|
||||||
|
|
||||||
|
|
||||||
|
def countSteps(f: Callable):
|
||||||
|
def inner(image: np.ndarray, PS: programState):
|
||||||
|
inner.counter += 1
|
||||||
|
return f(image, PS)
|
||||||
|
inner.counter = 0
|
||||||
|
return inner
|
||||||
|
|
||||||
|
@countSteps
|
||||||
|
def takeStep(image: np.ndarray, PS: programState) -> Union[programState, BaseException]:
|
||||||
|
"""
|
||||||
|
Takes a single step from the programstate
|
||||||
|
:param image: input image
|
||||||
|
:param PS: input programstate
|
||||||
|
:return: Returns either the resulting programstate, or an exception that occurred
|
||||||
|
"""
|
||||||
|
newState = copy.deepcopy(PS)
|
||||||
|
currentCodel = imageWrapper.getCodel(image, newState.position)
|
||||||
|
|
||||||
|
newGraph = newState.graph.graph
|
||||||
|
graphNode = newGraph[currentCodel]
|
||||||
|
newToken = graphNode.graphNode[newState.direction][0]
|
||||||
|
|
||||||
|
edgePosition = graphNode.graphNode[newState.direction][1]
|
||||||
|
|
||||||
|
result = runner.executeToken(newToken, newState.direction, newState.dataStack)
|
||||||
|
|
||||||
|
if isinstance(result, BaseException):
|
||||||
|
return result
|
||||||
|
|
||||||
|
# If the next token is either white or color, just move along. If the token was black (or terminate), the direction
|
||||||
|
# is already changed
|
||||||
|
if isinstance(newToken, (tokens.toWhiteToken, tokens.toColorToken)):
|
||||||
|
newState.position = movement.getNextPosition(edgePosition, newState.direction.pointers[0])
|
||||||
|
|
||||||
|
newState.direction = result[0]
|
||||||
|
newState.dataStack = result[1]
|
||||||
|
|
||||||
|
return newState
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.setrecursionlimit(1000000)
|
||||||
|
im = imageWrapper.getImage("../Piet_hello.png")
|
||||||
|
interpret(im)
|
44
interpreter/helperFunctions.py
Normal file
44
interpreter/helperFunctions.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from typing import Union, List, Any
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import interpreter.imageWrapper as imageWrapper
|
||||||
|
import interpreter.colors as colors
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.tokens as tokens
|
||||||
|
import interpreter.errors as errors
|
||||||
|
from interpreter.dataStructures import edge
|
||||||
|
|
||||||
|
|
||||||
|
def edgeToToken(image: np.ndarray, inputEdge: edge) -> Union[tokens.baseLexerToken, BaseException]:
|
||||||
|
"""
|
||||||
|
This function creates a token based on the given edge
|
||||||
|
:param image: input image
|
||||||
|
:param inputEdge: an edge containing (coords, direction)
|
||||||
|
:return: Either a newly created token, or an exception
|
||||||
|
"""
|
||||||
|
if not imageWrapper.boundsChecker(image, inputEdge.edge[0]):
|
||||||
|
return IndexError("Edge position {} is not in image".format(inputEdge.edge[0]))
|
||||||
|
|
||||||
|
nextPosition = movement.getNextPosition(inputEdge.edge[0], inputEdge.edge[1].pointers[0])
|
||||||
|
if not imageWrapper.boundsChecker(image, nextPosition):
|
||||||
|
return tokens.toBlackToken("edge")
|
||||||
|
|
||||||
|
pixel = imageWrapper.getPixel(image, nextPosition)
|
||||||
|
|
||||||
|
if colors.isBlack(pixel):
|
||||||
|
return tokens.toBlackToken("toBlack")
|
||||||
|
|
||||||
|
if colors.isWhite(pixel):
|
||||||
|
return tokens.toWhiteToken()
|
||||||
|
|
||||||
|
if not colors.isColor(pixel):
|
||||||
|
return tokens.toBlackToken("Unknown color")
|
||||||
|
|
||||||
|
colorChange = colors.getPixelChange(imageWrapper.getPixel(image, inputEdge.edge[0]), imageWrapper.getPixel(image, nextPosition))
|
||||||
|
if isinstance(colorChange, BaseException):
|
||||||
|
# Modify existing error message with location
|
||||||
|
newText = "{} at position {}".format(colorChange.args[0], nextPosition)
|
||||||
|
return errors.UnknownColorError(newText)
|
||||||
|
|
||||||
|
tokenType = tokens.getTokenType(colorChange['hueChange'], colorChange['lightChange'])
|
||||||
|
return tokens.toColorToken(tokenType, len(imageWrapper.getCodel(image, inputEdge.edge[0]).codel))
|
@ -1,29 +1,27 @@
|
|||||||
from typing import Tuple, Union, Set, List
|
from typing import Union
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import interpreter.movement as movement
|
|
||||||
import interpreter.colors as colors
|
import interpreter.colors as colors
|
||||||
|
from interpreter.dataStructures import position, codel
|
||||||
|
|
||||||
|
|
||||||
def boundsChecker(image: np.ndarray, position: Tuple[int, int]) -> bool:
|
def boundsChecker(image: np.ndarray, inputPosition: position) -> bool:
|
||||||
# Position 0 = x-axis, while matrix[0] = y-axis. This is why we compare position[0] with matrix[1]
|
# Position 0 = x-axis, while matrix[0] = y-axis. This is why we compare coords[0] with matrix[1]
|
||||||
return 0 <= position[0] < image.shape[1] and \
|
return 0 <= inputPosition.coords[0] < image.shape[1] and \
|
||||||
0 <= position[1] < image.shape[0]
|
0 <= inputPosition.coords[1] < image.shape[0]
|
||||||
|
|
||||||
|
|
||||||
def getPixel(image: np.ndarray, position: Tuple[int, int]) -> Union[np.ndarray, bool]:
|
def getPixel(image: np.ndarray, inputPosition: position) -> Union[np.ndarray, bool]:
|
||||||
"""
|
"""
|
||||||
This function the pixel at a specific location
|
This function the pixel at a specific location
|
||||||
:param image: np.ndarray of image
|
:param image: np.ndarray of image
|
||||||
:param position: wanted position
|
:param coords: wanted coords
|
||||||
:return: either a cell or False, if the cell is not inside the image
|
:return: either a cell or False, if the cell is not inside the image
|
||||||
"""
|
"""
|
||||||
if boundsChecker(image, position):
|
if boundsChecker(image, inputPosition):
|
||||||
return image[position[1]][position[0]]
|
return image[inputPosition.coords[1]][inputPosition.coords[0]]
|
||||||
else:
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def getImage(fileName: str) -> np.ndarray:
|
def getImage(fileName: str) -> np.ndarray:
|
||||||
@ -38,89 +36,51 @@ def getImage(fileName: str) -> np.ndarray:
|
|||||||
return np.array(image)
|
return np.array(image)
|
||||||
|
|
||||||
|
|
||||||
def getCodel(image: np.ndarray, position: Tuple[int, int], foundPixels: Set[Tuple[int, int]] = None) -> Set[Tuple[int, int]]:
|
def getCodel(image: np.ndarray, inputPosition: position, foundPixels: codel = None) -> codel:
|
||||||
"""
|
"""
|
||||||
This function finds all adjacent pixels with the same color as the pixel on the given position
|
This function finds all adjacent pixels with the same color as the pixel on the given coords
|
||||||
|
|
||||||
If you pass a white pixel, this will return a set with only the white pixel in it.
|
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 image: The image with all pixel values
|
||||||
:param position: Starting position
|
:param coords: Starting coords
|
||||||
:param foundPixels: currently found pixels
|
:param foundPixels: currently found pixels
|
||||||
:return: A Set with all positions of same-colored pixels (Also known as a codel)
|
:return: A Set with all positions of same-colored pixels (Also known as a codel)
|
||||||
"""
|
"""
|
||||||
if foundPixels is None:
|
if foundPixels is None:
|
||||||
foundPixels = set()
|
foundPixels = codel(set())
|
||||||
|
|
||||||
# If this position is already in the set, it has already been traversed
|
# If this coords is already in the set, it has already been traversed
|
||||||
if position in foundPixels:
|
if inputPosition in foundPixels.codel:
|
||||||
return foundPixels
|
return foundPixels
|
||||||
|
|
||||||
if colors.isWhite(getPixel(image, position)):
|
if colors.isWhite(getPixel(image, inputPosition)):
|
||||||
foundPixels.add(position)
|
foundPixels.codel.add(inputPosition)
|
||||||
return foundPixels
|
return foundPixels
|
||||||
|
|
||||||
x = position[0]
|
x = inputPosition.coords[0]
|
||||||
y = position[1]
|
y = inputPosition.coords[1]
|
||||||
|
|
||||||
foundPixels.add(position)
|
foundPixels.codel.add(inputPosition)
|
||||||
|
|
||||||
# right
|
# right
|
||||||
if boundsChecker(image, (x + 1, y)) and np.all(image[y][x + 1] == image[y][x]):
|
if boundsChecker(image, position((x + 1, y))) and np.all(image[y][x + 1] == image[y][x]):
|
||||||
newPosition = (position[0] + 1, position[1])
|
newPosition = position((inputPosition.coords[0] + 1, inputPosition.coords[1]))
|
||||||
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
foundPixels = codel(foundPixels.codel.union(getCodel(image, newPosition, foundPixels).codel))
|
||||||
|
|
||||||
# below
|
# below
|
||||||
if boundsChecker(image, (x, y - 1)) and np.all(image[y - 1][x] == image[y][x]):
|
if boundsChecker(image, position((x, y - 1))) and np.all(image[y - 1][x] == image[y][x]):
|
||||||
newPosition = (position[0], position[1] - 1)
|
newPosition = position((inputPosition.coords[0], inputPosition.coords[1] - 1))
|
||||||
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
foundPixels = codel(foundPixels.codel.union(getCodel(image, newPosition, foundPixels).codel))
|
||||||
|
|
||||||
# left
|
# left
|
||||||
if boundsChecker(image, (x - 1, y)) and np.all(image[y][x - 1] == image[y][x]):
|
if boundsChecker(image, position((x - 1, y))) and np.all(image[y][x - 1] == image[y][x]):
|
||||||
newPosition = (position[0] - 1, position[1])
|
newPosition = position((inputPosition.coords[0] - 1, inputPosition.coords[1]))
|
||||||
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
foundPixels = codel(foundPixels.codel.union(getCodel(image, newPosition, foundPixels).codel))
|
||||||
|
|
||||||
# above
|
# above
|
||||||
if boundsChecker(image, (x, y + 1)) and np.all(image[y + 1][x] == image[y][x]):
|
if boundsChecker(image, position((x, y + 1))) and np.all(image[y + 1][x] == image[y][x]):
|
||||||
newPosition = (position[0], position[1] + 1)
|
newPosition = position((inputPosition.coords[0], inputPosition.coords[1] + 1))
|
||||||
foundPixels = foundPixels.union(getCodel(image, newPosition, foundPixels))
|
foundPixels = codel(foundPixels.codel.union(getCodel(image, newPosition, foundPixels).codel))
|
||||||
|
|
||||||
return 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))
|
|
||||||
|
|
||||||
|
@ -1,138 +1,148 @@
|
|||||||
from typing import List, Tuple, Set, Dict, Union
|
from typing import List, Union, Tuple
|
||||||
|
import copy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import interpreter.colors as colors
|
import interpreter.colors as colors
|
||||||
import interpreter.imageWrapper as imageWrapper
|
import interpreter.imageWrapper as imageWrapper
|
||||||
import interpreter.lexerTokens as lexerTokens
|
import interpreter.tokens as tokens
|
||||||
|
import interpreter.helperFunctions as helperFunctions
|
||||||
import interpreter.movement as movement
|
import interpreter.movement as movement
|
||||||
|
from interpreter.dataStructures import position, codel, edge, graphNode, graph, direction
|
||||||
|
|
||||||
|
|
||||||
def cyclePosition(image: np.ndarray, startPosition: Tuple[int, int]) -> Union[Tuple[int, int], bool]:
|
def cyclePosition(image: np.ndarray, startPosition: position) -> Union[position, bool]:
|
||||||
"""
|
"""
|
||||||
:param image: numpy image array
|
:param image: numpy image array
|
||||||
:param startPosition: from where to go to Tuple (x,y)
|
:param startPosition: from where to go to Tuple (x,y)
|
||||||
:return: newPosition (x,y), or false if new position would fall out of bounds
|
:return: newPosition (x,y), or false if new coords would fall out of bounds
|
||||||
"""
|
"""
|
||||||
if not imageWrapper.boundsChecker(image, startPosition):
|
if not imageWrapper.boundsChecker(image, startPosition):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if startPosition[0] == image.shape[1] - 1:
|
if startPosition.coords[0] == image.shape[1] - 1:
|
||||||
if startPosition[1] < image.shape[0] - 1:
|
if startPosition.coords[1] < image.shape[0] - 1:
|
||||||
return (0, startPosition[1] + 1)
|
return position((0, startPosition.coords[1] + 1))
|
||||||
else:
|
return False
|
||||||
return False
|
return position((startPosition.coords[0] + 1, startPosition.coords[1]))
|
||||||
else:
|
|
||||||
return (startPosition[0] + 1, startPosition[1])
|
|
||||||
|
|
||||||
|
|
||||||
|
def getCodels(image: np.ndarray, positionList: List[position]) -> List[codel]:
|
||||||
def getCodelsEfficient(image: np.ndarray, positionList: List[Tuple[int, int]]) -> List[Set[Tuple[int, int]]]:
|
"""
|
||||||
|
Makes a list of codels from an image and a lits of positions to check
|
||||||
|
:param image: an np.ndarray representing the image
|
||||||
|
:param positionList: A list of positions, for which to find adjacent pixels of the same color
|
||||||
|
:return: A list of codels found in the given image
|
||||||
|
"""
|
||||||
if len(positionList) == 0:
|
if len(positionList) == 0:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
copiedList = positionList.copy()
|
copiedList = positionList.copy()
|
||||||
newPosition = copiedList.pop(0)
|
newPosition = copiedList.pop(0)
|
||||||
|
|
||||||
|
|
||||||
if colors.isBlack(imageWrapper.getPixel(image, newPosition)):
|
if colors.isBlack(imageWrapper.getPixel(image, newPosition)):
|
||||||
return getCodelsEfficient(image, copiedList)
|
return getCodels(image, copiedList)
|
||||||
|
|
||||||
newCodel = imageWrapper.getCodel(image, newPosition)
|
newCodel = imageWrapper.getCodel(image, newPosition)
|
||||||
|
|
||||||
# print("Original positionList: {}".format(positionList))
|
# Remove found positions from coords list
|
||||||
# print("Codel found: {}".format(newCodel))
|
copiedList = list(set(copiedList) - newCodel.codel)
|
||||||
# Remove found positions from position list
|
codelList = getCodels(image, copiedList)
|
||||||
copiedList = list(set(copiedList) - newCodel)
|
|
||||||
# print("New positionList: {}".format(copiedList))
|
|
||||||
codelList = getCodelsEfficient(image, copiedList)
|
|
||||||
|
|
||||||
codelList.append(newCodel)
|
codelList.append(newCodel)
|
||||||
return codelList
|
return codelList
|
||||||
|
|
||||||
|
|
||||||
|
def edgesToGraphNode(image: np.ndarray, edges: List[edge]) -> Tuple[graphNode, List[BaseException]]:
|
||||||
|
|
||||||
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
|
Constructs a dictionary with each pointer possibility as key and (token, coords) as value
|
||||||
:param image: Image required to find calculate tokens
|
:param image: Image required to find calculate tokens
|
||||||
:param edges: List[Tuple[position, pointers]]
|
:param edges: List[Tuple[coords, pointers]]
|
||||||
:return:
|
:return: A graphNode containing tokens for each edge given, and a list of exceptions occurred during creation
|
||||||
"""
|
"""
|
||||||
return dict(map(lambda x, lambdaImage=image: (hash(x[1]), (lexerTokens.edgeToToken(lambdaImage, x), x[0])), edges))
|
node = graphNode(dict(map(lambda x, lambdaImage=image: (x.edge[1], (helperFunctions.edgeToToken(lambdaImage, x), x.edge[0])), edges)))
|
||||||
|
# Extract the exceptions from each edge
|
||||||
|
exceptions = list(map(lambda x: x[1][0], filter(lambda graphNodeItem: isinstance(graphNodeItem[1][0], BaseException), node.graphNode.items())))
|
||||||
|
return (node, exceptions)
|
||||||
|
|
||||||
|
|
||||||
def isCodeldictTerminate(codelDict: Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]) -> bool:
|
def isGraphNodeTerminate(inputNode: graphNode) -> bool:
|
||||||
return all(map(lambda x: isinstance(x[1][0], lexerTokens.toBlackToken), codelDict.items()))
|
"""
|
||||||
|
Gets the token from the graphNode, and compares it against the toBlackToken from tokens.
|
||||||
|
:param inputNode: A graph node
|
||||||
|
:return: True if all tokens in graph node are toBlackTokens, False otherwise.
|
||||||
|
"""
|
||||||
|
return all(map(lambda x: isinstance(x[1][0], tokens.toBlackToken), inputNode.graphNode.items()))
|
||||||
|
|
||||||
|
|
||||||
def codelDictToTerminate(codelDict: Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]) -> Dict[int, Tuple[lexerTokens.terminateToken, Tuple[int, int]]]:
|
def graphNodeToTerminate(inputNode: graphNode) -> graphNode:
|
||||||
return dict(map(lambda x: (x[0], (lexerTokens.terminateToken(), x[1][1])), codelDict.items()))
|
"""
|
||||||
|
Replaces all tokens in the graphNode to terminate tokens
|
||||||
|
:param inputNode: A graph node
|
||||||
|
:return: A new graph node with only terminateTokens
|
||||||
|
"""
|
||||||
|
return graphNode(dict(map(lambda x: (x[0], (tokens.terminateToken(), x[1][1])), inputNode.graphNode.items())))
|
||||||
|
|
||||||
|
|
||||||
def codelToCodelDict(image: np.ndarray, codel: Set[Tuple[int, int]], edgePointers: List[Tuple[int, int]]) -> Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]:
|
def codelToGraphNode(image: np.ndarray, inputCodel: codel, edgePointers: List[direction]) -> Tuple[graphNode, List[BaseException]]:
|
||||||
"""
|
"""
|
||||||
:param image: image
|
:param image: image
|
||||||
:param codel: set of positions within the same color
|
:param inputCodel: set of positions within the same color
|
||||||
:param edgePointers: list of pointers to find tokens for
|
:param edgePointers: list of pointers to find tokens for
|
||||||
:return: A dictionary with each pointer possibility as key and (token, position) as value
|
:return: A dictionary with each pointer possibility as key and (token, coords) as value, and a list of exceptions
|
||||||
"""
|
"""
|
||||||
# make codel immutable
|
# make codel immutable
|
||||||
copiedCodel = frozenset(codel)
|
copiedCodel = copy.copy(inputCodel)
|
||||||
# Find all edges along the codel and edgepointers
|
# Find all edges along the codel and edgepointers
|
||||||
edges = list(map(lambda pointers, lambdaCodel=copiedCodel: (movement.findEdge(lambdaCodel, pointers), pointers), edgePointers))
|
edges = list(map(lambda pointers, lambdaCodel=copiedCodel: edge((movement.findEdge(lambdaCodel, pointers), pointers)), edgePointers))
|
||||||
codelDict = edgesToCodeldict(image, edges)
|
newGraphNode = edgesToGraphNode(image, edges)
|
||||||
|
|
||||||
if isCodeldictTerminate(codelDict):
|
# If there were exceptions in the graph node, there is no need to terminate them
|
||||||
codelDict = codelDictToTerminate(codelDict)
|
if len(newGraphNode[1]) > 0:
|
||||||
|
return newGraphNode
|
||||||
|
|
||||||
return codelDict
|
# Check if all tokens go either towards black pixels, or towards the edge. If thats the case, this is a terminate-node
|
||||||
|
if isGraphNodeTerminate(newGraphNode[0]):
|
||||||
|
return (graphNodeToTerminate(newGraphNode[0]), newGraphNode[1])
|
||||||
|
|
||||||
|
return newGraphNode
|
||||||
|
|
||||||
|
def codelsToGraph(image: np.ndarray, codels: List[codel]) -> Tuple[graph, List[BaseException]]:
|
||||||
|
"""
|
||||||
|
Converts a list of codels into a graph
|
||||||
|
:param image: Input image
|
||||||
|
:param codels: Input list of codels
|
||||||
|
:return: A tuple of a graph and a list of exceptions
|
||||||
|
"""
|
||||||
|
codels = codels.copy()
|
||||||
|
# Get an iterator of all possible directions (0,0), (0,1), (1,0) etc...
|
||||||
|
edgePointers = list(map(lambda i: direction((i % 4, int(i / 4))), iter(range(8))))
|
||||||
|
|
||||||
|
# If no more codels are to be graphed, return
|
||||||
|
if len(codels) == 0:
|
||||||
|
newGraph = graph(dict())
|
||||||
|
return (newGraph, [])
|
||||||
|
|
||||||
|
newNode = codelToGraphNode(image, codels[0], edgePointers)
|
||||||
|
newGraph = codelsToGraph(image, codels[1:])
|
||||||
|
newGraph[0].graph[codels[0]] = newNode[0]
|
||||||
|
|
||||||
|
errorList = newNode[1]
|
||||||
|
errorList.extend(newGraph[1])
|
||||||
|
return (newGraph[0], errorList)
|
||||||
|
|
||||||
|
|
||||||
def graphImage(image: np.ndarray, position: Tuple[int, int] = (0, 0)) -> Dict[int, Dict[int, Tuple[lexerTokens.baseLexerToken, Tuple[int, int]]]]:
|
def graphImage(image: np.ndarray) -> Tuple[graph, List[BaseException]]:
|
||||||
"""
|
"""
|
||||||
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.
|
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 image:
|
||||||
:param position:
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# allCodels = getAllCodels(image, position)
|
coords = np.ndindex(image.shape[1], image.shape[0])
|
||||||
allPositions = []
|
# Converts tuples of coordinates into position objects
|
||||||
whiteCodels = []
|
positions = map(position, coords)
|
||||||
print(image)
|
# Makes a list of non-black pixel positions
|
||||||
for y, row in enumerate(image):
|
nonBlackPositions = list(filter(lambda pos: not colors.isBlack(imageWrapper.getPixel(image, pos)), positions))
|
||||||
for x, pixel in enumerate(row):
|
# Gets all codels from all non-black pixel positions
|
||||||
if not colors.isBlack(pixel):
|
allCodels = getCodels(image, nonBlackPositions)
|
||||||
if colors.isWhite(pixel):
|
# Makes a graph with the codel as key, and the node as value
|
||||||
whiteCodels.append((x,y))
|
return codelsToGraph(image, allCodels)
|
||||||
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))
|
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
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])))
|
|
@ -1,96 +0,0 @@
|
|||||||
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()
|
|
@ -1,48 +1,68 @@
|
|||||||
from typing import Tuple, Set, Union
|
from typing import Union
|
||||||
|
|
||||||
|
from interpreter.dataStructures import direction, position, codel
|
||||||
|
|
||||||
def getDP(directionPointer: int) -> str:
|
def getDP(directionPointer: int) -> str:
|
||||||
|
"""
|
||||||
|
Finds the correct direction pointer string
|
||||||
|
:param directionPointer: Input direction pointer
|
||||||
|
:return: direction pointer string
|
||||||
|
"""
|
||||||
if directionPointer == 0:
|
if directionPointer == 0:
|
||||||
return 'r'
|
return 'r'
|
||||||
elif directionPointer == 1:
|
if directionPointer == 1:
|
||||||
return 'd'
|
return 'd'
|
||||||
elif directionPointer == 2:
|
if directionPointer == 2:
|
||||||
return 'l'
|
return 'l'
|
||||||
else:
|
return 'u'
|
||||||
return 'u'
|
|
||||||
|
|
||||||
|
|
||||||
def getCC(codelChooser: int) -> str:
|
def getCC(codelChooser: int) -> str:
|
||||||
|
"""
|
||||||
|
finds the correct codel chooser direction string
|
||||||
|
:param codelChooser: input codel chooser
|
||||||
|
:return: codel chooser direction string
|
||||||
|
"""
|
||||||
if codelChooser == 0:
|
if codelChooser == 0:
|
||||||
return 'l'
|
return 'l'
|
||||||
else:
|
return 'r'
|
||||||
return 'r'
|
|
||||||
|
|
||||||
|
|
||||||
def getArrow(pointers: Tuple[int, int]) -> str:
|
def getArrow(direction: direction) -> str:
|
||||||
if pointers[0] == 0:
|
"""
|
||||||
if pointers[1] == 0:
|
Returns the Unicode arrow from the direction
|
||||||
|
:param direction: Input direction
|
||||||
|
:return: Unicode arrow string
|
||||||
|
"""
|
||||||
|
if direction.pointers[0] == 0:
|
||||||
|
if direction.pointers[1] == 0:
|
||||||
return "\u2197"
|
return "\u2197"
|
||||||
elif pointers[1] == 1:
|
if direction.pointers[1] == 1:
|
||||||
return "\u2198"
|
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 ""
|
return ""
|
||||||
|
|
||||||
|
if direction.pointers[0] == 1:
|
||||||
|
if direction.pointers[1] == 0:
|
||||||
|
return "\u2198"
|
||||||
|
if direction.pointers[1] == 1:
|
||||||
|
return "\u2199"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if direction.pointers[0] == 2:
|
||||||
|
if direction.pointers[1] == 0:
|
||||||
|
return "\u2199"
|
||||||
|
if direction.pointers[1] == 1:
|
||||||
|
return "\u2196"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if direction.pointers[0] == 3:
|
||||||
|
if direction.pointers[1] == 0:
|
||||||
|
return "\u2196"
|
||||||
|
if direction.pointers[1] == 1:
|
||||||
|
return "\u2197"
|
||||||
|
return ""
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def flipCC(codelChooser: int) -> int:
|
def flipCC(codelChooser: int) -> int:
|
||||||
"""
|
"""
|
||||||
@ -63,8 +83,15 @@ def flipDP(directionPointer: int) -> int:
|
|||||||
return directionPointer + 1
|
return directionPointer + 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def flipDPInvert(directionPointer: int, count = 0) -> int:
|
||||||
|
if count >= 0:
|
||||||
|
return directionPointer
|
||||||
|
else:
|
||||||
|
if directionPointer != 0:
|
||||||
|
return flipDPInvert(directionPointer - 1, count + 1)
|
||||||
|
return flipDPInvert(3, count + 1)
|
||||||
|
|
||||||
def flip(pointers: Tuple[int, int]) -> Tuple[int, int]:
|
def flip(inputDirection: direction) -> direction:
|
||||||
"""
|
"""
|
||||||
Chooses what part of the general pointer to flip, by DP%2 == CC rule, providing the following flow:
|
Chooses what part of the general pointer to flip, by DP%2 == CC rule, providing the following flow:
|
||||||
(0,0) -> (0,1)
|
(0,0) -> (0,1)
|
||||||
@ -75,93 +102,101 @@ def flip(pointers: Tuple[int, int]) -> Tuple[int, int]:
|
|||||||
(2,1) -> (3,1)
|
(2,1) -> (3,1)
|
||||||
(3,1) -> (3,0)
|
(3,1) -> (3,0)
|
||||||
(3,0) -> (0,0)
|
(3,0) -> (0,0)
|
||||||
:param pointers: Original state of the pointers
|
:param inputDirection: Original state of the pointers
|
||||||
:return: Tuple of ints containing new pointers
|
:return: Tuple of ints containing new pointers
|
||||||
"""
|
"""
|
||||||
if pointers[0] % 2 == pointers[1]:
|
if inputDirection.pointers[0] % 2 == inputDirection.pointers[1]:
|
||||||
return (pointers[0], flipCC(pointers[1]))
|
return direction((inputDirection.pointers[0], flipCC(inputDirection.pointers[1])))
|
||||||
else:
|
return direction((flipDP(inputDirection.pointers[0]), inputDirection.pointers[1]))
|
||||||
return (flipDP(pointers[0]), pointers[1])
|
|
||||||
|
|
||||||
|
|
||||||
# TODO FIX KEYERROR
|
# TODO FIX KEYERROR
|
||||||
def getNextPosition(startPosition: Tuple[int, int], directionPointer: int) -> Union[Tuple[int, int], KeyError]:
|
def getNextPosition(startPosition: position, directionPointer: int) -> Union[position, KeyError]:
|
||||||
|
"""
|
||||||
|
Finds next position along the direction pointer
|
||||||
|
:param startPosition: start position
|
||||||
|
:param directionPointer: direction pointer
|
||||||
|
:return: next position
|
||||||
|
"""
|
||||||
if directionPointer == 0:
|
if directionPointer == 0:
|
||||||
return (startPosition[0] + 1, startPosition[1])
|
return position((startPosition.coords[0] + 1, startPosition.coords[1]))
|
||||||
elif directionPointer == 1:
|
if directionPointer == 1:
|
||||||
return (startPosition[0], startPosition[1] + 1)
|
return position((startPosition.coords[0], startPosition.coords[1] + 1))
|
||||||
elif directionPointer == 2:
|
if directionPointer == 2:
|
||||||
return (startPosition[0] - 1, startPosition[1])
|
return position((startPosition.coords[0] - 1, startPosition.coords[1]))
|
||||||
elif directionPointer == 3:
|
if directionPointer == 3:
|
||||||
return (startPosition[0], startPosition[1] - 1)
|
return position((startPosition.coords[0], startPosition.coords[1] - 1))
|
||||||
else:
|
return KeyError("Given key {} is no valid Direction Pointer (0, 1, 2, or 3)".format(directionPointer))
|
||||||
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]:
|
def getPreviousPosition(startPosition: position, directionPointer: int) -> position:
|
||||||
|
"""
|
||||||
|
Inverts the directionPointer, and finds the next position
|
||||||
|
:param startPosition: Input position
|
||||||
|
:param directionPointer: Input directionpointer
|
||||||
|
:return: Previous position
|
||||||
|
"""
|
||||||
if directionPointer == 0:
|
if directionPointer == 0:
|
||||||
return getNextPosition(startPosition, 2)
|
return getNextPosition(startPosition, 2)
|
||||||
elif directionPointer == 1:
|
if directionPointer == 1:
|
||||||
return getNextPosition(startPosition, 3)
|
return getNextPosition(startPosition, 3)
|
||||||
elif directionPointer == 2:
|
if directionPointer == 2:
|
||||||
return getNextPosition(startPosition, 0)
|
return getNextPosition(startPosition, 0)
|
||||||
return getNextPosition(startPosition, 1)
|
return getNextPosition(startPosition, 1)
|
||||||
# TODO: make the else return an error, and elif return 'd' position
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Error handling
|
def findEdge(inputCodel: codel, inputDirection: direction) -> Union[position, bool]:
|
||||||
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
|
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 inputCodel: Set of adjacent positions with the same color
|
||||||
:param pointers: Tuple where pointers[0] = DP and pointers[1] = CC
|
: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
|
:return: Position within the codel that is adjacent to the next pixel to go to
|
||||||
"""
|
"""
|
||||||
dp = pointers[0]
|
dp = inputDirection.pointers[0]
|
||||||
cc = pointers[1]
|
cc = inputDirection.pointers[1]
|
||||||
|
|
||||||
if dp == 0:
|
if dp == 0:
|
||||||
edgePosition = max(codel, key=lambda lambdaPos: lambdaPos[0])
|
edgePosition = max(inputCodel.codel, key=lambda lambdaPos: lambdaPos.coords[0])
|
||||||
for pos in codel:
|
for pos in inputCodel.codel:
|
||||||
if pos[0] == edgePosition[0]:
|
if pos.coords[0] == edgePosition.coords[0]:
|
||||||
# -> ^ Right and up
|
# -> ^ Right and up
|
||||||
if cc == 0 and pos[1] < edgePosition[1]:
|
if cc == 0 and pos.coords[1] < edgePosition.coords[1]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
# -> V Right and down
|
# -> V Right and down
|
||||||
elif cc == 1 and pos[1] > edgePosition[1]:
|
if cc == 1 and pos.coords[1] > edgePosition.coords[1]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
return edgePosition
|
return edgePosition
|
||||||
elif dp == 1:
|
elif dp == 1:
|
||||||
edgePosition = max(codel, key=lambda lambdaPos: lambdaPos[1])
|
edgePosition = max(inputCodel.codel, key=lambda lambdaPos: lambdaPos.coords[1])
|
||||||
for pos in codel:
|
for pos in inputCodel.codel:
|
||||||
if pos[1] == edgePosition[1]:
|
if pos.coords[1] == edgePosition.coords[1]:
|
||||||
# V -> Down and right
|
# V -> Down and right
|
||||||
if cc == 0 and pos[0] > edgePosition[0]:
|
if cc == 0 and pos.coords[0] > edgePosition.coords[0]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
# V <- Down and left
|
# V <- Down and left
|
||||||
elif cc == 1 and pos[0] < edgePosition[0]:
|
elif cc == 1 and pos.coords[0] < edgePosition.coords[0]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
return edgePosition
|
return edgePosition
|
||||||
elif dp == 2:
|
elif dp == 2:
|
||||||
edgePosition = min(codel, key=lambda lambdaPos: lambdaPos[0])
|
edgePosition = min(inputCodel.codel, key=lambda lambdaPos: lambdaPos.coords[0])
|
||||||
for pos in codel:
|
for pos in inputCodel.codel:
|
||||||
if pos[0] == edgePosition[0]:
|
if pos.coords[0] == edgePosition.coords[0]:
|
||||||
# <- V Left and down
|
# <- V Left and down
|
||||||
if cc == 0 and pos[1] > edgePosition[1]:
|
if cc == 0 and pos.coords[1] > edgePosition.coords[1]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
# <- ^ left and up
|
# <- ^ left and up
|
||||||
elif cc == 1 and pos[1] < edgePosition[1]:
|
elif cc == 1 and pos.coords[1] < edgePosition.coords[1]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
return edgePosition
|
return edgePosition
|
||||||
elif dp == 3:
|
elif dp == 3:
|
||||||
edgePosition = min(codel, key=lambda lambdaPos: lambdaPos[1])
|
edgePosition = min(inputCodel.codel, key=lambda lambdaPos: lambdaPos.coords[1])
|
||||||
for pos in codel:
|
for pos in inputCodel.codel:
|
||||||
if pos[1] == edgePosition[1]:
|
if pos.coords[1] == edgePosition.coords[1]:
|
||||||
# ^ <- Up and left
|
# ^ <- Up and left
|
||||||
if cc == 0 and pos[0] < edgePosition[0]:
|
if cc == 0 and pos.coords[0] < edgePosition.coords[0]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
# ^ -> Up and right
|
# ^ -> Up and right
|
||||||
elif cc == 1 and pos[0] > edgePosition[0]:
|
elif cc == 1 and pos.coords[0] > edgePosition.coords[0]:
|
||||||
edgePosition = pos
|
edgePosition = pos
|
||||||
return edgePosition
|
return edgePosition
|
||||||
else:
|
else:
|
||||||
|
8177
interpreter/output2.txt
Normal file
8177
interpreter/output2.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
|
|||||||
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))
|
|
@ -1,277 +0,0 @@
|
|||||||
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)
|
|
380
interpreter/tokenFunctions.py
Normal file
380
interpreter/tokenFunctions.py
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
from typing import List, Tuple, Union
|
||||||
|
import copy
|
||||||
|
|
||||||
|
import interpreter.tokens as lexerTokens
|
||||||
|
import interpreter.movement as movement
|
||||||
|
import interpreter.errors as errors
|
||||||
|
from interpreter.dataStructures import direction
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Nettere afhandeling errors (Union[Tuple[List[int], Tuple[int, int]], bool])
|
||||||
|
# TODO Test cases maken per token
|
||||||
|
def executeToken(token: lexerTokens.baseLexerToken, inputDirection: direction, dataStack: List[int]) -> Union[Tuple[direction, List[int]], BaseException]:
|
||||||
|
"""
|
||||||
|
Executes the function associated with tokens
|
||||||
|
:param token: Input token
|
||||||
|
:param inputDirection: Input direction
|
||||||
|
:param dataStack: Input stack
|
||||||
|
:return: Either a combination of a new stack and direction, or a runtime Exception
|
||||||
|
"""
|
||||||
|
if isinstance(token, lexerTokens.toBlackToken):
|
||||||
|
newPointers = movement.flip(inputDirection)
|
||||||
|
return (newPointers, dataStack)
|
||||||
|
if isinstance(token, lexerTokens.toWhiteToken):
|
||||||
|
return (inputDirection, dataStack)
|
||||||
|
if isinstance(token, lexerTokens.toColorToken):
|
||||||
|
return executeColorToken(token, inputDirection, dataStack)
|
||||||
|
if isinstance(token, lexerTokens.terminateToken):
|
||||||
|
return (inputDirection, dataStack)
|
||||||
|
return errors.UnknownTokenError("Token of type {} is unknown")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def executeColorToken(token: lexerTokens.toColorToken, inputDirection: direction, dataStack: List[int]) -> Union[Tuple[direction, List[int]], BaseException]:
|
||||||
|
"""
|
||||||
|
Executes the to color operations
|
||||||
|
:param token: input token
|
||||||
|
:param inputDirection: Input direction
|
||||||
|
:param dataStack: Input data stack
|
||||||
|
:return: either a combination of a new direction and data stack, or a runtime Exception
|
||||||
|
"""
|
||||||
|
if token.tokenType == "noop":
|
||||||
|
return noopOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "push":
|
||||||
|
# Needs the codelsize to push
|
||||||
|
return pushOperator(token, inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "pop":
|
||||||
|
return popOperator(inputDirection, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "add":
|
||||||
|
return addOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "subtract":
|
||||||
|
return subtractOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "multiply":
|
||||||
|
return multiplyOperator(inputDirection, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "divide":
|
||||||
|
return divideOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "mod":
|
||||||
|
return modOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "not":
|
||||||
|
return notOperator(inputDirection, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "greater":
|
||||||
|
return greaterOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "pointer":
|
||||||
|
return pointerOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "switch":
|
||||||
|
return switchOperator(inputDirection, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "duplicate":
|
||||||
|
return duplicateOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "roll":
|
||||||
|
return rollOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "inN":
|
||||||
|
return inNOperator(inputDirection, dataStack)
|
||||||
|
|
||||||
|
elif token.tokenType == "inC":
|
||||||
|
return inCOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "outN":
|
||||||
|
return outNOperator(inputDirection, dataStack)
|
||||||
|
elif token.tokenType == "outC":
|
||||||
|
return outCOperator(inputDirection, dataStack)
|
||||||
|
else:
|
||||||
|
return errors.UnknownTokenError("Token {} not found".format(token.tokenType))
|
||||||
|
|
||||||
|
|
||||||
|
def noopOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, 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 (copy.deepcopy(inputDirection), dataStack.copy())
|
||||||
|
|
||||||
|
|
||||||
|
def addOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, 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 = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
newStack.append(newStack.pop() + newStack.pop())
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def subtractOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Subtracts the second value from the first value of the stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
first = newStack.pop()
|
||||||
|
second = newStack.pop()
|
||||||
|
newStack.append(second - first)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def multiplyOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pops the first 2 values from the stack, and pushes the product of them
|
||||||
|
"""
|
||||||
|
newStack = list(dataStack)
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
newStack.append(newStack.pop() * newStack.pop())
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def divideOperator(inputDirection: direction, dataStack: List[int]) -> Union[Tuple[direction, List[int]], BaseException]:
|
||||||
|
"""
|
||||||
|
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 = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
first = newStack.pop()
|
||||||
|
second = newStack.pop()
|
||||||
|
if second == 0:
|
||||||
|
return ZeroDivisionError("Division by zero {}/{}".format(first, second))
|
||||||
|
newStack.append(int(second / first))
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def modOperator(inputDirection: direction, dataStack: List[int]) -> Union[Tuple[direction, List[int]], BaseException]:
|
||||||
|
"""
|
||||||
|
Pops the first two values of the stack, mods the second value by the first value and pushes the result back to the stack
|
||||||
|
:param inputDirection:
|
||||||
|
:param dataStack:
|
||||||
|
:return: Tuple of direction and new data stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
valA = newStack.pop()
|
||||||
|
valB = newStack.pop()
|
||||||
|
if valB == 0:
|
||||||
|
# TODO ERROR
|
||||||
|
return ZeroDivisionError("Second value is 0: {}%{}".format(valA, valB))
|
||||||
|
newStack.append(valB % valA)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def greaterOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, 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 = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
valA = newStack.pop()
|
||||||
|
valB = newStack.pop()
|
||||||
|
|
||||||
|
newStack.append(int(valB > valA))
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def notOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, 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 = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
result = 1 if newStack.pop() == 0 else 0
|
||||||
|
newStack.append(result)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def pointerOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pop the top value of the stack, and turn the direction pointer that many times. (counter clockwise if negative)
|
||||||
|
:param inputDirection:
|
||||||
|
:param dataStack:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
dp = inputDirection.pointers[0]
|
||||||
|
dpTurnCount = newStack.pop()
|
||||||
|
# Python module makes negative modulo's positive, so we need to manually flip the DP the required amount of times
|
||||||
|
if dpTurnCount < 0:
|
||||||
|
dp = movement.flipDPInvert(dp, dpTurnCount)
|
||||||
|
return (direction((dp, inputDirection.pointers[1])), newStack)
|
||||||
|
else:
|
||||||
|
# Cycle the DP forward by using the module operator
|
||||||
|
newDP = (inputDirection.pointers[0] + (dpTurnCount % 4)) % 4
|
||||||
|
return (direction((newDP, inputDirection.pointers[1])), newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def switchOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pop the first value of the stack, and turn the codel chooser that many times.
|
||||||
|
:param pointers:
|
||||||
|
:param dataStack:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
ccTurnCount = abs(newStack.pop()) % 2
|
||||||
|
newCC = (inputDirection.pointers[1] + ccTurnCount) % 2
|
||||||
|
return (direction((inputDirection.pointers[0], newCC)), newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def inNOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Add a number from the input. If it isn't a number, nothing is added instead
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
newVal = input("Input number: ")
|
||||||
|
if newVal.isdigit():
|
||||||
|
newStack.append(newVal)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def inCOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Add a numeric representation of a character to the stack.
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
newVal = input("Input character")
|
||||||
|
if len(newVal) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
newStack.append(ord(newVal[0]))
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def outNOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pops the top number from the stack and outputs it as a number
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
print(newStack.pop(), end="")
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def outCOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pops the top number from the stack and outputs it as a number. Does nothing if top value is negative
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
valA = newStack.pop()
|
||||||
|
if valA < 0:
|
||||||
|
newStack.append(valA)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
print(chr(valA), end="")
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def pushOperator(token: lexerTokens.toColorToken, inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pushes the codelsize of the token to the stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
newStack.append(token.codelSize)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def popOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Pops and discards the top number of the stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
newStack.pop()
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def duplicateOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Duplicates the top value of the stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 1:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
val = newStack.pop()
|
||||||
|
newStack.append(val)
|
||||||
|
newStack.append(val)
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
|
||||||
|
def rollOperator(inputDirection: direction, dataStack: List[int]) -> Tuple[direction, List[int]]:
|
||||||
|
"""
|
||||||
|
Rolls the stack x times, to a depth of y, where x is equal to the top value of the stack, and y is equal to the second value of the stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
inputDirection = copy.deepcopy(inputDirection)
|
||||||
|
if len(newStack) < 2:
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
rolls = newStack.pop()
|
||||||
|
depth = newStack.pop()
|
||||||
|
insertIndex = len(newStack) - depth
|
||||||
|
newStack = rollStack(newStack, rolls, insertIndex)
|
||||||
|
|
||||||
|
return (inputDirection, newStack)
|
||||||
|
|
||||||
|
def rollStack(dataStack: List[int], numberOfRolls: int, insertIndex: int) -> List[int]:
|
||||||
|
"""
|
||||||
|
Rolls the stack recursively, and inverted when negative number of rolls
|
||||||
|
:param dataStack: Input stack
|
||||||
|
:param numberOfRolls: Number of rolls
|
||||||
|
:param insertIndex: At which index to either insert new values, or to get values from
|
||||||
|
:return: Rolled data stack
|
||||||
|
"""
|
||||||
|
newStack = dataStack.copy()
|
||||||
|
if numberOfRolls > 0:
|
||||||
|
newStack.insert(insertIndex, newStack.pop())
|
||||||
|
return rollStack(newStack, numberOfRolls - 1, insertIndex)
|
||||||
|
elif numberOfRolls < 0:
|
||||||
|
newStack.append(newStack.pop(insertIndex))
|
||||||
|
return rollStack(newStack, numberOfRolls + 1, insertIndex)
|
||||||
|
else:
|
||||||
|
return newStack
|
45
interpreter/tokens.py
Normal file
45
interpreter/tokens.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
class baseLexerToken():
|
||||||
|
def __init__(self, tokenType: str):
|
||||||
|
self.tokenType = tokenType
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Token type = {}".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 getTokenType(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]
|
24
main.py
Normal file
24
main.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import argparse
|
||||||
|
|
||||||
|
from interpreter import executionFunctions as executionFunctions
|
||||||
|
from interpreter import imageWrapper as imageWrapper
|
||||||
|
from GUI import main as GUIMain
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description='Interprets a piet image')
|
||||||
|
parser.add_argument("-f", "--file", required=True, type=str, help="complete filepath to a .png or .gif image")
|
||||||
|
parser.add_argument("-v", "--verbose", action="store_true", help="Outputs number of steps to STDOUT")
|
||||||
|
parser.add_argument("-g", "--graphical", action="store_true", help="Opens GUI with the file loaded")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not args.graphical:
|
||||||
|
executionFunctions.interpret(imageWrapper.getImage(args.file))
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
print("\nTotal steps: {}".format(executionFunctions.takeStep.counter))
|
||||||
|
else:
|
||||||
|
print("GUI TIME!")
|
||||||
|
app = GUIMain.GUI()
|
||||||
|
app.setFileText(args.file)
|
||||||
|
app.loadFile()
|
||||||
|
app.run()
|
Loading…
x
Reference in New Issue
Block a user