def runSimulation(lines, getOldAndNewSeatFcn): grid = com.CartesianGrid(' ') x = 0 y = 0 for line in lines: for char in line.strip(): point = com.Point(x, y, char) grid.addPoint(point) x += 1 x = 0 y -= 1 loops = 0 while True: newGrid = com.CartesianGrid(' ') hadChange = False for y in range(0, -1 * len(lines), -1): for x in range(len(lines[0].strip())): oldSeat, newSeat = getOldAndNewSeatFcn(grid, x, y) newPoint = com.Point(x, y, newSeat) hadChange |= oldSeat != newSeat newGrid.addPoint(newPoint) grid = newGrid if not hadChange: break loops += 1 count = 0 for point in grid.getAllPoints(): if point.data == '#': count += 1 return count
def Part1(lines): x = None y = None tid = None grid = com.CartesianGrid(' ') numBlocks = 0 def outputCallback(output): nonlocal x, y, tid, grid, numBlocks if x is None: x = output elif y is None: y = output elif tid is None: tid = output point = com.Point(x, y, tid) if tid == 2: numBlocks += 1 grid.addPoint(point) x = None y = None tid = None compy = com.intCode(lines[0], printOutput=False, hasOutputCallback=outputCallback) compy.RunIntCodeComputer() print(numBlocks)
def doOrigami(lines: List[str], isPart1): parseFolds = False folds = list() grid = com.CartesianGrid(flipOutput=True) for line in lines: if line.strip() == "": parseFolds = True continue if parseFolds: axis, num = line.strip().split(' ')[2].split('=') folds.append((axis, int(num))) else: x, y = line.strip().split(',') point = com.Point(int(x), int(y), '#') grid.addPoint(point) for axis, lineNum in folds: foldGrid(grid, axis, lineNum) # part 1 is just one fold if isPart1: break if part1: return len(grid.getAllPoints()) else: # Easier to just print out the grid and read it to submit print(grid) return None
def Part1(lines): grid = com.CartesianGrid() currentX = 0 currentY = 0 def outputCallback(output): nonlocal grid, currentX, currentY value = chr(output) if output == 10: currentY += 1 currentX = 0 print('\n', end='') else: currentPoint = com.Point(currentX, currentY, value) grid.addPoint(currentPoint) currentX += 1 print(value, end='') intCode = com.intCode(lines[0], False, hasOutputCallback=outputCallback) intCode.RunIntCodeComputer() total = 0 for point in grid.getAllPoints(): if point.data == '#': up = grid.getPoint(point.x, point.y + 1) if up is not None and up.data == '#': down = grid.getPoint(point.x, point.y - 1) if down is not None and down.data == '#': left = grid.getPoint(point.x - 1, point.y) if left is not None and left.data == '#': right = grid.getPoint(point.x + 1, point.y) if right is not None and right.data == '#': total += (point.x * point.y) print(total)
def Part1(lines): grid = com.CartesianGrid() myShip = waterVessel() shipPoint = com.Point(0, 0, myShip) grid.addPoint(shipPoint) myShip.setPoint(shipPoint) for line in lines: command = line[0] units = int(line[1:].strip()) if command == 'N': myShip.moveNorth(units) elif command == 'E': myShip.moveEast(units) elif command == 'S': myShip.moveSouth(units) elif command == 'W': myShip.moveWest(units) elif command == 'L': # turning left should be the same as moving negative degrees myShip.turn(-units) elif command == 'R': myShip.turn(units) elif command == 'F': myShip.moveForward(units) return shipPoint.ManhattenDistance(com.Point(0, 0, None))
def runSim(lines, part1=True): total = 0 grid = com.CartesianGrid(flipOutput=True) numOctopi = 0 y = 0 steps = 100 if not part1: steps = 10000000 for line in lines: x = 0 for char in line.strip(): point = Point(x, y, int(char)) grid.addPoint(point) numOctopi += 1 x += 1 y += 1 for step in range(steps): alreadyFlashed = set() for point in grid.getAllPoints(lowYFirst=True): if point in alreadyFlashed: continue point.data += 1 if point.data > 9: processFlash(grid, point, alreadyFlashed) total += len(alreadyFlashed) for point in alreadyFlashed: point.data = 0 if not part1 and len(alreadyFlashed) == numOctopi: return step + 1 alreadyFlashed.clear() return total
def Part2(lines): grid = com.CartesianGrid() currentX = 0 currentY = 0 gridFinished = False def outputCallback(output): nonlocal grid, currentX, currentY, gridFinished if not gridFinished: if output > 256: print(output) return value = chr(output) if output == 10: currentY += 1 currentX = 0 print('\n', end='') else: currentPoint = com.Point(currentX, currentY, value) grid.addPoint(currentPoint) currentX += 1 print(value, end='') else: print(output) inputNum = 0 localInputNum = 0 def inputCallback(): nonlocal inputNum, gridFinished, localInputNum value = None #gridFinished = True if inputNum == 0: # main value = toAsciiInts('A,C,A,C,B,B,C,B,C,A\n') elif inputNum == 1: # A value = toAsciiInts('R,12,L,8,R,12\n') elif inputNum == 2: # B value = toAsciiInts('R,8,L,8,R,8,R,4,R,4\n') elif inputNum == 3: # C value = toAsciiInts('R,8,R,6,R,6,R,8\n') elif inputNum == 4: # video value = toAsciiInts('n\n') character = value[localInputNum] if character == 10: inputNum += 1 localInputNum = 0 else: localInputNum += 1 return character stringList = list(lines[0]) stringList[0] = '2' intCode = com.intCode(''.join(stringList), False, needsInputCallback=inputCallback, hasOutputCallback=outputCallback) intCode.RunIntCodeComputer()
def makeBlankGrid(): grid = com.CartesianGrid() for y in range(5): for x in range(5): point = com.Point(x, y, '.') grid.addPoint(point) x += 1 y += 1 x = 0 return grid
def makeCaveGrid(lines): grid = com.CartesianGrid(flipOutput=True) y = 0 for line in lines: x = 0 for char in line.strip(): point = com.Point(x, y, int(char)) grid.addPoint(point) x += 1 y += 1 return grid
def runEnhancementCalcs(lines, numEnhancements): enhancementAlgorithm = None picture = com.CartesianGrid(flipOutput=True) squareSize = 0 y = 0 for line in lines: stripped = line.strip() if stripped == '': continue if enhancementAlgorithm is None: enhancementAlgorithm = stripped continue x = 0 for char in stripped: point = com.Point(x, y, char) picture.addPoint(point) x += 1 y += 1 squareSize = max(squareSize, y) print(picture) extrasToAdd = 1 outsideValue = '.' for i in range(numEnhancements): #print('Before') #print(picture) picture.moveAllPoints(extrasToAdd, extrasToAdd) squareSize += (extrasToAdd * 2) for x in range(squareSize): for extra in range(extrasToAdd): picture.addPoint(com.Point(x, extra, outsideValue)) picture.addPoint(com.Point(extra, x, outsideValue)) picture.addPoint( com.Point(squareSize - (extra + 1), x, outsideValue)) picture.addPoint( com.Point(x, squareSize - (extra + 1), outsideValue)) #print('After Shift') #print(picture) picture = enhance(picture, enhancementAlgorithm, outsideValue) #print('After Enhance') #print(picture) outsideValue = enhancementAlgorithm[0] if i % 2 != 0 and outsideValue == '#': outsideValue = enhancementAlgorithm[-1] print(picture) total = 0 for point in picture.getAllPoints(): if point.data == '#': total += 1 return total
def Part1(lines): grid = com.CartesianGrid(' ') keysAndDoors = {} start = None KEY = 0 DOOR = 1 remainingKeys = set() openSpaces = [] y = 0 openSpaceIdx = 0 for line in lines: x = 0 for char in line.strip(): if char != '#': data = char if char == '.': data = openSpaceIdx openSpaceIdx += 1 point = com.Point(x, y, data) grid.addPoint(point) if char == '@': start = point elif char != '.': charToLower = char.lower() existing = keysAndDoors.get(charToLower) if existing is None: existing = [None, None] keysAndDoors[charToLower] = existing if charToLower == char: existing[KEY] = point remainingKeys.add(point.data) else: existing[DOOR] = point x += 1 y += 1 ownedKeys = set() graph = com.Graph(False, edgeWeightFcn(ownedKeys)) for point in grid.getAllPoints(): graph.add_node(point.data) previouslyHit = set() previouslyHit.add(point) connected = connectedGridElements(grid, point, 0, previouslyHit) for edge in connected: graph.add_edge(point.data, edge[0], edge[1], False) for openSpace in range(openSpaceIdx): graph.remove_node(openSpace) answer, path = findShortest(graph, '@', ownedKeys, remainingKeys, 0) print(answer) print(path) return answer
def Part1(lines): grid = com.CartesianGrid() centralPort = com.Point(0, 0, -1) lineId = 0 smallestDistance = 99999999999 for line in lines: x = 0 y = 0 for split in line.split(','): direction = split[0] length = int(split[1:]) xDelta = 0 yDelta = 0 if direction == 'U': yDelta = length elif direction == 'D': yDelta = -length elif direction == 'R': xDelta = length elif direction == 'L': xDelta = -length if xDelta: newX = x + xDelta for xRange in range(min(x, newX), max(x, newX), 1): point = com.Point(xRange, y, lineId) existingPoint = grid.getPoint(xRange, y) if existingPoint and point.data != existingPoint.data: distance = centralPort.ManhattenDistance(point) if distance > 0 and distance < smallestDistance: smallestDistance = distance closestPoint = point grid.addPoint(point) x = newX if yDelta: newY = y + yDelta for yRange in range(min(y, newY), max(y, newY), 1): point = com.Point(x, yRange, lineId) existingPoint = grid.getPoint(x, yRange) if existingPoint and point.data != existingPoint.data: distance = centralPort.ManhattenDistance(point) if distance > 0 and distance < smallestDistance: smallestDistance = distance closestPoint = point grid.addPoint(point) y = newY lineId = lineId + 1 print('smallest = ' + str(smallestDistance) + ': ' + str(closestPoint.x) + ', ' + str(closestPoint.y))
def Part2(lines): x = None y = None tid = None grid = com.CartesianGrid(' ', cellOutputStrFcn=cellStr) score = 0 ball = None paddle = None def inputCallback(): nonlocal grid, ball, paddle #print(grid) if ball.x == paddle.x: return 0 elif ball.x < paddle.x: return -1 else: return 1 def outputCallback(output): nonlocal x, y, tid, grid, score, ball, paddle if x is None: x = output elif y is None: y = output elif tid is None: tid = output point = com.Point(x, y, tid) if tid > 4 and x == -1 and y == 0: score = tid else: if tid == 4: ball = point elif tid == 3: paddle = point grid.addPoint(point) x = None y = None tid = None compy = com.intCode(lines[0], printOutput=False, hasOutputCallback=outputCallback, needsInputCallback=inputCallback) compy.initialMemory[0] = 2 compy.RunIntCodeComputer() print(score)
def runRobot(line, startingColor): grid = com.CartesianGrid(' ', cellStr) black = 0 white = 1 currentPoint = com.Point(0, 0, startingColor) grid.addPoint(currentPoint) painted = set() needsColorOutput = True up = [0, 1] right = [1, 0] down = [0, -1] left = [-1, 0] directions = [up, right, down, left] facingIdx = 0 def outputCallback(output): nonlocal needsColorOutput, currentPoint, painted, directions, facingIdx if needsColorOutput: currentPoint.data = output painted.add(currentPoint) needsColorOutput = False else: if output == 0: facingIdx -= 1 else: facingIdx += 1 facingIdx %= 4 nextX = currentPoint.x + directions[facingIdx][0] nextY = currentPoint.y + directions[facingIdx][1] currentPoint = grid.getPoint(nextX, nextY) if currentPoint is None: currentPoint = com.Point(nextX, nextY, 0) grid.addPoint(currentPoint) needsColorOutput = True def inputCallback(): nonlocal currentPoint return currentPoint.data intcode = com.intCode(lines[0], printOutput=False, needsInputCallback=inputCallback, hasOutputCallback=outputCallback) intcode.RunIntCodeComputer() return painted, grid
def enhance(picture: com.CartesianGrid, algorithm: str, outsideValue: str): newPicture = com.CartesianGrid(flipOutput=True) for point in picture.getAllPoints(True): lookup = '' pointsToCheck = picture.getAdjacentPoints(point.x, point.y, True, True) pointsToCheck.append(point) pointsToCheck = sorted(pointsToCheck, key=lambda x: (x.y, x.x)) if len(pointsToCheck) != 9: test = 0 for x in pointsToCheck: data = x.data if data is None: data = outsideValue if data == '#': lookup += '1' else: lookup += '0' newValue = algorithm[int(lookup, 2)] newPicture.addPoint(com.Point(point.x, point.y, newValue)) return newPicture
def Part2(lines): grid = com.CartesianGrid() myShip = waterVessel() shipPoint = com.Point(0, 0, myShip) grid.addPoint(shipPoint) myShip.setPoint(shipPoint) waypoint = waterVessel() waypointPoint = com.Point(10, 1, waypoint) grid.addPoint(waypointPoint) waypoint.setPoint(waypointPoint) origin = com.Point(0, 0, None) grid.addPoint(origin) for line in lines: command = line[0] units = int(line[1:].strip()) if command == 'N': waypoint.moveNorth(units) elif command == 'E': waypoint.moveEast(units) elif command == 'S': waypoint.moveSouth(units) elif command == 'W': waypoint.moveWest(units) elif command == 'L': # turning left should be the same as moving negative degrees rotateWaypoint(origin, -units, waypointPoint) elif command == 'R': rotateWaypoint(origin, units, waypointPoint) elif command == 'F': print('ship ' + str(shipPoint.x) + ', ' + str(shipPoint.y)) print('waypoint ' + str(waypointPoint.x) + ', ' + str(waypointPoint.y)) scaledVector = com.util.vector_math( mul, [waypointPoint.x, waypointPoint.y], [units, units]) print('scaledVector ' + str(scaledVector[0]) + ', ' + str(scaledVector[1])) shipPoint.move(*scaledVector) # don't actually need to move the waypoint as it's always relative to the ship print('movedShip ' + str(shipPoint.x) + ', ' + str(shipPoint.y)) return shipPoint.ManhattenDistance(com.Point(0, 0, None))
def Part1(lines): x = 0 y = 4 grid = com.CartesianGrid() for line in lines: for char in line.strip(): point = com.Point(x, y, char) grid.addPoint(point) x += 1 y -= 1 x = 0 minute = 1 states = {} while True: changes = [] for point in grid.getAllPoints(): if newValue(point, grid) != point.data: changes.append(point) for change in changes: if change.data == '#': change.data = '.' else: change.data = '#' print(minute, '\n', grid, sep='') state = tuple(i.data for i in grid.getAllPoints()) foundState = states.get(state) if foundState is not None: break states[state] = True minute += 1 biodiversity = 0 powerOfTwo = 1 for point in grid.getAllPoints(): if point.data == '#': biodiversity += powerOfTwo powerOfTwo *= 2 print(biodiversity)
from typing import List, Optional, Set, Tuple import common as com test = False part1 = False part2 = True puzzle = com.PuzzleWithTests() grid = com.CartesianGrid() def in_target(xMin: int, xMax: int, yMin: int, yMax: int, point: com.Point): return point.x >= xMin and point.x <= xMax and point.y >= yMin and point.y <= yMax def shoot_probe(xMin: int, xMax: int, yMin: int, yMax: int, xVelocity: int, yVelocity: int, currentMaxHeight: Optional[int]): "Returns None if the probe misses the target or doesn't go over the current max height, else max height" global grid position = com.Point(0, 0, None) grid.addPoint(position) previousHeight = 0 maxHeight = 0 # Bail if we overshot in the X direction while (position.x <= xMax): if in_target(xMin, xMax, yMin, yMax, position): if not currentMaxHeight: # Part2 just needs to know if we hit the target return True if maxHeight > currentMaxHeight:
def Part2(lines): grid = com.CartesianGrid() #centralPort = com.Point(0, 0, {-1 : 999999}) lineId = 0 smallestDistance = 99999999999 for line in lines: x = 0 y = 0 steps = 0 for split in line.split(','): direction = split[0] length = int(split[1:]) xDelta = 0 yDelta = 0 if direction == 'U': yDelta = length elif direction == 'D': yDelta = -length elif direction == 'R': xDelta = length elif direction == 'L': xDelta = -length if xDelta: newX = x + xDelta rangeX = None if xDelta > 0: rangeX = range(x, newX, 1) else: rangeX = range(x, newX, -1) for xRange in rangeX: if (xRange != 0 or y != 0): steps = steps + 1 point = com.Point(xRange, y, {lineId: steps}) existingPoint = grid.getPoint(xRange, y) if (xRange != 0 or y != 0 ) and existingPoint and existingPoint.data.get( lineId) is None: distance = existingPoint.data[0] + steps if distance > 0 and distance < smallestDistance: smallestDistance = distance closestPoint = point grid.addPoint(point) x = newX if yDelta: newY = y + yDelta rangeY = None if yDelta > 0: rangeY = range(y, newY, 1) else: rangeY = range(y, newY, -1) for yRange in rangeY: if (x != 0 or yRange != 0): steps = steps + 1 point = com.Point(x, yRange, {lineId: steps}) existingPoint = grid.getPoint(x, yRange) if (x != 0 or yRange != 0 ) and existingPoint and existingPoint.data.get( lineId) is None: distance = existingPoint.data[0] + steps if distance > 0 and distance < smallestDistance: smallestDistance = distance closestPoint = point grid.addPoint(point) y = newY lineId = lineId + 1 #print(grid) print('smallest = ' + str(smallestDistance) + ': ' + str(closestPoint.x) + ', ' + str(closestPoint.y))
def Part2(lines): OPEN = 1 WALL = 0 currentPoint = com.Point(0, 0, OPEN) nextPoint = None north = [0, 1] east = [1, 0] south = [0, -1] west = [-1, 0] directions = [east, north, west, south] directionInputs = [4, 1, 3, 2] facingIdx = 0 turned = False maxSteps = 9999999999999 def outputPoint(point): nonlocal facingIdx, currentPoint if point.data == 0: return '#' elif point == currentPoint: if facingIdx == 0: return '>' elif facingIdx == 1: return '^' elif facingIdx == 2: return '<' elif facingIdx == 3: return 'v' return '.' grid = com.CartesianGrid(' ', outputPoint) grid.addPoint(currentPoint) def inputHandler(): nonlocal grid, currentPoint, OPEN, WALL, north, east, south, west, directions, facingIdx, directionInputs, nextPoint, turned while True: leftIdx = (facingIdx + 1) % 4 newCoords = currentPoint + directions[leftIdx] leftPoint = grid.getPoint(newCoords[0], newCoords[1]) if leftPoint is None: nextPoint = com.Point(newCoords[0], newCoords[1], 99999999) grid.addPoint(nextPoint) #print('left point at ', nextPoint.x, nextPoint.y, ' not visited. Facing', facingIdx) turned = True return directionInputs[leftIdx] elif leftPoint.data >= OPEN: nextPoint = leftPoint facingIdx = leftIdx #print('left point at ', nextPoint.x, nextPoint.y, ' is open. Facing', facingIdx) return directionInputs[leftIdx] # go straight newCoords = currentPoint + directions[facingIdx] forwardPoint = grid.getPoint(newCoords[0], newCoords[1]) if forwardPoint is None: forwardPoint = com.Point(newCoords[0], newCoords[1], 99999999) grid.addPoint(forwardPoint) #print('fwd point at ', nextPoint.x, nextPoint.y, ' is empty. Facing', facingIdx) elif forwardPoint.data == WALL: facingIdx = (facingIdx - 1) % 4 #print('fwd point at ', nextPoint.x, nextPoint.y, ' is Wall. Facing', facingIdx) continue else: pass #print('fwd point at ', nextPoint.x, nextPoint.y, ' is open. Facing', facingIdx) nextPoint = forwardPoint return directionInputs[facingIdx] def outputHandler(output): nonlocal grid, currentPoint, OPEN, WALL, nextPoint, turned, facingIdx, maxSteps localTurned = turned turned = False if output == WALL: nextPoint.data = output #print('Ran into wall at', nextPoint.x, nextPoint.y) elif output == 2: print('Oxygen system at ', nextPoint.x, nextPoint.y, 'with steps', currentPoint.data) for point in grid.getAllPoints(): if point.data > WALL: point.data = 9999999999999999999999999 nextPoint.data = WALL # make it a wall so we don't go back currentPoint = nextPoint maxSteps = 0 return elif output == OPEN: steps = currentPoint.data + 1 if steps < nextPoint.data: nextPoint.data = steps if maxSteps < steps: maxSteps = steps #print('Walked to', nextPoint.x, nextPoint.y, 'with steps', steps) if steps % 20 == 0: print(grid) if localTurned: facingIdx = (facingIdx + 1) % 4 currentPoint = nextPoint compy = com.intCode(lines[0], False, None, inputHandler, outputHandler) compy.RunIntCodeComputer()
north = 'north' south = 'south' east = 'east' west = 'west' inventory = 'inv' def toAsciiInts(string): return [ord(i) for i in string] def printCell(cell): return cell.data[0] grid = com.CartesianGrid(''.rjust(30), printCell) compys = [] pickUpItems = True def inputCallback(gridIdx): global compys, grid, north, south, east, west inputIdx = 0 inputValue = None compy = compys[gridIdx] def internalCallback(): nonlocal inputValue, inputIdx, compy if inputValue is None: if compy[3]: realInput = compy[3].pop()