Skip to content

Commit

Permalink
Solutions days 23, 25 from 2023 (#20)
Browse files Browse the repository at this point in the history
* Solution day 23

* Solve day 25
  • Loading branch information
mkopec87 authored Dec 19, 2024
1 parent 557c0fb commit 3f9585f
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 0 deletions.
137 changes: 137 additions & 0 deletions src/2023/23/2023_23.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import itertools
from typing import Tuple

import networkx as nx
import numpy as np
from tqdm import tqdm

from src.utils.data import load_data
from src.utils.submission import submit_or_print

ROCK = "#"

N = (-1, 0)
S = (1, 0)
W = (0, -1)
E = (0, 1)


def main(debug: bool) -> None:
input_data = load_data(debug)

grid, start, end = parse_grid(input_data)

result_part1 = solve_part1(grid, start, end)
result_part2 = solve_part2(grid, start, end)

submit_or_print(result_part1, result_part2, debug)


def parse_grid(input_data: str) -> Tuple[np.array, Tuple[int, int], Tuple[int, int]]:
rows = []
for line in input_data.strip().splitlines():
rows.append(list(line))

# borders
rows.append(["#" for _ in rows[0]])
rows.insert(0, ["#" for _ in rows[0]])

grid = np.array(rows)

# search for start and end positions
start = 1, [y for y in range(grid.shape[1]) if grid[1, y] == "."][0]
end = (
grid.shape[0] - 2,
[y for y in range(grid.shape[1]) if grid[grid.shape[0] - 2, y] == "."][0],
)

return grid, start, end


def solve_part1(grid: np.array, start: Tuple[int, int], end: Tuple[int, int]) -> int:
graph = create_graph(grid)
return max(map(len, nx.all_simple_paths(graph, start, end))) - 1


def solve_part2(grid: np.array, start: Tuple[int, int], end: Tuple[int, int]) -> int:
graph = create_graph(grid, part2=True)

print("Compressing graph...")
compressed_graph = compress(graph)
print("Initial graph: ", graph)
print("Compressed graph:", compressed_graph)

viz_path = "graph.png"
pos = nx.planar_layout(compressed_graph)
nx.draw(compressed_graph, pos, with_labels=True)
import matplotlib.pyplot as plt

plt.savefig(viz_path)
print(f"Saved compressed graph visualization to: {viz_path}")

print("Searching for longest path in compressed graph...")
return max(
map(
lambda path: nx.path_weight(compressed_graph, path, "weight"),
nx.all_simple_paths(compressed_graph, start, end),
)
)


def create_graph(grid: np.array, part2: bool = False) -> nx.Graph:
graph = nx.Graph() if part2 else nx.DiGraph()
for x, y in np.ndindex(grid.shape):
if grid[x, y] != ROCK:
graph.add_node((x, y))
for x, y in np.ndindex(grid.shape):
p = grid[x, y]
if p != ROCK:
if part2:
p = "."

match p:
case ">":
dirs = [E]
case "<":
dirs = [W]
case "^":
dirs = [N]
case "v":
dirs = [S]
case _:
dirs = [N, S, W, E]

for d in dirs:
n_pos = d[0] + x, d[1] + y
n = grid[n_pos]
if n != ROCK:
graph.add_edge((x, y), n_pos, weight=1)
return graph


def compress(graph: nx.Graph) -> nx.Graph:
crossroads = {node for node in graph.nodes if len(graph.edges(node)) != 2}

compressed_graph = nx.Graph(graph)
for p1, p2 in tqdm(list(itertools.combinations(crossroads, 2))):
# simplified graph without crossroads
graph_copy = nx.Graph(graph)
for c in crossroads:
if c not in {p1, p2}:
graph_copy.remove_node(c)

# find all paths
for path in nx.all_simple_paths(graph_copy, p1, p2):
if len(path) < 3:
continue
weight = len(path) - 1
compressed_graph.add_edge(p1, p2, weight=weight)
for n in path[1:-1]:
compressed_graph.remove_node(n)
return compressed_graph


if __name__ == "__main__":
debug_mode = True
# debug_mode = False
main(debug_mode)
5 changes: 5 additions & 0 deletions src/2023/23/sample_input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#.#######
#>......#
#.###.#.#
#....>..#
#######.#
47 changes: 47 additions & 0 deletions src/2023/25/2023_25.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import math
import re

import matplotlib.pyplot as plt
import networkx as nx

from src.utils.data import load_data
from src.utils.submission import submit_or_print


def main(debug: bool) -> None:
input_data = load_data(debug)

graph = parse_graph(input_data)
print(graph)

viz_path = "graph.png"
pos = nx.spring_layout(graph)
nx.draw(graph, pos, with_labels=True)
plt.savefig(viz_path)
print(f"Saved graph visualization to: {viz_path}")

edges = nx.edge_betweenness_centrality(graph)
top3 = sorted(edges.items(), key=lambda k: k[1], reverse=True)[:3]
for e, _ in top3:
graph.remove_edge(*e)
print(f"Removed 3 key edges: {[t[0] for t in top3]}")

result_part1 = math.prod([len(c) for c in nx.connected_components(graph)])
result_part2 = None

submit_or_print(result_part1, result_part2, debug)


def parse_graph(input_data: str) -> nx.Graph:
graph = nx.Graph()
for line in input_data.strip().splitlines():
nodes = re.findall(r"[a-z]+", line)
for node in nodes[1:]:
graph.add_edge(nodes[0], node)
return graph


if __name__ == "__main__":
debug_mode = True
# debug_mode = False
main(debug_mode)
Binary file added src/2023/25/graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/2023/25/sample_input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
a: b c d e
e: f g h a
f: b g h
h: d g f
b: f c d
d: h b c

0 comments on commit 3f9585f

Please sign in to comment.