Added 2017/10 part 1
This commit is contained in:
parent
4cc516a620
commit
adea09622c
@ -29,7 +29,7 @@ if part == 1:
|
||||
|
||||
#########################################
|
||||
# #
|
||||
# not working Part 2 #
|
||||
# Part 2 #
|
||||
# #
|
||||
#########################################
|
||||
if part == 2:
|
||||
|
169
2017/10/10.md
Normal file
169
2017/10/10.md
Normal file
@ -0,0 +1,169 @@
|
||||
## \-\-- Day 10: Knot Hash \-\--
|
||||
|
||||
You come across some programs that are trying to implement a software
|
||||
emulation of a hash based on knot-tying. The hash these programs are
|
||||
implementing isn\'t very strong, but you decide to help them anyway. You
|
||||
make a mental note to remind the Elves later not to [invent their own
|
||||
cryptographic functions]{title="NEW CRYPTOSYSTEM WHO DIS"}.
|
||||
|
||||
This hash function simulates tying a knot in a circle of string with 256
|
||||
marks on it. Based on the input to be hashed, the function repeatedly
|
||||
selects a span of string, brings the ends together, and gives the span a
|
||||
half-twist to reverse the order of the marks within it. After doing this
|
||||
many times, the order of the marks is used to build the resulting hash.
|
||||
|
||||
4--5 pinch 4 5 4 1
|
||||
/ \ 5,0,1 / \/ \ twist / \ / \
|
||||
3 0 --> 3 0 --> 3 X 0
|
||||
\ / \ /\ / \ / \ /
|
||||
2--1 2 1 2 5
|
||||
|
||||
To achieve this, begin with a *list* of numbers from `0` to `255`, a
|
||||
*current position* which begins at `0` (the first element in the list),
|
||||
a *skip size* (which starts at `0`), and a sequence of *lengths* (your
|
||||
puzzle input). Then, for each length:
|
||||
|
||||
- *Reverse* the order of that *length* of elements in the *list*,
|
||||
starting with the element at the *current position*.
|
||||
- *Move* the *current position* forward by that *length* plus the
|
||||
*skip size*.
|
||||
- *Increase* the *skip size* by one.
|
||||
|
||||
The *list* is circular; if the *current position* and the *length* try
|
||||
to reverse elements beyond the end of the list, the operation reverses
|
||||
using as many extra elements as it needs from the front of the list. If
|
||||
the *current position* moves past the end of the list, it wraps around
|
||||
to the front. *Lengths* larger than the size of the *list* are invalid.
|
||||
|
||||
Here\'s an example using a smaller list:
|
||||
|
||||
Suppose we instead only had a circular list containing five elements,
|
||||
`0, 1, 2, 3, 4`, and were given input lengths of `3, 4, 1, 5`.
|
||||
|
||||
- The list begins as `[0] 1 2 3 4` (where square brackets indicate the
|
||||
*current position*).
|
||||
- The first length, `3`, selects `([0] 1 2) 3 4` (where parentheses
|
||||
indicate the sublist to be reversed).
|
||||
- After reversing that section (`0 1 2` into `2 1 0`), we get
|
||||
`([2] 1 0) 3 4`.
|
||||
- Then, the *current position* moves forward by the *length*, `3`,
|
||||
plus the *skip size*, 0: `2 1 0 [3] 4`. Finally, the *skip size*
|
||||
increases to `1`.
|
||||
|
||||
```{=html}
|
||||
<!-- -->
|
||||
```
|
||||
- The second length, `4`, selects a section which wraps:
|
||||
`2 1) 0 ([3] 4`.
|
||||
- The sublist `3 4 2 1` is reversed to form `1 2 4 3`:
|
||||
`4 3) 0 ([1] 2`.
|
||||
- The *current position* moves forward by the *length* plus the *skip
|
||||
size*, a total of `5`, causing it not to move because it wraps
|
||||
around: `4 3 0 [1] 2`. The *skip size* increases to `2`.
|
||||
|
||||
```{=html}
|
||||
<!-- -->
|
||||
```
|
||||
- The third length, `1`, selects a sublist of a single element, and so
|
||||
reversing it has no effect.
|
||||
- The *current position* moves forward by the *length* (`1`) plus the
|
||||
*skip size* (`2`): `4 [3] 0 1 2`. The *skip size* increases to `3`.
|
||||
|
||||
```{=html}
|
||||
<!-- -->
|
||||
```
|
||||
- The fourth length, `5`, selects every element starting with the
|
||||
second: `4) ([3] 0 1 2`. Reversing this sublist (`3 0 1 2 4` into
|
||||
`4 2 1 0 3`) produces: `3) ([4] 2 1 0`.
|
||||
- Finally, the *current position* moves forward by `8`: `3 4 2 1 [0]`.
|
||||
The *skip size* increases to `4`.
|
||||
|
||||
In this example, the first two numbers in the list end up being `3` and
|
||||
`4`; to check the process, you can multiply them together to produce
|
||||
`12`.
|
||||
|
||||
However, you should instead use the standard list size of `256` (with
|
||||
values `0` to `255`) and the sequence of *lengths* in your puzzle input.
|
||||
Once this process is complete, *what is the result of multiplying the
|
||||
first two numbers in the list*?
|
||||
|
||||
Your puzzle answer was `19591`.
|
||||
|
||||
The first half of this puzzle is complete! It provides one gold star: \*
|
||||
|
||||
## \-\-- Part Two \-\-- {#part2}
|
||||
|
||||
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](https://en.wikipedia.org/wiki/ASCII#Printable_characters). 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](https://en.wikipedia.org/wiki/Bitwise_operation#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](https://en.wikipedia.org/wiki/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.
|
||||
|
||||
Answer:
|
||||
|
||||
Although it hasn\'t changed, you can still [get your puzzle
|
||||
input](10/input).
|
49
2017/10/solution.py
Normal file
49
2017/10/solution.py
Normal file
@ -0,0 +1,49 @@
|
||||
#!/bin/python3
|
||||
import sys,re
|
||||
from pprint import pprint
|
||||
|
||||
input_f = 'input'
|
||||
|
||||
def list2int(x):
|
||||
return list(map(int, x))
|
||||
|
||||
part = 1
|
||||
#########################################
|
||||
# #
|
||||
# Part 1 #
|
||||
# #
|
||||
#########################################
|
||||
|
||||
if part == 1:
|
||||
|
||||
size = 256
|
||||
lengths = []
|
||||
skip = 0
|
||||
numbers = []
|
||||
pos = 0
|
||||
for i in range(0,size):
|
||||
numbers.append(i)
|
||||
|
||||
with open(input_f) as file:
|
||||
for line in file:
|
||||
lengths = list2int(line.rsplit()[0].split(','))
|
||||
|
||||
for ldx, length in enumerate(lengths):
|
||||
sub = [numbers[(pos + i) % len(numbers)] for i in range(length)]
|
||||
rev = sub[::-1]
|
||||
|
||||
for i in range(length):
|
||||
numbers[(pos + i) % len(numbers)] = rev[i]
|
||||
|
||||
pos += (length+skip)
|
||||
pos = pos % len(numbers)
|
||||
skip += 1
|
||||
print(numbers[0]*numbers[1])
|
||||
|
||||
#########################################
|
||||
# #
|
||||
# Part 2 #
|
||||
# #
|
||||
#########################################
|
||||
if part == 2:
|
||||
exit()
|
Loading…
Reference in New Issue
Block a user