Skip to content

Commit 66a8779

Browse files
committed
day20
small edit in template
1 parent fadc7c8 commit 66a8779

File tree

4 files changed

+274
-0
lines changed

4 files changed

+274
-0
lines changed

day00/part1.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def compute(s: str) -> int:
3737
),
3838
)
3939
def test(input_s: str, expected: int) -> None:
40+
print() # newline in test output, helps readability
4041
assert compute(input_s) == expected
4142

4243

day20/__init__.py

Whitespace-only changes.

day20/part1.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import argparse
2+
import os.path
3+
from dataclasses import dataclass
4+
5+
import pytest
6+
7+
from support import timing
8+
9+
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
10+
11+
# NOTE: paste test text here
12+
INPUT_S = '''\
13+
1
14+
2
15+
-3
16+
3
17+
-2
18+
0
19+
4
20+
'''
21+
EXPECTED = 3
22+
23+
24+
@dataclass
25+
class Node:
26+
data: int
27+
next: 'Node' = None
28+
prev: 'Node' = None
29+
30+
def __str__(self):
31+
return str(self.data)
32+
33+
34+
def create_circular_linked_list(numbers):
35+
# create the first node
36+
head = Node(data=numbers[0])
37+
current_node = head
38+
39+
# create the rest of the nodes and link them together
40+
for number in numbers[1:]:
41+
new_node = Node(data=number, prev=current_node)
42+
current_node.next = new_node
43+
current_node = new_node
44+
45+
if number == 0:
46+
NODE_ZERO = new_node # NOTE: keep track of the NODE_ZERO
47+
48+
# link the last node to the first node to create the circular linked list
49+
current_node.next = head
50+
head.prev = current_node
51+
return head, NODE_ZERO
52+
53+
54+
def yield_circular_linked_list(node):
55+
current_node = node
56+
yield current_node
57+
current_node = current_node.next
58+
while current_node != node:
59+
yield current_node
60+
current_node = current_node.next
61+
62+
63+
def print_circular_linked_list(node):
64+
print('-' * 50)
65+
print(', '.join(str(n) for n in yield_circular_linked_list(node)))
66+
67+
68+
def find_nth_node(node, n):
69+
current_node = node
70+
for i in range(n):
71+
current_node = current_node.next
72+
return current_node
73+
74+
75+
def remove_and_insert_nth(node, n):
76+
# remove the node from the list
77+
node.prev.next = node.next
78+
node.next.prev = node.prev
79+
# insert the node n places forward
80+
current_node = node
81+
for i in range(n + 1):
82+
current_node = current_node.next
83+
node.prev = current_node.prev
84+
node.next = current_node
85+
current_node.prev.next = node
86+
current_node.prev = node
87+
88+
89+
def get_shift(n, l):
90+
return n % (l - 1) if n else 0
91+
92+
93+
def compute(s: str) -> int:
94+
# load into dictionary
95+
nums = [int(n) for n in s.splitlines()]
96+
num_len = len(nums)
97+
head, node_zero = create_circular_linked_list(nums)
98+
orig_nodes = list(yield_circular_linked_list(head))
99+
100+
for node in orig_nodes:
101+
# print(f'{node!s}')
102+
shift = get_shift(node.data, num_len)
103+
remove_and_insert_nth(node, shift)
104+
# print_circular_linked_list(node_zero)
105+
106+
return sum((
107+
find_nth_node(node_zero, 1000 % num_len).data,
108+
find_nth_node(node_zero, 2000 % num_len).data,
109+
find_nth_node(node_zero, 3000 % num_len).data,
110+
))
111+
112+
113+
@pytest.mark.parametrize(
114+
('input_s', 'expected'),
115+
(
116+
(INPUT_S, EXPECTED),
117+
),
118+
)
119+
def test(input_s: str, expected: int) -> None:
120+
print() # newline in test output, helps readability
121+
assert compute(input_s) == expected
122+
123+
124+
def main() -> int:
125+
parser = argparse.ArgumentParser()
126+
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
127+
args = parser.parse_args()
128+
129+
with open(args.data_file) as f, timing():
130+
print(compute(f.read()))
131+
132+
return 0
133+
134+
135+
if __name__ == '__main__':
136+
raise SystemExit(main())

