Compare commits

..

10 Commits

9 changed files with 162 additions and 113 deletions

8
answer_cache.json Normal file
View File

@ -0,0 +1,8 @@
{
"16": {
"1": {
"wrong": [],
"correct": 59522422
}
}
}

View File

@ -1,6 +1,19 @@
from tools.aoc import AOCDay from tools.aoc import AOCDay
def get_fuel(count: int, part2: bool = False):
if not part2:
return count // 3 - 2
else:
fuel_sum = 0
count = count // 3 - 2
while count > 0:
fuel_sum += count
count = count // 3 - 2
return fuel_sum
class Day(AOCDay): class Day(AOCDay):
inputs = [ inputs = [
[ [
@ -18,22 +31,21 @@ class Day(AOCDay):
] ]
] ]
def part1(self): def get_fuel(self, part2: bool = False):
if len(self.input) == 1:
return get_fuel(self.getInput(int), part2)
else:
fuel_sum = 0 fuel_sum = 0
for x in self.getInputListAsType(int): for x in self.getInput(int):
fuel_sum += x // 3 - 2 fuel_sum += get_fuel(x, part2)
return fuel_sum return fuel_sum
def part1(self):
return self.get_fuel()
def part2(self): def part2(self):
fuel_sum = 0 return self.get_fuel(True)
for x in self.getInputListAsType(int):
fuel_add = x // 3 - 2
while fuel_add > 0:
fuel_sum += fuel_add
fuel_add = fuel_add // 3 - 2
return fuel_sum
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -7,7 +7,7 @@ from typing import Any, List
def get_comps(memory: List[int]) -> List[IntCode]: def get_comps(memory: List[int]) -> List[IntCode]:
comps = [] comps = []
for _ in range(5): for _ in range(5):
comps.append(IntCode(memory.copy())) comps.append(IntCode(memory))
return comps return comps
@ -41,7 +41,7 @@ class Day(AOCDay):
comps[i].addInput(input1) comps[i].addInput(input1)
comps[i].addInput(input2) comps[i].addInput(input2)
comps[i].run() comps[i].start()
signal = comps[4].getOutput() signal = comps[4].getOutput()
if signal > max_signal: if signal > max_signal:
@ -54,7 +54,7 @@ class Day(AOCDay):
max_signal = 0 max_signal = 0
phase_settings = [5, 6, 7, 8, 9] phase_settings = [5, 6, 7, 8, 9]
for s in itertools.permutations(phase_settings): for s in itertools.permutations(phase_settings):
comps = get_comps(init_memory.copy()) comps = get_comps(init_memory)
for i, input1 in enumerate(s): for i, input1 in enumerate(s):
if i == 0 and not comps[i].isRunning(): if i == 0 and not comps[i].isRunning():

View File

