diff --git a/challenges/2023/20-pulsePropagation/README.md b/challenges/2023/20-pulsePropagation/README.md new file mode 100644 index 0000000..1882c60 --- /dev/null +++ b/challenges/2023/20-pulsePropagation/README.md @@ -0,0 +1 @@ +# [Day 20: Pulse Propagation](https://adventofcode.com/2023/day/20) diff --git a/challenges/2023/20-pulsePropagation/main.py b/challenges/2023/20-pulsePropagation/main.py new file mode 100644 index 0000000..c1d9d02 --- /dev/null +++ b/challenges/2023/20-pulsePropagation/main.py @@ -0,0 +1,77 @@ +import sys +from collections import namedtuple +from enum import IntEnum + + +Module = namedtuple("Module", ["type", "name", "outputs"]) +Pulse = namedtuple("Pulse", ["from", "to", "value"]) + + +class PulseValue(IntEnum): + LOW = 0 + HIGH = 1 + + +def parse(instr: str) -> dict[str, Module]: + x = {} + + for line in instr.splitlines(): + name, outputs = line.split(" -> ") + module_type = None + if not name[0].isalpha(): + module_type = name[0] + name = name[1:] + else: + module_type = name + + x[name] = Module(module_type, name, outputs.split(", ")) + + return x + + +def tick(modules: dict[str, Module], state: dict[str, any], pulses: list[Pulse]): + next_pulses = [] + + for pulse in pulses: + dest_module = modules[pulse.to] + + match dest_module.type: + case "broadcaster": + for output in dest_module.outputs: + next_pulses.append(Pulse(dest_module.name, output, pulse.value)) + case "%": + if pulse.value == PulseValue.LOW: + toggled = state.get(dest_module.name, False) + next_pulse_val = PulseValue.HIGH if toggled else PulseValue.LOW + for output in dest_module.outputs: + next_pulses.append(Pulse(dest_module.name, output, next_pulse_val)) + state[dest_module.name] = not toggled + case "&": + state[dest_module.name] = state[dest_module.name] + [pulse] + + + +def one(instr: str): + modules = parse(instr) + _debug(modules) + return + + +def two(instr: str): + return + + +def _debug(*args, **kwargs): + kwargs["file"] = sys.stderr + print(*args, **kwargs) + + +if __name__ == "__main__": + if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]: + print("Missing day argument", file=sys.stderr) + sys.exit(1) + inp = sys.stdin.read().strip() + if sys.argv[1] == "1": + print(one(inp)) + else: + print(two(inp)) \ No newline at end of file diff --git a/challenges/2023/20-pulsePropagation/tests.json b/challenges/2023/20-pulsePropagation/tests.json new file mode 100644 index 0000000..f2dd02d --- /dev/null +++ b/challenges/2023/20-pulsePropagation/tests.json @@ -0,0 +1,12 @@ +{ + "1": [ + { + "is": "32000000", + "input": "broadcaster -> a, b, c\n%a -> b\n%b -> c\n%c -> inv\n&inv -> a\n\n" + }, + { + "is": "11687500", + "input": "broadcaster -> a\n%a -> inv, con\n&inv -> b\n%b -> con\n&con -> output\n" + } + ] +} \ No newline at end of file diff --git a/challenges/2023/21-stepCounter/README.md b/challenges/2023/21-stepCounter/README.md new file mode 100644 index 0000000..4c544f2 --- /dev/null +++ b/challenges/2023/21-stepCounter/README.md @@ -0,0 +1 @@ +# [Day 21: Step Counter](https://adventofcode.com/2023/day/21) diff --git a/challenges/2023/21-stepCounter/main.py b/challenges/2023/21-stepCounter/main.py new file mode 100644 index 0000000..925b3f8 --- /dev/null +++ b/challenges/2023/21-stepCounter/main.py @@ -0,0 +1,86 @@ +import sys +import gridutil.grid as gu +import gridutil.coord as cu +from collections.abc import Callable +from functools import reduce + + +def parse(instr: str) -> gu.Grid: + return gu.parse(instr) + + +def find_n_end_points(grid: gu.Grid, start_pos: cu.Coordinate, n_steps: int, infinite: bool = False) -> int: + max_x = gu.get_max_x(grid) + max_y = gu.get_max_y(grid) + + locations = set([start_pos]) + for _ in range(n_steps): + new_locations = set([]) + for loc in locations: + for direction in cu.Direction: + next_pos = cu.add(loc, direction.delta()) + adjusted_next_pos = next_pos + + if infinite: + if not (0 < adjusted_next_pos.x < max_x): + adjusted_next_pos = cu.Coordinate(abs(adjusted_next_pos.x) % (max_x + 1), adjusted_next_pos.y) + + if not (0 < adjusted_next_pos.y < max_y): + adjusted_next_pos = cu.Coordinate(adjusted_next_pos.x, abs(adjusted_next_pos.y) % (max_y + 1)) + + if adjusted_next_pos not in grid or grid[adjusted_next_pos] == "#": + continue + new_locations.add(next_pos) + + locations = new_locations + return len(locations) + + +def find_start_point(grid: gu.Grid) -> cu.Coordinate: + for k in grid: + if grid[k] == "S": + return k + raise ValueError("No start position found") + + +def one(instr: str): + grid = parse(instr) + start_pos = find_start_point(grid) + res = find_n_end_points(grid, start_pos, 64) + return res + + +def two(instr: str): + grid = parse(instr) + start_pos = find_start_point(grid) + + TARGET_STEPS = 26501365 + WIDTH = int(gu.get_max_x(grid)) + 1 + a, b = TARGET_STEPS // WIDTH, TARGET_STEPS % WIDTH + + _debug(WIDTH, a, b) + + r = [] + for i in range(3): + _debug((WIDTH * i) + b) + r.append(find_n_end_points(grid, start_pos, (WIDTH * i) + b, infinite=True)) + + _debug(r) + x, y, z = r + return x+a*(y-z+(a-1)*(z-(2*y)+x)//2) + + +def _debug(*args, **kwargs): + kwargs["file"] = sys.stderr + print(*args, **kwargs) + + +if __name__ == "__main__": + if len(sys.argv) < 2 or sys.argv[1] not in ["1", "2"]: + print("Missing day argument", file=sys.stderr) + sys.exit(1) + inp = sys.stdin.read().strip() + if sys.argv[1] == "1": + print(one(inp)) + else: + print(two(inp)) \ No newline at end of file diff --git a/challenges/2023/21-stepCounter/tests.json b/challenges/2023/21-stepCounter/tests.json new file mode 100644 index 0000000..1764331 --- /dev/null +++ b/challenges/2023/21-stepCounter/tests.json @@ -0,0 +1,8 @@ +{ + "1": [ + { + "is": "16", + "input": "...........\n.....###.#.\n.###.##..#.\n..#.#...#..\n....#.#....\n.##..S####.\n.##..#...#.\n.......##..\n.##.#.####.\n.##..##.##.\n...........\n\n" + } + ] +} \ No newline at end of file