summaryrefslogtreecommitdiff
path: root/2020/aoc2020-d16.py
diff options
context:
space:
mode:
authorblenovo <bk@gmail.com>2025-08-02 03:13:50 +0200
committerblenovo <bk@gmail.com>2025-08-02 03:13:50 +0200
commit12f551dbfef138880b29ba6abe4576714ae942cb (patch)
treeb7d3b20f01df625b8f2be552314133ebe6c0d1d1 /2020/aoc2020-d16.py
parent99a7d62c30069a5ffe2210a72c7cf81e76a1f241 (diff)
summer warmup sesh part 2
Diffstat (limited to '2020/aoc2020-d16.py')
-rw-r--r--2020/aoc2020-d16.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/2020/aoc2020-d16.py b/2020/aoc2020-d16.py
new file mode 100644
index 0000000..86cd8eb
--- /dev/null
+++ b/2020/aoc2020-d16.py
@@ -0,0 +1,71 @@
+#advent of code 2020
+#day 16
+#I spent a lot of time fixing its logic during solving
+#so the code was cleaned thorougly after finishing
+#which was a good idea because i was doing it directly after
+#and still have to think for a minute what some lines are actually doing
+#I think there's a way to skip looping over tickets for second time
+#but it would make it unnecessarily convoluted
+#I also tried making understandable variable names way too hard for a puzzle code
+p1 = 0;
+p2 = 1;
+requirements = dict();
+NearbyTickets = [];
+PuzzleInput = open("16.in","r").read().split("\n\n");
+#rules for ticket fields
+for line in PuzzleInput[0].split("\n"):
+ FieldName, FieldValues = line.split(":");
+ FieldValues = [ tuple([int(v) for v in fv.split("-")]) for fv in FieldValues.split(" or ")];
+ requirements[FieldName] = FieldValues;
+#your ticket
+MyTicket = [int(val) for val in PuzzleInput[1].split("\n")[1].split(",")];
+#nearby tickets
+for line in PuzzleInput[2].split("\n")[1:]:
+ if len(line) <= 1: continue;
+ NearbyTickets.append([int(val) for val in line.split(",")]);
+
+GoodTickets = [];
+for ticket in NearbyTickets:
+ ValidTicket = True;
+ for TicketValue in ticket:
+ for FieldValues1, FieldValues2 in requirements.values():
+ test1 = FieldValues1[0] <= TicketValue <= FieldValues1[1];
+ test2 = FieldValues2[0] <= TicketValue <= FieldValues2[1];
+ valid = test1 or test2;
+ if valid: break;
+ if not valid:
+ p1 += TicketValue;
+ ValidTicket = False;
+ if ValidTicket: GoodTickets.append(ticket);
+
+Fields = dict();
+InvalidFields = dict();
+#find for which fields the numbers in tickets are viable for
+#store them in InvalidFields dict
+for ticket in GoodTickets:
+ for ti, TicketValue in enumerate(ticket):
+ for FieldName in requirements:
+ if FieldName in Fields.values(): continue;
+ FieldValues1, FieldValues2 = requirements[FieldName];
+ test1 = FieldValues1[0] <= TicketValue <= FieldValues1[1];
+ test2 = FieldValues2[0] <= TicketValue <= FieldValues2[1];
+ valid = test1 or test2;
+ if not valid:
+ if FieldName not in InvalidFields: InvalidFields[FieldName] = set();
+ InvalidFields[FieldName].add(ti);
+
+#all fields have different number of possible places and its linear
+#that is: field 1 has 19/20 possible assignments, field 2 has 18/20 etc.
+#by sorting it from longest to shortest we make assign the fields in a single loop
+#check which indexes are missing and skip the indexes that have their field assigned
+for FieldName in sorted(InvalidFields, key = lambda f: len(InvalidFields[f]) , reverse=True):
+ FieldIndexes = [FieldIndex for FieldIndex in range(len(requirements)) if FieldIndex not in InvalidFields[FieldName]];
+ FieldIndexes = [FieldIndex for FieldIndex in FieldIndexes if FieldIndex not in Fields]; #trim already assigned fields
+ Fields[FieldIndexes[0]] = FieldName;
+
+for key in Fields:
+ if "departure" in Fields[key]: p2 *= MyTicket[key];
+
+print("part 1 =",p1);
+print("part 2 =",p2);
+