diff --git a/2024/18/daily.py b/2024/18/daily.py new file mode 100644 index 0000000..4cd05a6 --- /dev/null +++ b/2024/18/daily.py @@ -0,0 +1,109 @@ +import queue + +def parse(input_text): + falling_bytes = [] + falling_bytes_map = {} + + max_x = 0 + may_y = 0 + for line in input_text.strip().split('\n'): + if len(line) == 0: + continue + + x, y = tuple(map(int,line.split(','))) + if x > max_x: + max_x = x + if y > may_y: + may_y = y + + # Starts at zeroth-nanosecond + falling_bytes_map[(x, y)] = len(falling_bytes) + falling_bytes.append((x, y)) + + grid = [] + + for y in range(may_y + 1): + g = [] + for x in range(max_x + 1): + if (x, y) in falling_bytes: + # Starts at zeroth-nanosecond + g.append(falling_bytes.index((x, y))) + else: + g.append(None) + grid.append(g) + + return falling_bytes_map, grid + +def render(grid, time): + for y in range(len(grid)): + for x in range(len(grid[y])): + if grid[y][x] == None: + print('.', end='') + elif grid[y][x] <= time: + print('#', end='') + else: + print('_', end='') + print() + + print() + +def distance(a, b): + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + +def pathfinder(fb_map, time_code, s, e): + best_steps = 99999999 + + candidates = queue.PriorityQueue() + candidates.put((distance(s, e)*3, s, 0)) + visited = {} + + counter = 0 + while not candidates.empty(): + counter += 1 + score, pos, steps = candidates.get() + + if pos in visited: + if visited[pos] > steps: + visited[pos] = steps + else: + continue + else: + visited[pos] = steps + + if pos == e: + if steps < best_steps: + best_steps = steps + continue + + for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: + nx, ny = pos + nx += dx + ny += dy + + # blocked by bounds of grid + if nx < 0 or nx > e[0] or ny < 0 or ny > e[1]: + continue + # blocked by falling block + if (nx, ny) in fb_map and fb_map[(nx, ny)] < time_code: + continue + + # candidates.put((distance((nx, ny), e) + steps, (nx, ny), steps + 1)) + # print(f"Putting: {nx}, {ny}, {steps + 1}") + candidates.put((distance((nx, ny), e)*3 + steps + 1, (nx, ny), steps + 1)) + + print(f"Counter: {counter}") + return best_steps + +def part1(input_text, time_code, s, e): + fb_map, _ = parse(input_text) + return pathfinder(fb_map, time_code, s, e) + +def part2(input_text): + return 0 + +if __name__ == "__main__": + with open(__file__.rsplit('/', 1)[0] + "/input.txt", 'r') as file: + print(part1(file.read(), 1024, (0, 0), (70, 70))) + + with open(__file__.rsplit('/', 1)[0] + "/input.txt", 'r') as file: + print(part2(file.read())) \ No newline at end of file diff --git a/2024/18/daily_test.py b/2024/18/daily_test.py new file mode 100644 index 0000000..5d0e7ca --- /dev/null +++ b/2024/18/daily_test.py @@ -0,0 +1,54 @@ +import pytest +from daily import * + +@pytest.fixture +def sample_data(): + return """ +5,4 +4,2 +4,5 +3,0 +2,1 +6,3 +2,4 +1,5 +0,6 +3,3 +2,6 +5,1 +1,2 +5,5 +2,5 +6,5 +1,4 +0,4 +6,4 +1,1 +6,1 +1,0 +0,5 +1,6 +2,0 +""" + +@pytest.fixture +def parsed_data(sample_data): + return parse(sample_data) + +def test_parse(sample_data): + fb_map, grid= parse(sample_data) + + assert len(fb_map) == 25 + assert fb_map[(5,4)] == 0 + assert fb_map[(2,0)] == 24 + +def test_pathfinder(parsed_data): + fb_map, grid = parsed_data + render(grid, 12) + assert pathfinder(fb_map, 12, (0,0), (6,6)) == 22 + +def test_part1(sample_data): + assert part1(sample_data, 12, (0,0), (6,6)) == 22 + +# def test_part2(sample_data): +# assert part2(sample_data) == 45 \ No newline at end of file