-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday3.py
152 lines (120 loc) · 3.97 KB
/
day3.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
149
150
151
152
"""Solution for Advent of Code day 3."""
from pathlib import Path
import doctest
from typing import Iterable, Iterator
import click
def read_as_int_list(filename: Path) -> Iterator[list[int]]:
"""Read file as interger list.
Read file line by line and convert each line into a list of intergers.
Args:
filename (Path): path to the input file.
Yields:
int: The next line as list of intergers.
Examples:
>>> next(read_as_int_list(Path("test_data/day_3.data")))
[0, 0, 1, 0, 0]
"""
with filename.open("r") as file:
for line in file:
data = [int(char) for char in line.strip()]
yield data
def bitwise_most_common_bit(input_iter: Iterable) -> list[int]:
"""Calculate the most common bit for each position.
The elements are binaries reperesentet in a list of intergers.
Each element must have the same length.
WARNING: The input does not undergo a sanity check.
Args:
input_iter (Iterable): Iterable with lists of intergers representing a binary
Returns:
(list[int]) Most common bit for each position. If both 0
Examples:
>>> int_list_to_bin([0, 1])
1
>>> int_list_to_bin([1, 0, 1, 0, 1, 0, 1])
85
>>> int_list_to_bin([2, 5, 7])
25
>>> int_list_to_bin([])
0
"""
counter = next(input_iter)
num_lines = 1
for element in input_iter:
counter = [x + y for x, y in zip(counter, element)]
num_lines = num_lines + 1
return [int(x >= num_lines / 2) for x in counter]
def int_list_to_bin(int_list: list[int]) -> int:
"""Interpret a list of integers as a binary.
WARNING: The input does not undergo a sanity check.
Args:
int_list (list[int]): List of integer representing a binary.
Returns:
(int) Binary as integer.
Examples:
>>> int_list_to_bin([0])
0
>>> int_list_to_bin([0, 1])
1
>>> int_list_to_bin([1, 0, 1, 0, 1, 0, 1])
85
>>> int_list_to_bin([2, 5, 7])
25
>>> int_list_to_bin([])
0
"""
return sum(c << i for i, c in enumerate(reversed(int_list)))
@click.group()
def main():
"""CLI for the solution of day 3
Advent of code 2021 (https://adventofcode.com/2021/day/3)
"""
@main.command()
@click.argument(
"filename",
required=False,
type=Path,
default=Path("test_data/day_3.data"),
)
def part_1(filename: Path):
"""Part one of day three. (power consumption)"""
gamma_rate = bitwise_most_common_bit(read_as_int_list(filename))
epsilon_rate = [int(not x) for x in gamma_rate]
gamma_rate = int_list_to_bin(gamma_rate)
epsilon_rate = int_list_to_bin(epsilon_rate)
print(f"power consumption of submarine: {gamma_rate * epsilon_rate}")
@main.command()
@click.argument(
"filename",
required=False,
type=Path,
default=Path("test_data/day_3.data"),
)
def part_2(filename: Path):
"""Part two of day three. (life support rating)"""
oxy_remainders = list(read_as_int_list(filename))
co2_remainders = oxy_remainders
counter = 0
while len(oxy_remainders) > 1:
criteria = bitwise_most_common_bit(iter(oxy_remainders))[counter]
oxy_remainders = [
element for element in oxy_remainders if element[counter] == criteria
]
counter = counter + 1
counter = 0
while len(co2_remainders) > 1:
criteria = bitwise_most_common_bit(iter(co2_remainders))[counter]
co2_remainders = [
element for element in co2_remainders if element[counter] != criteria
]
counter = counter + 1
oxygen_generator_rating = int_list_to_bin(oxy_remainders[0])
co2_scrubber_rating = int_list_to_bin(co2_remainders[0])
print(
f"life support rating of the submarine: {oxygen_generator_rating * co2_scrubber_rating}"
)
@main.command()
def test():
"""run doctest."""
print(doctest.testmod())
if __name__ == "__main__":
main()