@ -1,4 +1,5 @@
from tools.aoc import AOCDay from tools.aoc import AOCDay
from tools.aoc_ocr import convert_6
from typing import Any from typing import Any
@ -8,7 +9,7 @@ class Day(AOCDay):
(2806, "input08") (2806, "input08")
], ],
[ [
("see image above", "input08") ("ZBJAB", "input08")
] ]
] ]
@ -57,14 +58,11 @@ class Day(AOCDay):
while layers[z][y][x] == "2": while layers[z][y][x] == "2":
z += 1 z += 1
line += " " if layers[z][y][x] == "0" else "#" line += "." if layers[z][y][x] == "0" else "#"
rows.append(line) rows.append(line)
for x in rows: return convert_6("\n".join(rows))
print(x)
return "see image above"
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,7 +1,7 @@
from intcode import IntCode from intcode import IntCode
from tools.aoc import AOCDay from tools.aoc import AOCDay
from tools.coordinate import Coordinate from tools.coordinate import Coordinate
from tools.grid import Grid, GridTransformation from tools.grid import Grid
from typing import Any from typing import Any
MOVEMENTS = [Coordinate(0, -1), Coordinate(1, 0), Coordinate(0, 1), Coordinate(-1, 0)] MOVEMENTS = [Coordinate(0, -1), Coordinate(1, 0), Coordinate(0, 1), Coordinate(-1, 0)]
@ -13,7 +13,7 @@ class Day(AOCDay):
(2373, "input11") (2373, "input11")
], ],
[ [
("see image above", "input11") ("PCKRLPUK", "input11")
] ]
] ]
@ -24,12 +24,12 @@ class Day(AOCDay):
hull = Grid() hull = Grid()
face = 0 face = 0
pos = Coordinate(0, 0) pos = Coordinate(0, 0)
painted = {} painted = set()
while not comp.isHalted(): while not comp.isHalted():
comp.addInput(hull.isSet(pos)) comp.addInput(int(hull.isSet(pos)))
hull.set(pos, comp.getOutput()) hull.set(pos, comp.getOutput())
painted[pos] = True painted.add(pos)
face += 1 if comp.getOutput() else -1 face += 1 if comp.getOutput() else -1
pos = pos + MOVEMENTS[face % 4] pos = pos + MOVEMENTS[face % 4]
@ -50,15 +50,7 @@ class Day(AOCDay):
face += 1 if comp.getOutput() else -1 face += 1 if comp.getOutput() else -1
pos = pos + MOVEMENTS[face % 4] pos = pos + MOVEMENTS[face % 4]
hull.transform(GridTransformation.ROTATE_RIGHT) return hull.get_aoc_ocr_string(x_shift=1)
hull.transform(GridTransformation.FLIP_HORIZONTALLY)
for x in range(hull.minX, hull.maxX + 1):
for y in range(hull.minY, hull.maxY + 1):
print("#" if hull.isSet(Coordinate(x, y)) else " ", end="")
print()
return "see image above"
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -20,10 +20,20 @@ class Moon:
self.y = y self.y = y
self.z = z self.z = z
def getKineticEnergy(self):
return abs(self.vel_x) + abs(self.vel_y) + abs(self.vel_z)
def getPotentialEnergy(self):
return abs(self.x) + abs(self.y) + abs(self.z)
def getEnergy(self): def getEnergy(self):
potential = abs(self.x) + abs(self.y) + abs(self.z) return self.getPotentialEnergy() * self.getKineticEnergy()
kinetic = abs(self.vel_x) + abs(self.vel_y) + abs(self.vel_z)
return potential * kinetic def __str__(self):
return "x=%3d y=%3d z=%3d" % (self.x, self.y, self.z)
def __repr__(self):
return str(self)
def moveMoons(moons: List[Moon]): def moveMoons(moons: List[Moon]):
@ -50,7 +60,7 @@ class Day(AOCDay):
(12644, "input12") (12644, "input12")
], ],
[ [
# ??? (2772, "test_input12"), (2772, "test_input12"),
(4686774924, "test_input12_2"), (4686774924, "test_input12_2"),
(None, "input12") (None, "input12")
] ]
@ -66,21 +76,20 @@ class Day(AOCDay):
def part2(self) -> Any: def part2(self) -> Any:
moons = [Moon(*map(int, findall(scanline_regex, line)[0])) for line in self.getInput()] moons = [Moon(*map(int, findall(scanline_regex, line)[0])) for line in self.getInput()]
init_moons = [Moon(*map(int, findall(scanline_regex, line)[0])) for line in self.getInput()]
init_moons = moons.copy() vel_0_pos = [0] * len(moons)
vel_0_pos = [0, 0, 0, 0]
moveCounter = 0 moveCounter = 0
#while 0 in vel_0_pos: while 0 in vel_0_pos:
for bla in range(3000):
moveCounter += 1 moveCounter += 1
moveMoons(moons) moveMoons(moons)
for i, m in enumerate(moons): for i, m in enumerate(moons):
if m.x == init_moons[i].x and m.y == init_moons[i].y and m.z == init_moons[i].z and m.vel_x == 0 and m.vel_y == 0 and m.vel_z == 0: if m.x == init_moons[i].x and m.y == init_moons[i].y and m.z == init_moons[i].z:
print(i, moveCounter) # if i == 1:
if (vel_0_pos[i] == 0 or vel_0_pos[i] > moveCounter - vel_0_pos[i]) and m.vel_x == 0 and m.vel_y == 0 and m.vel_z == 0: # print("init pos:", i, "after", moveCounter, "moves =>", m.getPotentialEnergy(), m.getKineticEnergy())
vel_0_pos[i] = moveCounter - vel_0_pos[i] if m.getKineticEnergy() == 0:
print("init state:", i, "after", moveCounter, "moves =>", m.getPotentialEnergy())
vel_0_pos[i] = moveCounter
print(vel_0_pos)
return lcm(*vel_0_pos) return lcm(*vel_0_pos)

View File

