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 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] # This is the default programState. startPosition = position((0, 0)) pointers = direction((0, 0)) PS = programState(graph[0], startPosition, pointers) result = runProgram(image, PS) # Check if executed step had an error if isinstance(result, BaseException): print( "The following exception occured while executing the next step:\n{}" .format(result)) return [result] return result
def updateEdgesInfo(self, image, inputGraph, programState): edgesInfo = self.builder.get_object('codelEdgesMessage', self.generalInfo) if colors.isBlack(imageWrapper.getPixel(image, programState.position)): edgesInfo.configure( text="Black pixels are no codel, and have no edges") return None codel = imageWrapper.getCodel(image, programState.position) baseString = "Next step will be:\n" graphNode = inputGraph.graph[codel] edge = graphNode.graphNode[programState.direction] baseString += self.getEdgeDescription(edge, programState.direction) baseString += "\nCodel edges are as follows:\n" #Generate pointers edgePointers = list( map(lambda i: direction((i % 4, int(i / 4))), iter(range(8)))) for edgePointer in edgePointers: edge = graphNode.graphNode[edgePointer] baseString += self.getEdgeDescription(edge, edgePointer) edgesInfo.configure(text=baseString)
def flip(inputDirection: direction) -> direction: """ Chooses what part of the general pointer to flip, by DP%2 == CC rule, providing the following flow: (0,0) -> (0,1) (0,1) -> (1,1) (1,1) -> (1,0) (1,0) -> (2,0) (2,0) -> (2,1) (2,1) -> (3,1) (3,1) -> (3,0) (3,0) -> (0,0) :param inputDirection: Original state of the pointers :return: Tuple of ints containing new pointers """ if inputDirection.pointers[0] % 2 == inputDirection.pointers[1]: return direction( (inputDirection.pointers[0], flipCC(inputDirection.pointers[1]))) return direction( (flipDP(inputDirection.pointers[0]), inputDirection.pointers[1]))
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 loadFile(self): fileName = self.builder.get_object('fileNameEntry', self.optionBar).get() if len(fileName) < 1: return None try: tmpImage = imageWrapper.getImage(fileName) except FileNotFoundError: edgeInfo = self.infoManager.builder.get_object('codelEdgesMessage', self.infoManager.generalInfo) edgeInfo.configure(text="The file '{}' could not be found".format(fileName)) return False tmpResult = lexer.graphImage(tmpImage) if len(tmpResult[1]) != 0: edgeInfo = self.infoManager.builder.get_object('codelEdgesMessage', self.infoManager.generalInfo) edgeInfo.configure(text="The following exceptions occured while making the graph:\n{}".format("".join(list(map(lambda x: "\t{}\n".format(x), tmpResult[1]))))) return False self.image = tmpImage self.graph = tmpResult[0] self.programState = programState(self.graph, position((0,0)), direction((0,0))) # Reset previous state self.canvasManager.previousProgramState = None self.canvasManager.programState = None self.update()