-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
120 lines (92 loc) · 3.66 KB
/
main.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
from src.common.file_utils import get_path, read_lines, read_raw
class TicketReader():
def __init__(self, filename):
self.your_tickets, self.nearby_tickets, self.fields = self.process_input(
filename)
self.error_rate = self.get_error_rate()
self.valid_tickets = self.get_valid_tickets()
def is_valid(self, rule, v):
for (lower, upper) in self.fields[rule]:
if (lower <= v and v <= upper):
return True
return False
def process_input(self, filename):
lines = read_raw(get_path(__file__, filename))
rules_string, your_ticket_string, nearby_ticket_string = lines.split(
"\n\n")
your_tickets = [[int(x) for x in t.split(",")]
for t in your_ticket_string.split("\n")[1:]]
nearby_tickets = [[int(x) for x in t.split(",")]
for t in nearby_ticket_string.split("\n")[1:]]
rules = {}
for rule in rules_string.split("\n"):
name, boundaries = rule.split(": ")
rules[name] = []
for val in boundaries.split("or"):
splitted = val.strip().split("-")
rules[name].append((int(splitted[0]), int(splitted[1])))
return your_tickets[0], nearby_tickets, rules
def get_error_rate(self):
error = 0
for ticket in self.nearby_tickets:
for f in ticket:
valid_field = False
for rule in self.fields:
if self.is_valid(rule, f):
valid_field = True
if not valid_field:
error += f
return error
def get_valid_tickets(self):
valid_nearby_tickets = []
for ticket in self.nearby_tickets:
valid_ticket = True
for f in ticket:
valid_field = False
for rule in self.fields:
if self.is_valid(rule, f):
valid_field = True
if not valid_field:
valid_ticket = False
if valid_ticket:
valid_nearby_tickets.append(ticket)
return [self.your_tickets] + valid_nearby_tickets
def part_one(filename: str) -> int:
ticket_reader = TicketReader(filename)
return ticket_reader.error_rate
def part_two(filename: str) -> int:
ticket_reader = TicketReader(filename)
possible_positions = {}
tickets = ticket_reader.valid_tickets
your_ticket = ticket_reader.your_tickets
for rule in ticket_reader.fields:
possible_positions[rule] = set(
[x for x in range(len(your_ticket))])
for ticket in tickets:
for pos, v in enumerate(ticket):
for rule in possible_positions:
if pos in possible_positions[rule] and not ticket_reader.is_valid(rule, v):
possible_positions[rule].remove(pos)
mapping = {}
while len(possible_positions) > 0:
pos_taken = None
for rule, positions in possible_positions.items():
if len(positions) == 1:
v = list(positions)[0]
mapping[rule] = pos_taken = v
del possible_positions[rule]
break
for rule, positions in possible_positions.items():
positions.remove(pos_taken)
total = 1
for rule, val in mapping.items():
if "departure" in rule:
total *= your_ticket[val]
return total
if __name__ == '__main__':
print("---Part One---")
part_one_res = part_one("input.txt")
print(part_one_res)
print("---Part Two---")
part_two_res = part_two("input.txt")
print(part_two_res)