You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
link: /python/string_manipulation # Assuming an internal link for string manipulation
14
-
- name: Looping
15
-
link: /python/looping # Assuming an internal link for looping
16
12
---
17
13
14
+
## Page Navigation
15
+
16
+
-[Problem Intro](#problem-intro)
17
+
-[Part 1](#part-1)
18
+
-[Part 2](#part-2)
19
+
-[Results](#results)
20
+
18
21
## Problem Intro
19
22
20
23
In this Advent of Code puzzle, we are tasked with finding an eight-character password for a security door. The password is generated by repeatedly hashing a combination of a "Door ID" (our puzzle input) and an incrementing integer (nonce). A character is revealed if the hexadecimal representation of the MD5 hash starts with five zeroes.
@@ -24,7 +27,9 @@ For example, if the Door ID is `abc`:
24
27
25
28
Our goal is to find this eight-character password.
26
29
27
-
## Part 1: Simple Password Construction
30
+
## Part 1
31
+
32
+
**Given the actual Door ID, what is the password?**
28
33
29
34
The first part requires us to construct the password by taking the sixth character of each valid hash (those starting with five zeroes) in the order they are found.
30
35
@@ -63,7 +68,9 @@ def main():
63
68
# ...
64
69
```
65
70
66
-
## Part 2: Positional Password Construction
71
+
## Part 2
72
+
73
+
**Given the actual Door ID and a new hashing method, what is the password??**
67
74
68
75
The second part introduces a twist: the password characters are placed at specific positions. The sixth character of a valid hash now indicates the *position* (0-7) in the password, and the seventh character is the actual character to be placed at that position. If a position is already filled, we ignore subsequent attempts to fill it.
logging.debug(f"Found {hash_hex} with data {data}.")
176
+
logging.info(f"{pwd}")
177
+
178
+
nonce +=1
179
+
180
+
181
+
if__name__=="__main__":
182
+
t1 = time.perf_counter()
183
+
main()
184
+
t2 = time.perf_counter()
185
+
print(f"Execution time: {t2 - t1:0.4f} seconds")
186
+
```
112
187
113
-
This puzzle is a straightforward application of MD5 hashing and string manipulation. The core challenge lies in efficiently generating and checking a large number of hashes. Part 2 adds a layer of complexity by introducing positional requirements and the need to handle already-filled positions, making it a good exercise in careful state management during iteration. The `hashlib` module in Python provides a convenient way to perform the necessary cryptographic hashing operations.
188
+
This puzzle is a straightforward application of MD5 hashing and string manipulation. The core challenge lies in efficiently generating and checking a large number of hashes. Part 2 adds a layer of complexity by introducing positional requirements and the need to handle already-filled positions, making it a good exercise in careful state management during iteration. The `hashlib` module in Python provides a convenient way to perform the necessary cryptographic hashing operations.
The year is 2016, and we're helping Santa's communication system. Due to a local electromagnetic anomaly, messages are being corrupted. We receive a series of messages, but each character in the message has been sent many times, and the most frequent character in each position is the correct one.
17
+
We're receiving a garbled message from Santa. It seems to be a simple repetition code, where the same message is sent over and over. Our job is to decode it.
21
18
22
-
Our input consists of a list of corrupted messages, one per line. For example:
19
+
The input data is a series of lines, each representing a received message. For example:
23
20
24
21
```text
25
22
eedadn
@@ -33,26 +30,26 @@ rasrtv
33
30
nssdts
34
31
ntnada
35
32
svetve
36
-
tesnvf
33
+
tesnvt
37
34
vntsnd
38
35
vrdear
39
36
dvrsen
40
37
enarar
41
38
```
42
39
43
-
## Part 1
40
+
To decode the message, we need to find the most common character in each column.
44
41
45
-
**Given the corrupted messages, what is the error-corrected version of the message?**
42
+
## Part 1
46
43
47
-
To solve this, we need to determine the most frequent character in each column of the input data. The problem can be broken down into these steps:
44
+
**Given the recording in your puzzle input, what is the error-corrected version of the message being sent?**
48
45
49
-
1. Read all the lines of the input data.
50
-
2."Transpose" the data so that we can easily access all characters in a given column.
51
-
3.For each column, count the occurrences of each character.
52
-
4.Identify the most frequent character in that column.
53
-
5.Combine these characters to form the error-corrected message.
46
+
My strategy is to:
47
+
1.Read all the lines of the input file.
48
+
2.Transpose the data, so that columns become rows.
49
+
3.For each new "row" (which was a column), find the most common character.
50
+
4.Concatenate these characters to form the message.
54
51
55
-
Here's the core logic from the solution:
52
+
Here's the Python code that implements this:
56
53
57
54
```python
58
55
import logging
@@ -62,28 +59,27 @@ from collections import Counter
most_common ="".join(str(char) for char in most_common_chars)
88
84
89
85
logging.info(f"Part 1 message: {most_common}")
@@ -95,44 +91,40 @@ if __name__ == "__main__":
95
91
print(f"Execution time: {t2 - t1:0.4f} seconds")
96
92
```
97
93
98
-
The key steps here are:
94
+
The key parts of the code are:
99
95
100
-
-`zip(*data)`: This elegant Python idiom is used to transpose the rows and columns. If `data` is a list of strings (each string representing a row), `zip(*data)` treats each string as an iterable and groups the characters at the same index across all strings. The `list()` conversion then turns this into a list of tuples, where each tuple represents a column.
101
-
-`collections.Counter`: For each transposed "column" (which is now a tuple of characters), `Counter` efficiently counts the occurrences of each character.
102
-
-`char_counts.most_common(1)[0][0]`: This retrieves the most common character. `most_common(1)`returns a list of the single most common element and its count (e.g., `[('e', 5)]`). We then access the character itself using `[0][0]`.
96
+
-`zip(*data)`: This is a neat trick to transpose a list of lists (or in this case, a list of strings). The `*` operator unpacks the `data` list, so each string is passed as a separate argument to `zip`. `zip`then aggregates the elements from each of the iterables.
97
+
-`collections.Counter`: This is a specialized dictionary subclass for counting hashable objects. It's perfect for this task.
98
+
-`max(char_counts.items(), key=lambda x: x[1])[0]`: This finds the item in the `Counter` with the highest count. `char_counts.items()`gives us `(character, count)` pairs. The `key=lambda x: x[1]` tells `max` to use the count (the second element of the tuple) for comparison. Finally, `[0]` gets the character from the `(character, count)` tuple.
103
99
104
100
## Part 2
105
101
106
-
**As a second part of the communication system, we also need to find the original message if the communication system uses a modified repetition code where the character that appears *least* frequently in each positionis the correct one.**
102
+
**Now, find the least common character in each position. What is the modified message?**
107
103
108
-
Part 2 is a slight variation of Part 1. Instead of finding the *most* frequent character, we need to find the *least* frequent character in each column. The `collections.Counter` object doesn't have a direct `least_common` method, but we can achieve this by sorting the items by their counts and picking the first one, or by using `min` with a custom key.
104
+
This is a simple modification of Part 1. Instead of finding the `max`character count, we need to find the `min`.
109
105
110
-
Here's how the solution extends to handle Part 2:
106
+
Here's the updated code within the `main` function:
111
107
112
108
```python
113
-
# ... (previous code for reading data and transposing)
least_common ="".join(str(char) for char in least_common_chars)
129
-
most_common ="".join(str(char) for char in most_common_chars)
130
118
131
-
logging.info(f"Part 1 message: {most_common}")
132
119
logging.info(f"Part 2 message: {least_common}")
133
120
```
134
121
135
-
The key change for Part 2 is the line:
136
-
-`least_common_chars.append(min(char_counts.items(), key=lambda x: x[1])[0])`: This finds the character with the minimum count. `char_counts.items()` returns key-value pairs (character, count). The `key=lambda x: x[1]` tells `min()` to compare these pairs based on their second element (the count). We then extract the character (`[0]`) from the resulting `(character, count)` tuple.
122
+
The only change is using `min()` instead of `max()`.
137
123
138
-
This approach efficiently solves both parts of the puzzle by leveraging Python's built-in `zip` function for transposition and `collections.Counter` for frequency analysis.
0 commit comments