from fraction import * class Direction(object): RIGHT = 0 UP = 1 LEFT = 2 DOWN = 3 class Piece(object): def __init__(self): self.inputDirections = [] self.outputDirections = [] self.flow = Fraction(0, 1) def stringHelper(self, char): string = " " + ("^" if Direction.UP in self.outputDirections else ("v" if Direction.DOWN in self.inputDirections else " ")) + " \n" string += ("<" if Direction.LEFT in self.outputDirections else (">" if Direction.RIGHT in self.inputDirections else " ")) + char + (">" if Direction.RIGHT in self.outputDirections else ("<" if Direction.LEFT in self.inputDirections else " ")) + "\n" string += " " + ("v" if Direction.DOWN in self.outputDirections else ("^" if Direction.UP in self.inputDirections else " ")) + " " return string class Splitter(Piece): def __init__(self, inputDirection, outputDirections): Piece.__init__(self) self.inputDirections = [inputDirection] self.outputDirections = outputDirections def __str__(self): return self.stringHelper("S") class Laser(Piece): def __init__(self, outputDirection): Piece.__init__(self) self.outputDirections = [outputDirection] self.flow = Fraction(1, 1) def __str__(self): return self.stringHelper("L") class Target(Piece): def __init__(self, inputDirection, targetFlow): Piece.__init__(self) self.inputDirections = [inputDirection] self.targetFlow = targetFlow def __str__(self): if self.isPowered(): return self.stringHelper("T") else: return self.stringHelper("t") def isPowered(self): return self.targetFlow == self.flow class LaserBeam(object): def __init__(self, direction): self.direction = direction def __str__(self): if self.direction == Direction.UP or self.direction == Direction.DOWN: return " | \n | \n | " else: return " \n---\n " class Grid(object): WIDTH = 10 def __init__(self): self.cells = [] for row in range(Grid.WIDTH): rowCells = [] for column in range(Grid.WIDTH): rowCells.append(None) self.cells.append(rowCells) def placePieceAt(self, piece, row, column): self.cells[row][column] = piece def __str__(self): string = "-" * (Grid.WIDTH * 3 + 2) + "\n" #string = "" for row in range(Grid.WIDTH): rowStrs = [] for column in range(Grid.WIDTH): piece = self.cells[row][column] if isinstance(piece, Piece) or isinstance(piece, LaserBeam): tempStr = str(piece) else: tempStr = " \n \n " stringLines = tempStr.split("\n") for lineNum in range(len(stringLines)): if lineNum < len(rowStrs): rowStrs[lineNum] += stringLines[lineNum] else: rowStrs.append(stringLines[lineNum]) for rowStrLine in rowStrs: string += "|" + rowStrLine + "|\n" string += "-" * (Grid.WIDTH * 3 + 2) + "\n" return string def step(self, row, column, direction): if direction == Direction.RIGHT: if column < Grid.WIDTH - 1: return (row, column+1) else: return None elif direction == Direction.UP: if row > 0: return (row-1, column) else: return None elif direction == Direction.LEFT: if column > 0: return (row, column-1) else: return None elif direction == Direction.DOWN: if row < Grid.WIDTH - 1: return (row+1, column) else: return None def sendLasers(self): for row in range(Grid.WIDTH): for column in range(Grid.WIDTH): piece = self.cells[row][column] if isinstance(piece, Laser): self.propagateLaser(piece, row, column, piece.flow, piece.outputDirections[0]) def propagateLaser(self, piece, row, column, flow, direction): newLocation = self.step(row, column, direction) while newLocation != None: piece2 = self.cells[newLocation[0]][newLocation[1]] if isinstance(piece2, Piece): if direction in piece2.inputDirections: piece2.flow = flow numOutputDirections = len(piece2.outputDirections) for outputDirection in piece2.outputDirections: self.propagateLaser(piece2, newLocation[0], newLocation[1], Fraction(flow.numerator, flow.denominator * numOutputDirections), outputDirection) return else: ## laser or empty space self.placePieceAt(LaserBeam(direction), newLocation[0], newLocation[1]) newLocation = self.step(newLocation[0], newLocation[1], direction) def didIWin(self): for row in range(Grid.WIDTH): for column in range(Grid.WIDTH): piece = self.cells[row][column] if isinstance(piece, Target): if not piece.isPowered(): return False return True if __name__ == '__main__': s = Splitter(Direction.RIGHT, [Direction.UP, Direction.DOWN]) print s l = Laser(Direction.RIGHT) print l t = Target(Direction.DOWN, Fraction(1, 2)) print t g = Grid() g.placePieceAt(l, 3, 2) g.placePieceAt(s, 3, 8) g.placePieceAt(t, 7, 8) g.sendLasers() print g print g.didIWin()