@ -1,3 +1,4 @@
from collections import deque
from intcode import IntCode from intcode import IntCode
from tools.aoc import AOCDay from tools.aoc import AOCDay
from tools.coordinate import Coordinate from tools.coordinate import Coordinate
@ -6,58 +7,78 @@ from typing import Any
MOVEMENTS = [Coordinate(0, -1), Coordinate(0, 1), Coordinate(-1, 0), Coordinate(1, 0)] MOVEMENTS = [Coordinate(0, -1), Coordinate(0, 1), Coordinate(-1, 0), Coordinate(1, 0)]
OXYGEN_POS = None
def discover(comp: IntCode, grid: Grid, pos: Coordinate, visited: set = None) -> Grid:
global OXYGEN_POS
if visited is None:
visited = set()
visited.add(pos)
for m in range(4):
next_pos = pos + MOVEMENTS[m]
if next_pos in visited:
continue
comp.addInput(m + 1)
outcome = comp.getOutput()
if outcome == 0:
grid.set(next_pos)
else:
if outcome == 2:
OXYGEN_POS = next_pos
grid = discover(comp, grid, next_pos, visited)
comp.addInput(MOVEMENTS.index(MOVEMENTS[m].reverse()) + 1)
comp.getOutput() # just ignore one to keep the queue clear
return grid
class Day(AOCDay): class Day(AOCDay):
inputs = [ inputs = [
[ [
(None, "input15") (354, "input15")
], ],
[ [
(None, "input15") (370, "input15")
] ]
] ]
def part1(self) -> Any: def get_grid(self) -> Grid:
comp = IntCode(self.getInputAsArraySplit(",", int)) comp = IntCode(self.getInputAsArraySplit(",", int))
comp.start() comp.start()
pos = Coordinate(0, 0) pos = Coordinate(0, 0)
ox_pos = None grid = discover(comp, Grid(), pos)
area = Grid() comp.stop()
while ox_pos is None: return grid
madeMove = Coordinate(0, 0)
for i, move in enumerate(MOVEMENTS):
if not area.isSet(pos + move):
print("Trying to move to", pos + move)
comp.addInput(i + 1)
madeMove = move
break
reply = comp.getOutput()
print("comp replied with", reply)
if reply == 0:
area.set(pos + madeMove)
elif reply == 1:
pos += madeMove
else:
ox_pos = pos + madeMove
for y in range(area.minY, area.maxY + 1):
for x in range(area.minX, area.maxX + 1):
if area.isSet(Coordinate(x, y)):
print("#", end="")
else:
print(" ", end="")
print()
print("Oxygen System found at", ox_pos)
def part1(self) -> Any:
return len(self.get_grid().getPath(Coordinate(0, 0), OXYGEN_POS, includeDiagonal=False, walls=[True])) - 1
def part2(self) -> Any: def part2(self) -> Any:
return "" grid = self.get_grid()
queue = deque()
queue.append(OXYGEN_POS)
grid.set(OXYGEN_POS, 2)
count = 0
while queue:
count += 1
next_queue = deque()
for pos in queue:
for next_pos in grid.getNeighboursOf(pos, includeDefault=True, includeDiagonal=False):
if grid.get(next_pos) is False:
next_queue.append(next_pos)
grid.set(next_pos, 2)
queue = next_queue
return count - 1
if __name__ == '__main__': if __name__ == '__main__':
day = Day(15) day = Day(2019, 15)
day.run(verbose=True) day.run(verbose=True)

View File

