-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day08.py
148 lines (122 loc) · 4.29 KB
/
Day08.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from aocd.models import Puzzle
import os
import time
import math
import itertools
from collections import namedtuple
# Constants
INPUT_FILE = "../input.txt"
Node = namedtuple("Node", ["left", "right"])
def get_input_data(input_file):
"""
Read the input data from the input_file if it exists, or fetch it from the AoC website.
Parameters:
input_file (str): The path to the input file.
Returns:
data (list): The input data, split by newline characters.
"""
try:
cwd = os.path.dirname(os.path.realpath(__file__))
input_file = f"{cwd}/{input_file}"
with open(input_file, "r") as file:
data = file.read().split("\n")
print(f"Using {input_file} for input data.")
except FileNotFoundError:
print(f"Input file {input_file} not found. Fetching data from AoC website.")
puzzle = Puzzle(year=2023, day=8)
data = puzzle.input_data.split("\n")
return data
def parse_input(input_string):
lines = input_string.strip().split("\n")
nodes = {}
for line in lines[2:]: # Skip the first two lines
if " = " in line and ", " in line:
name, rest = line.strip().split(" = ")
left, right = rest.strip("()").split(", ")
nodes[name] = Node(left, right)
return nodes, lines[0]
def navigate2(current_node, instructions, nodes):
sum = 0
while not current_node.endswith("Z"):
i = instructions[sum % len(instructions)]
n = nodes[current_node]
if i == "L":
current_node = n.left
else:
current_node = n.right
print(f"Node: {current_node}")
sum += 1
return sum
def navigate1(current_node, instructions, nodes):
steps = 0
for instruction in itertools.cycle(instructions):
if instruction == "L":
current_node = nodes[current_node].left
else:
current_node = nodes[current_node].right
print(f"Node: {current_node}, step {steps}")
steps += 1
if current_node == "ZZZ":
return steps
# --- Part One ---
# The first part of the problem is to find the number of steps required for a single node
# to reach the node ending with 'Z'. Basically a Camel Navigation Puzzle or Parking Functions.
def part1(data):
nodes, instructions = parse_input(data)
steps = navigate1("AAA", instructions, nodes)
return steps
# --- Part Two ---
# To solve the second part of the problem, you need to modify the navigate function to
# handle multiple current nodes at once and continue until all current nodes end with 'Z'.
# You can use a set to keep track of the current nodes and update this set at each step
# based on the instructions.
# """
def part2(data):
nodes, instructions = parse_input(data)
start_nodes = [node for node in nodes if node.endswith("A")]
steps_for = [navigate2(node, instructions, nodes) for node in start_nodes]
return math.lcm(*steps_for)
if __name__ == "__main__":
test_data1 = """
LLR
AAA = (BBB, BBB)
BBB = (AAA, ZZZ)
ZZZ = (ZZZ, ZZZ)
"""
test_data2 = """
LR
11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
"""
print(test_data1)
part1_answer = part1(test_data1)
print(f"Steps required to reach ZZZ: {part1_answer}")
print(f"Test 1: {part1_answer}")
assert part1_answer == 6
part2_answer = part2(test_data2)
print(f"Test 2: {part2_answer}")
assert part2_answer == 6
# Read input.txt as a string
with open("2023/8/input.txt", "r") as file:
input_string = file.read()
steps = part1(input_string)
print(f"P1 Steps required to reach ZZZ: {steps}")
steps = part2(input_string)
print(f"P2 Steps required to reach ZZZ: {steps}")
# data = read_input_data(INPUT_FILE)
# start_p1 = time.perf_counter()
# part1_answer = part1(data)
# print(f"Part 1 answer: {part1_answer}")
# # puzzle.answer_a = part1_answer
# print(f"Part 1 time: {time.perf_counter() - start_p1:.5f} Sec.")
# start_p2 = time.perf_counter()
# # part2_answer = part2(data)
# # print(f"Part 2 answer: {part2_answer}")
# # puzzle.answer_b = part2_answer
# print(f"Part 2 time: {time.perf_counter() - start_p2} Sec.")