Solution to problem 10 in Python

This commit is contained in:
David Doblas Jiménez 2022-05-18 18:40:24 +02:00
parent e6043bf326
commit 8ea219f72a

View File

@ -73,14 +73,15 @@
# list?
from collections import deque
from typing import Deque
from typing import Deque, Tuple
with open("files/P10.txt") as f:
lengths = [int(num) for num in f.read().strip().split(",")]
def simulated_hash(circle: Deque[int], sequence: list) -> Deque[int]:
curr_pos, skip = 0, 0
def simulated_hash(
circle: Deque[int], sequence: list, curr_pos: int, skip: int
) -> Tuple[Deque[int], int, int]:
for length in sequence:
circle.rotate(-curr_pos)
# 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
curr_pos = (curr_pos + length + skip) % 256
skip += 1
return circle
return circle, curr_pos, skip
def part_1() -> None:
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]
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__":
part_1()
part_2()