Skip to content

Commit 10a8453

Browse files
committed
Working part two
It was kind of interesting to do a "real" computer problem, but trying to read the instructions was pretty tough. Really it was just a lesson is carefully reading the instructions.
1 parent fe59a67 commit 10a8453

File tree

4 files changed

+93
-16
lines changed

4 files changed

+93
-16
lines changed

2017/10/README.md

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Answers
22

3-
| Part 1 | Part 2 |
4-
|---------|--------|
5-
| `38628` | ` ` |
3+
| Part 1 | Part 2 |
4+
|---------|------------------------------------|
5+
| `38628` | `e1462100a34221a7f0906da15c1c979a` |
66

77
## --- Day 10: Knot Hash ---
88

@@ -47,3 +47,34 @@ Suppose we instead only had a circular list containing five elements, `0, 1, 2,
4747
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`.
4848

4949
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_?
50+
51+
-----------------
52+
53+
## --- Part Two ---
54+
55+
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.
56+
57+
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`.
58+
59+
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).
60+
61+
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`).
62+
63+
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.
64+
65+
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:
66+
67+
65 ^ 27 ^ 9 ^ 1 ^ 4 ^ 3 ^ 40 ^ 50 ^ 91 ^ 7 ^ 6 ^ 0 ^ 2 ^ 5 ^ 68 ^ 22 = 64
68+
69+
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.
70+
71+
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.
72+
73+
Here are some example hashes:
74+
75+
* The empty string becomes `a2582a3a0e66e6e86e3812dcb672a272`.
76+
* `AoC 2017` becomes `33efeb34ea91902bb2f59c9920caa6cd`.
77+
* `1,2,3` becomes `3efbe78a8d82f29979031a4aa0b16a9d`.
78+
* `1,2,4` becomes `63960835bcdc130f0b66d7ff4f6a5a8e`.
79+
80+
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.

2017/10/knot.js

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { range } = require('lodash');
2-
const assert = require('assert')
2+
const assert = require('assert');
33

44
class Knot {
55
constructor(size, current_position = 0, skip = 0) {
@@ -8,23 +8,48 @@ class Knot {
88
this.skip = skip;
99
}
1010

11-
performTwists(twists) {
12-
twists.forEach(twist => {
13-
let indices = range(twist).map(v => (v + this.current_position) % this.string.length);
14-
let points = indices.map(i => this.string[i]);
15-
points.reverse();
16-
indices.forEach((string_i, root_i) => (this.string[string_i] = points[root_i]));
17-
this.current_position =
18-
(this.current_position + twist + this.skip++) % this.string.length;
19-
});
11+
static stringToInputArray(str) {
12+
return str
13+
.split('')
14+
.map(v => v.charCodeAt())
15+
.concat([17, 31, 73, 47, 23]);
16+
}
17+
18+
performTwists(twists, iterations = 1) {
19+
for (let iteration = 0; iteration < iterations; iteration++) {
20+
twists.forEach(twist => {
21+
let indices = range(twist).map(
22+
v => (v + this.current_position) % this.string.length
23+
);
24+
let points = indices.map(i => this.string[i]);
25+
points.reverse();
26+
indices.forEach((string_i, root_i) => (this.string[string_i] = points[root_i]));
27+
this.current_position =
28+
(this.current_position + twist + this.skip++) % this.string.length;
29+
});
30+
}
2031

2132
return this.string;
2233
}
2334

24-
computeAnswer() {
35+
denseHash() {
36+
let hash = [];
37+
for (let i = 0; i < 16; i++) {
38+
let slice = this.string.slice(i * 16, (i + 1) * 16);
39+
hash.push(slice.reduce((a, b) => a ^ b));
40+
}
41+
42+
return hash.map(v => v.toString(16).padStart(2, '0')).join('');
43+
}
44+
45+
partOneAnswer() {
2546
assert.ok(this.string.length >= 2);
2647
return this.string[0] * this.string[1];
2748
}
49+
50+
partTwoAnswer() {
51+
return this.denseHash();
52+
}
2853
}
2954

3055
module.exports = Knot;

2017/10/part-one.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ const assert = require('assert');
66
let sample_knot = new Knot(sampleInput.size);
77
sample_knot.performTwists(sampleInput.twists);
88
assert.deepStrictEqual(sample_knot.string, [3, 4, 2, 1, 0]);
9-
assert.strictEqual(sample_knot.computeAnswer(), 12);
9+
assert.strictEqual(sample_knot.partOneAnswer(), 12);
1010
assert.strictEqual(sample_knot.current_position, 4);
1111

1212
let knot = new Knot(input.size);
1313
knot.performTwists(input.twists);
1414

15-
console.log(knot.computeAnswer());
15+
console.log(knot.partOneAnswer());

2017/10/part-two.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const { inputTwo } = require('./input');
2+
const Knot = require('./knot');
3+
const assert = require('assert');
4+
5+
// Tests
6+
[
7+
{ str: '', hash: 'a2582a3a0e66e6e86e3812dcb672a272' },
8+
{ str: 'AoC 2017', hash: '33efeb34ea91902bb2f59c9920caa6cd' },
9+
{ str: '1,2,3', hash: '3efbe78a8d82f29979031a4aa0b16a9d' },
10+
{ str: '1,2,4', hash: '63960835bcdc130f0b66d7ff4f6a5a8e' },
11+
].forEach(({ str, hash }) => {
12+
let sample_twists = Knot.stringToInputArray(str);
13+
let sample_knot = new Knot(256);
14+
sample_knot.performTwists(sample_twists, 64);
15+
assert.strictEqual(sample_knot.denseHash(), hash);
16+
});
17+
18+
let knot = new Knot(inputTwo.size);
19+
knot.performTwists(inputTwo.twists, 64);
20+
21+
console.log(knot.partTwoAnswer());

0 commit comments

Comments
 (0)