Solution to problem 10 in Python
This commit is contained in:
parent
e6043bf326
commit
8ea219f72a
@ -73,14 +73,15 @@
|
|||||||
# list?
|
# list?
|
||||||
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from typing import Deque
|
from typing import Deque, Tuple
|
||||||
|
|
||||||
with open("files/P10.txt") as f:
|
with open("files/P10.txt") as f:
|
||||||
lengths = [int(num) for num in f.read().strip().split(",")]
|
lengths = [int(num) for num in f.read().strip().split(",")]
|
||||||
|
|
||||||
|
|
||||||
def simulated_hash(circle: Deque[int], sequence: list) -> Deque[int]:
|
def simulated_hash(
|
||||||
curr_pos, skip = 0, 0
|
circle: Deque[int], sequence: list, curr_pos: int, skip: int
|
||||||
|
) -> Tuple[Deque[int], int, int]:
|
||||||
for length in sequence:
|
for length in sequence:
|
||||||
circle.rotate(-curr_pos)
|
circle.rotate(-curr_pos)
|
||||||
# creates a copy of the list
|
# creates a copy of the list
|
||||||
@ -93,16 +94,113 @@ def simulated_hash(circle: Deque[int], sequence: list) -> Deque[int]:
|
|||||||
# move forward the current position
|
# move forward the current position
|
||||||
curr_pos = (curr_pos + length + skip) % 256
|
curr_pos = (curr_pos + length + skip) % 256
|
||||||
skip += 1
|
skip += 1
|
||||||
return circle
|
return circle, curr_pos, skip
|
||||||
|
|
||||||
|
|
||||||
def part_1() -> None:
|
def part_1() -> None:
|
||||||
list_of_numbers = deque(list(range(256)))
|
list_of_numbers = deque(list(range(256)))
|
||||||
simulated_hash_res = simulated_hash(list_of_numbers, lengths)
|
curr_pos, skip = 0, 0
|
||||||
|
simulated_hash_res, *_ = simulated_hash(
|
||||||
|
list_of_numbers, lengths, curr_pos, skip
|
||||||
|
)
|
||||||
res = simulated_hash_res[0] * simulated_hash_res[1]
|
res = simulated_hash_res[0] * simulated_hash_res[1]
|
||||||
|
|
||||||
print(f"The result is {res}")
|
print(f"The result is {res}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Part Two ---
|
||||||
|
|
||||||
|
# The logic you've constructed forms a single round of the Knot Hash algorithm;
|
||||||
|
# running the full thing requires many of these rounds. Some input and output
|
||||||
|
# processing is also required.
|
||||||
|
|
||||||
|
# First, from now on, your input should be taken not as a list of numbers, but
|
||||||
|
# as a string of bytes instead. Unless otherwise specified, convert characters
|
||||||
|
# to bytes using their ASCII codes. This will allow you to handle arbitrary
|
||||||
|
# ASCII strings, and it also ensures that your input lengths are never larger
|
||||||
|
# than 255. For example, if you are given 1,2,3, you should convert it to the
|
||||||
|
# ASCII codes for each character: 49,44,50,44,51.
|
||||||
|
|
||||||
|
# Once you have determined the sequence of lengths to use, add the following
|
||||||
|
# lengths to the end of the sequence: 17, 31, 73, 47, 23. For example, if you
|
||||||
|
# are given 1,2,3, your final sequence of lengths should be 49,44,50,44,51,17,
|
||||||
|
# 31,73,47,23 (the ASCII codes from the input string combined with the standard
|
||||||
|
# length suffix values).
|
||||||
|
|
||||||
|
# Second, instead of merely running one round like you did above, run a total
|
||||||
|
# of 64 rounds, using the same length sequence in each round. The current
|
||||||
|
# position and skip size should be preserved between rounds. For example, if
|
||||||
|
# the previous example was your first round, you would start your second round
|
||||||
|
# with the same length sequence (3, 4, 1, 5, 17, 31, 73, 47, 23, now assuming
|
||||||
|
# they came from ASCII codes and include the suffix), but start with the
|
||||||
|
# previous round's current position (4) and skip size (4).
|
||||||
|
|
||||||
|
# Once the rounds are complete, you will be left with the numbers from 0 to 255
|
||||||
|
# in some order, called the sparse hash. Your next task is to reduce these to a
|
||||||
|
# list of only 16 numbers called the dense hash. To do this, use numeric
|
||||||
|
# bitwise XOR to combine each consecutive block of 16 numbers in the sparse
|
||||||
|
# hash (there are 16 such blocks in a list of 256 numbers). So, the first
|
||||||
|
# element in the dense hash is the first sixteen elements of the sparse hash
|
||||||
|
# XOR'd together, the second element in the dense hash is the second sixteen
|
||||||
|
# elements of the sparse hash XOR'd together, etc.
|
||||||
|
|
||||||
|
# For example, if the first sixteen elements of your sparse hash are as shown
|
||||||
|
# below, and the XOR operator is ^, you would calculate the first output number
|
||||||
|
# like this:
|
||||||
|
|
||||||
|
# 65 ^ 27 ^ 9 ^ 1 ^ 4 ^ 3 ^ 40 ^ 50 ^ 91 ^ 7 ^ 6 ^ 0 ^ 2 ^ 5 ^ 68 ^ 22 = 64
|
||||||
|
|
||||||
|
# Perform this operation on each of the sixteen blocks of sixteen numbers in
|
||||||
|
# your sparse hash to determine the sixteen numbers in your dense hash.
|
||||||
|
|
||||||
|
# Finally, the standard way to represent a Knot Hash is as a single hexadecimal
|
||||||
|
# string; the final output is the dense hash in hexadecimal notation. Because
|
||||||
|
# each number in your dense hash will be between 0 and 255 (inclusive), always
|
||||||
|
# represent each number as two hexadecimal digits (including a leading zero as
|
||||||
|
# necessary). So, if your first three numbers are 64, 7, 255, they correspond
|
||||||
|
# to the hexadecimal numbers 40, 07, ff, and so the first six characters of the
|
||||||
|
# hash would be 4007ff. Because every Knot Hash is sixteen such numbers, the
|
||||||
|
# hexadecimal representation is always 32 hexadecimal digits (0-f) long.
|
||||||
|
|
||||||
|
# Here are some example hashes:
|
||||||
|
|
||||||
|
# The empty string becomes a2582a3a0e66e6e86e3812dcb672a272.
|
||||||
|
# AoC 2017 becomes 33efeb34ea91902bb2f59c9920caa6cd.
|
||||||
|
# 1,2,3 becomes 3efbe78a8d82f29979031a4aa0b16a9d.
|
||||||
|
# 1,2,4 becomes 63960835bcdc130f0b66d7ff4f6a5a8e.
|
||||||
|
|
||||||
|
# Treating your puzzle input as a string of ASCII characters, what is the Knot
|
||||||
|
# Hash of your puzzle input? Ignore any leading or trailing whitespace you
|
||||||
|
# might encounter.
|
||||||
|
|
||||||
|
|
||||||
|
with open("files/P10.txt") as f:
|
||||||
|
ascii_lengths = [ord(c) for c in f.read().strip()]
|
||||||
|
ascii_lengths.extend([17, 31, 73, 47, 23])
|
||||||
|
|
||||||
|
|
||||||
|
def part_2():
|
||||||
|
list_of_numbers = deque(list(range(256)))
|
||||||
|
curr_pos, skip = 0, 0
|
||||||
|
for _ in range(64):
|
||||||
|
list_of_numbers, curr_pos, skip = simulated_hash(
|
||||||
|
list_of_numbers, ascii_lengths, curr_pos, skip
|
||||||
|
)
|
||||||
|
|
||||||
|
sparse = list(list_of_numbers)
|
||||||
|
dense = []
|
||||||
|
|
||||||
|
for block in range(0, 256, 16):
|
||||||
|
hashed = 0
|
||||||
|
group = sparse[block : block + 16]
|
||||||
|
for n in group:
|
||||||
|
hashed ^= n
|
||||||
|
dense.append(hashed)
|
||||||
|
|
||||||
|
res = "".join(f"{n:02x}" for n in dense)
|
||||||
|
print(f"The Knot Hash of the input is {res}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
part_1()
|
part_1()
|
||||||
|
part_2()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user