mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-22 12:19:53 +00:00
Add day 10 solution
This commit is contained in:
parent
e608483ef0
commit
2960b6bea6
5 changed files with 124 additions and 0 deletions
2017/day/10
4
2017/day/10/Cargo.lock
generated
Normal file
4
2017/day/10/Cargo.lock
generated
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[[package]]
|
||||||
|
name = "day10"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
6
2017/day/10/Cargo.toml
Normal file
6
2017/day/10/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "day10"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Wesley Moore <wes@wezm.net>"]
|
||||||
|
|
||||||
|
[dependencies]
|
1
2017/day/10/input
Normal file
1
2017/day/10/input
Normal file
|
@ -0,0 +1 @@
|
||||||
|
230,1,2,221,97,252,168,169,57,99,0,254,181,255,235,167
|
43
2017/day/10/problem.txt
Normal file
43
2017/day/10/problem.txt
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
--- 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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?
|
||||||
|
|
70
2017/day/10/src/main.rs
Normal file
70
2017/day/10/src/main.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let mut file = File::open("input").expect("unable to open input file");
|
||||||
|
file.read_to_string(&mut buffer).expect("error reading input");
|
||||||
|
|
||||||
|
let lengths = buffer.split(",")
|
||||||
|
.map(|chr| usize::from_str(chr.trim()).expect("invalid number"))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut hash = KnotHash::new(lengths);
|
||||||
|
println!("{}", hash.hash(0..256));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not sure this struct is actually adding value...
|
||||||
|
struct KnotHash {
|
||||||
|
current_position: usize,
|
||||||
|
skip_size: usize,
|
||||||
|
lengths: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KnotHash {
|
||||||
|
pub fn new(lengths: Vec<usize>) -> Self {
|
||||||
|
KnotHash {
|
||||||
|
current_position: 0,
|
||||||
|
skip_size: 0,
|
||||||
|
lengths: lengths,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&mut self, list: Range<usize>) -> u16 {
|
||||||
|
let mut list: Vec<usize> = list.collect();
|
||||||
|
|
||||||
|
for &length in self.lengths.iter() {
|
||||||
|
self.reverse(list.as_mut_slice(), length);
|
||||||
|
if length <= list.len() {
|
||||||
|
self.current_position = (self.current_position + length + self.skip_size) % list.len();
|
||||||
|
}
|
||||||
|
self.skip_size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list[0] as u16 * list[1] as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reverse(&self, list: &mut [usize], length: usize) {
|
||||||
|
if length == 1 { return };
|
||||||
|
|
||||||
|
let list_len = list.len();
|
||||||
|
|
||||||
|
let mut slice = Vec::new();
|
||||||
|
for i in 0..length {
|
||||||
|
slice.push(list[(self.current_position + length - 1 - i) % list_len]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..length {
|
||||||
|
list[(self.current_position + i) % list_len] = slice[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_knot_hash() {
|
||||||
|
let mut hash = KnotHash::new(vec![3, 4, 1, 5]);
|
||||||
|
assert_eq!(hash.hash(0..5), 12);
|
||||||
|
}
|
Loading…
Reference in a new issue