summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--day15/__init__.py8
-rw-r--r--day15/test_init.py16
-rw-r--r--day16/__init__.py130
-rw-r--r--day16/example.txt1
-rw-r--r--day16/input.txt1
5 files changed, 142 insertions, 14 deletions
diff --git a/day15/__init__.py b/day15/__init__.py
index 38126fc..9eb94d9 100644
--- a/day15/__init__.py
+++ b/day15/__init__.py
@@ -116,17 +116,13 @@ class AssignmentOne(Assignment):
116 example_result = 40 116 example_result = 40
117 117
118class AssignmentTwo(Assignment): 118class AssignmentTwo(Assignment):
119 example_result = 315 119 example_result = 315
120
121 @classmethod
122 def overflow(self, item):
123 return item - 9 if item > 9 else item
124 120
125 @classmethod 121 @classmethod
126 def increase_map(cls, map) -> Map: 122 def increase_map(cls, map) -> Map:
127 return [ 123 return [
128 [ 124 [
129 cls.overflow(item + dx + dy) 125 ((item + dx + dy - 1) % 9) + 1
130 for dx in range(5) 126 for dx in range(5)
131 for item in row 127 for item in row
132 ] 128 ]
diff --git a/day15/test_init.py b/day15/test_init.py
index e5f10b0..e72e0e2 100644
--- a/day15/test_init.py
+++ b/day15/test_init.py
@@ -11,11 +11,9 @@ def test_icrease_map():
11 ] 11 ]
12 12
13 assert AssignmentTwo.increase_map([ 13 assert AssignmentTwo.increase_map([
14 [0], 14 [1],
15 [1] 15 [2]
16 ]) == [ 16 ]) == [
17 [0, 1, 2, 3, 4],
18 [1, 2, 3, 4, 5],
19 [1, 2, 3, 4, 5], 17 [1, 2, 3, 4, 5],
20 [2, 3, 4, 5, 6], 18 [2, 3, 4, 5, 6],
21 [2, 3, 4, 5, 6], 19 [2, 3, 4, 5, 6],
@@ -23,15 +21,17 @@ def test_icrease_map():
23 [3, 4, 5, 6, 7], 21 [3, 4, 5, 6, 7],
24 [4, 5, 6, 7, 8], 22 [4, 5, 6, 7, 8],
25 [4, 5, 6, 7, 8], 23 [4, 5, 6, 7, 8],
26 [5, 6, 7, 8, 9] 24 [5, 6, 7, 8, 9],
25 [5, 6, 7, 8, 9],
26 [6, 7, 8, 9, 1]
27 ] 27 ]
28 28
29 assert AssignmentTwo.increase_map([ 29 assert AssignmentTwo.increase_map([
30 [0, 1], 30 [1, 2],
31 ]) == [ 31 ]) == [
32 [0, 1, 1, 2, 2, 3, 3, 4, 4, 5],
33 [1, 2, 2, 3, 3, 4, 4, 5, 5, 6], 32 [1, 2, 2, 3, 3, 4, 4, 5, 5, 6],
34 [2, 3, 3, 4, 4, 5, 5, 6, 6, 7], 33 [2, 3, 3, 4, 4, 5, 5, 6, 6, 7],
35 [3, 4, 4, 5, 5, 6, 6, 7, 7, 8], 34 [3, 4, 4, 5, 5, 6, 6, 7, 7, 8],
36 [4, 5, 5, 6, 6, 7, 7, 8, 8, 9] 35 [4, 5, 5, 6, 6, 7, 7, 8, 8, 9],
36 [5, 6, 6, 7, 7, 8, 8, 9, 9, 1]
37 ] 37 ]
diff --git a/day16/__init__.py b/day16/__init__.py
new file mode 100644
index 0000000..66c0d36
--- /dev/null
+++ b/day16/__init__.py
@@ -0,0 +1,130 @@
1import math
2from abc import ABC
3from dataclasses import dataclass
4from typing import List, Tuple, Iterator, TypedDict, Dict, Union
5
6from aoc import BaseAssignment
7
8@dataclass
9class Packet:
10 raw: str
11 version: int = None
12 type: int = None
13 length_type = str
14 padding: int = 0
15 payload_length = None
16 payload_start = None
17 payload: Union[int, List['Packet']] = None
18
19 LITERAL = 4
20
21 FIFTEEN = '0'
22 ELEVEN = '1'
23
24 PAYLOAD_LENGTH_TYPE = {
25 FIFTEEN: 15,
26 ELEVEN: 11
27 }
28
29 @classmethod
30 def from_hex(cls, value: str) -> 'Packet':
31 print()
32 print(value)
33 for byte in value:
34 print(byte, bin(int(byte, 16))[2:].rjust(4, '0'))
35
36 bits = ''.join([
37 bin(int(byte, 16))[2:]
38 .rjust(4, '0')
39 for byte
40 in value
41 ])
42
43 return cls(
44 raw=bits
45 )
46
47
48 def __post_init__(self):
49 self.version = int(self.raw[:3], 2)
50 self.type = int(self.raw[3:6], 2)
51
52 match self.type:
53 case self.LITERAL:
54 self.payload = self.parse_literal()
55 case _:
56 self.length_type = self.raw[6]
57 self.payload_start = 8 + self.PAYLOAD_LENGTH_TYPE[self.length_type]
58 self.payload_length = int(self.raw[8:self.payload_start], 2)
59
60 print(self.raw[:3], self.raw[3:6], self.raw[7], self.raw[7:self.payload_start], self.raw[self.payload_start:])
61
62 self.payload = self.parse_operator()
63
64
65 def __len__(self):
66 return len(self.raw) - self.padding
67
68 def pad(self):
69 added_zeroes = 4 - len(self.raw) % 4
70 self.raw += added_zeroes * '0'
71 self.padding = added_zeroes
72
73 def parse_literal(self) -> int:
74 start_index = 6
75
76 end = False
77 bits = []
78
79 while not end:
80 bits.append(self.raw[start_index + 1:start_index + 5])
81 if self.raw[start_index] == '0':
82 end = True
83
84 start_index += 5
85
86 self.raw = self.raw[:start_index]
87 self.pad()
88
89 return int(''.join(bits), 2)
90
91 def parse_operator(self) -> List['Packet']:
92 packets = []
93 payload_end = self.payload_start + self.payload_length
94 payload = self.raw[self.payload_start:payload_end]
95
96 while len(payload) > 0:
97 packets.append(Packet(raw=payload))
98 payload = payload[len(packets[-1]):]
99
100 self.raw = self.raw[:payload_end]
101 self.pad()
102
103 return packets
104
105
106class Assignment(BaseAssignment, ABC):
107 def parse_item(self, item: str) -> Packet:
108 return Packet.from_hex(item)
109
110
111 def read_input(self, example=False) -> Packet:
112 return next(super().read_input(example))
113
114class AssignmentOne(Assignment):
115 example_result = 31
116
117 def version_sum(self, packet: Packet):
118 if packet.type == Packet.LITERAL:
119 return packet.version
120
121 return packet.version + sum(
122 self.version_sum(p)
123 for p in packet.payload
124 )
125
126 def run(self, input: Packet):
127 return self.version_sum(input)
128
129
130
diff --git a/day16/example.txt b/day16/example.txt
new file mode 100644
index 0000000..0d2cbff
--- /dev/null
+++ b/day16/example.txt
@@ -0,0 +1 @@
8A004A801A8002F478
diff --git a/day16/input.txt b/day16/input.txt
new file mode 100644
index 0000000..3c7410e
--- /dev/null
+++ b/day16/input.txt
@@ -0,0 +1 @@
620D49005AD2245800D0C9E72BD279CAFB0016B1FA2B1802DC00D0CC611A47FCE2A4ACE1DD144BFABBFACA002FB2C6F33DFF4A0C0119B169B013005F003720004263644384800087C3B8B51C26B449130802D1A0068A5BD7D49DE793A48B5400D8293B1F95C5A3005257B880F5802A00084C788AD0440010F8490F608CACE034401AB4D0F5802726B3392EE2199628CEA007001884005C92015CC8051800130EC0468A01042803B8300D8E200788018C027890088CE0049006028012AB00342A0060801B2EBE400424933980453EFB2ABB36032274C026E4976001237D964FF736AFB56F254CB84CDF136C1007E7EB42298FE713749F973F7283005656F902A004067CD27CC1C00D9CB5FDD4D0014348010C8331C21710021304638C513006E234308B060094BEB76CE3966AA007C6588A5670DC3754395485007A718A7F149CA2DD3B6E7B777800118E7B59C0ECF5AE5D3B6CB1496BAE53B7ADD78C013C00CD2629BF5371D1D4C537EA6E3A3E95A3E180592AC7246B34032CF92804001A1CCF9BA521782ECBD69A98648BC18025800F8C9C37C827CA7BEFB31EADF0AE801BA42B87935B8EF976194EEC426AAF640168CECAF84BC004AE7D1673A6A600B4AB65802D230D35CF81B803D3775683F3A3860087802132FB32F322C92A4C402524F2DE006E8000854378F710C0010D8F30FE224AE428C015E00D40401987F06E3600021D0CE3EC228DA000574E4C3080182931E936E953B200BF656E15400D3496E4A725B92998027C00A84EEEE6B347D30BE60094E537AA73A1D600B880371AA36C3200043235C4C866C018E4963B7E7AA2B379918C639F1550086064BB148BA499EC731004E1AC966BDBC7646600C080370822AC4C1007E38C428BE0008741689D0ECC01197CF216EA16802D3748FE91B25CAF6D5F11C463004E4FD08FAF381F6004D3232CC93E7715B463F780