@ -1,35 +1,33 @@
import threading import threading
from collections import defaultdict
from queue import Queue, Empty
from enum import Enum from enum import Enum
from queue import Queue from typing import List
from typing import List, Union
class IntCodeState(Enum): class IntCodeState(Enum):
INITIALIZED = 0 INITIALIZED = 0
RUNNING = 1 RUNNING = 1
HALTED = 2 HALTED = 2
STOPPED = 3
class IntCode(threading.Thread): class IntCode(threading.Thread):
def __init__(self, memory: List[int]): def __init__(self, memory: List[int]):
super().__init__() super().__init__()
self.instr_ptr = 0 self.instr_ptr = 0
self.memory = memory self.memory = defaultdict(int)
for i, v in enumerate(memory):
self.memory[i] = v
self.input_queue = Queue() self.input_queue = Queue()
self.output_queue = Queue() self.output_queue = Queue()
self.state = IntCodeState.INITIALIZED self.state = IntCodeState.INITIALIZED
self.relative_base = 0 self.relative_base = 0
def getMemoryValue(self, address: int) -> int: def getMemoryValue(self, address: int) -> int:
if address > len(self.memory) - 1: return int(self.memory[address])
self.memory.extend([0] * (address - len(self.memory) + 1))
return self.memory[address]
def setMemoryValue(self, address: int, value: int): def setMemoryValue(self, address: int, value: int):
if address > len(self.memory) - 1:
self.memory.extend([0] * (address - len(self.memory) + 1))
self.memory[address] = value self.memory[address] = value
def getParameterValue(self, address: int, mode: int = 0) -> int: def getParameterValue(self, address: int, mode: int = 0) -> int:
@ -52,30 +50,42 @@ class IntCode(threading.Thread):
def isHalted(self): def isHalted(self):
return self.state == IntCodeState.HALTED return self.state == IntCodeState.HALTED
def sendOutputTo(self, target_queue: Queue): def isStopped(self):
self.output_queue = target_queue return self.state == IntCodeState.STOPPED
def _get_from_queue(self, queue: Queue, count: int = 1, timeout: int = 3) -> int | List[int] | None:
try:
if count == 1:
return queue.get(timeout=timeout)
else:
return [queue.get(timeout=timeout) for _ in range(count)]
except Empty as e:
if self.state == IntCodeState.STOPPED:
return None
else:
raise e
def addInput(self, value: int): def addInput(self, value: int):
self.input_queue.put(value) self.input_queue.put(value)
def addOutput(self, value: int):
self.output_queue.put(value)
def hasOutput(self): def hasOutput(self):
return self.output_queue.qsize() > 0 return self.output_queue.qsize() > 0
def getOutput(self, count: int = 1, block: bool = True, timeout: int = None) -> Union[int, List[int]]: def getOutput(self, count: int = 1, timeout: int = 3) -> int | List[int] | None:
if count == 1: return self._get_from_queue(self.output_queue, count, timeout)
res = self.output_queue.get(block=block, timeout=timeout)
self.output_queue.task_done()
else:
res = []
for _ in range(count):
res.append(self.output_queue.get(block=block, timeout=timeout))
self.output_queue.task_done()
return res def getInput(self, count: int = 1, timeout: int = 3) -> int | List[int] | None:
return self._get_from_queue(self.input_queue, count, timeout)
def stop(self):
self.state = IntCodeState.STOPPED
def run(self): def run(self):
self.state = IntCodeState.RUNNING self.state = IntCodeState.RUNNING
while not self.isHalted(): while not self.isHalted() and not self.isStopped():
instr = self.getMemoryValue(self.instr_ptr) instr = self.getMemoryValue(self.instr_ptr)
op_code = instr % 100 op_code = instr % 100
p1_mode = instr // 100 % 10 p1_mode = instr // 100 % 10
@ -96,11 +106,10 @@ class IntCode(threading.Thread):
self.instr_ptr += 4 self.instr_ptr += 4
elif op_code == 3: # input elif op_code == 3: # input
target_addr = self.getTargetAddress(self.instr_ptr + 1, p1_mode) target_addr = self.getTargetAddress(self.instr_ptr + 1, p1_mode)
self.setMemoryValue(target_addr, self.input_queue.get(timeout=30)) self.setMemoryValue(target_addr, self.getInput())
self.input_queue.task_done()
self.instr_ptr += 2 self.instr_ptr += 2
elif op_code == 4: # output elif op_code == 4: # output
self.output_queue.put(self.getParameterValue(self.instr_ptr + 1, p1_mode)) self.addOutput(self.getParameterValue(self.instr_ptr + 1, p1_mode))
self.instr_ptr += 2 self.instr_ptr += 2
elif op_code == 5: # jump-if-true elif op_code == 5: # jump-if-true
if self.getParameterValue(self.instr_ptr + 1, p1_mode) != 0: if self.getParameterValue(self.instr_ptr + 1, p1_mode) != 0:

View File

@ -10,8 +10,8 @@ import webbrowser
YEAR = 2019 YEAR = 2019
CHARMS = { CHARMS = {
'Linux': '/usr/local/bin/charm', 'Linux': '~/bin/charm',
'Windows': r'C:\somewhere\pycharm64.exe' 'Windows': r'C:\Program Files\JetBrains\PyCharm 2020.2.4\bin\pycharm64.exe'
} }
arg_parser = ArgumentParser() arg_parser = ArgumentParser()