day20/part2.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import argparse
2+
import os.path
3+
from dataclasses import dataclass
4+
5+
import pytest
6+
7+
from support import timing
8+
9+
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
10+
11+
# NOTE: paste test text here
12+
INPUT_S = '''\
13+
1
14+
2
15+
-3
16+
3
17+
-2
18+
0
19+
4
20+
'''
21+
EXPECTED = 1623178306
22+
23+
24+
@dataclass
25+
class Node:
26+
data: int
27+
next: 'Node' = None
28+
prev: 'Node' = None
29+
30+
def __str__(self):
31+
return str(self.data)
32+
33+
34+
def create_circular_linked_list(numbers):
35+
# create the first node
36+
head = Node(data=numbers[0])
37+
current_node = head
38+
39+
# create the rest of the nodes and link them together
40+
for number in numbers[1:]:
41+
new_node = Node(data=number, prev=current_node)
42+
current_node.next = new_node
43+
current_node = new_node
44+
45+
if number == 0:
46+
NODE_ZERO = new_node # NOTE: keep track of the NODE_ZERO
47+
48+
# link the last node to the first node to create the circular linked list
49+
current_node.next = head
50+
head.prev = current_node
51+
return head, NODE_ZERO
52+
53+
54+
def yield_circular_linked_list(node):
55+
current_node = node
56+
yield current_node
57+
current_node = current_node.next
58+
while current_node != node:
59+
yield current_node
60+
current_node = current_node.next
61+
62+
63+
def print_circular_linked_list(node):
64+
print('-' * 50)
65+
print(', '.join(str(n) for n in yield_circular_linked_list(node)))
66+
67+
68+
def find_nth_node(node, n):
69+
current_node = node
70+
for i in range(n):
71+
current_node = current_node.next
72+
return current_node
73+
74+
75+
def remove_and_insert_nth(node, n):
76+
# remove the node from the list
77+
node.prev.next = node.next
78+
node.next.prev = node.prev
79+
# insert the node n places forward
80+
current_node = node
81+
for i in range(n + 1):
82+
current_node = current_node.next
83+
node.prev = current_node.prev
84+
node.next = current_node
85+
current_node.prev.next = node
86+
current_node.prev = node
87+
88+
89+
def get_shift(n, l):
90+
return n % (l - 1) if n else 0
91+
92+
93+
def compute(s: str) -> int:
94+
# load into dictionary
95+
nums = [int(n) * 811589153 for n in s.splitlines()]
96+
num_len = len(nums)
97+
head, node_zero = create_circular_linked_list(nums)
98+
orig_nodes = list(yield_circular_linked_list(head))
99+
100+
for _ in range(10):
101+
for node in orig_nodes:
102+
# print(f'{node!s}')
103+
shift = get_shift(node.data, num_len)
104+
remove_and_insert_nth(node, shift)
105+
# print_circular_linked_list(node_zero)
106+
107+
return sum((
108+
find_nth_node(node_zero, 1000 % num_len).data,
109+
find_nth_node(node_zero, 2000 % num_len).data,
110+
find_nth_node(node_zero, 3000 % num_len).data,
111+
))
112+
113+
114+
@pytest.mark.parametrize(
115+
('input_s', 'expected'),
116+
(
117+
(INPUT_S, EXPECTED),
118+
),
119+
)
120+
def test(input_s: str, expected: int) -> None:
121+
print() # newline in test output, helps readability
122+
assert compute(input_s) == expected
123+
124+
125+
def main() -> int:
126+
parser = argparse.ArgumentParser()
127+
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
128+
args = parser.parse_args()
129+
130+
with open(args.data_file) as f, timing():
131+
print(compute(f.read()))
132+
133+
return 0
134+
135+
136+
if __name__ == '__main__':
137+
raise SystemExit(main())

0 commit comments

Comments
 (0)