mirror of
https://github.com/Smaug123/advent-of-code-2017
synced 2025-10-05 03:28:40 +00:00
Day 14
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -199,6 +199,14 @@ version = "0.1.0"
|
||||
name = "day_13"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "day_14"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"day_10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day_15"
|
||||
version = "0.1.0"
|
||||
|
@@ -13,6 +13,7 @@ members = [
|
||||
"day_11",
|
||||
"day_12",
|
||||
"day_13",
|
||||
"day_14",
|
||||
"day_15",
|
||||
"day_16",
|
||||
"day_17",
|
||||
|
@@ -69,28 +69,31 @@ pub mod day_10 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn knot_hash_unsalted(bytes: &[u8]) -> String {
|
||||
pub fn knot_hash_unsalted(bytes: &[u8]) -> Vec<u8> {
|
||||
let mut state = new_state(256);
|
||||
for _ in 0..64 {
|
||||
execute_round(&mut state, &bytes);
|
||||
}
|
||||
let dense = densify(&state.v);
|
||||
let mut answer = vec![0u8; 2 * dense.len()];
|
||||
for (i, b) in dense.iter().enumerate() {
|
||||
densify(&state.v)
|
||||
}
|
||||
|
||||
pub fn knot_hash(bytes: &[u8]) -> Vec<u8> {
|
||||
let mut copy: Vec<u8> = bytes.to_vec();
|
||||
copy.extend(vec![17, 31, 73, 47, 23]);
|
||||
knot_hash_unsalted(©)
|
||||
}
|
||||
|
||||
pub fn to_hex_str(bytes: &[u8]) -> String {
|
||||
let mut answer = vec![0u8; 2 * bytes.len()];
|
||||
for (i, b) in bytes.iter().enumerate() {
|
||||
answer[2 * i] = to_hex(b / 16);
|
||||
answer[2 * i + 1] = to_hex(b % 16);
|
||||
}
|
||||
String::from_utf8(answer).unwrap()
|
||||
}
|
||||
|
||||
pub fn knot_hash(bytes: &[u8]) -> String {
|
||||
let mut copy: Vec<u8> = bytes.to_vec();
|
||||
copy.extend(vec![17, 31, 73, 47, 23]);
|
||||
knot_hash_unsalted(©)
|
||||
}
|
||||
|
||||
pub fn part_2(input: &[u8]) -> String {
|
||||
knot_hash(input)
|
||||
to_hex_str(&knot_hash(input))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,17 +112,20 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(knot_hash("".as_bytes()), "a2582a3a0e66e6e86e3812dcb672a272");
|
||||
assert_eq!(
|
||||
knot_hash("AoC 2017".as_bytes()),
|
||||
to_hex_str(&knot_hash("".as_bytes())),
|
||||
"a2582a3a0e66e6e86e3812dcb672a272"
|
||||
);
|
||||
assert_eq!(
|
||||
to_hex_str(&knot_hash("AoC 2017".as_bytes())),
|
||||
"33efeb34ea91902bb2f59c9920caa6cd"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,3".as_bytes()),
|
||||
to_hex_str(&knot_hash("1,2,3".as_bytes())),
|
||||
"3efbe78a8d82f29979031a4aa0b16a9d"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,4".as_bytes()),
|
||||
to_hex_str(&knot_hash("1,2,4".as_bytes())),
|
||||
"63960835bcdc130f0b66d7ff4f6a5a8e"
|
||||
);
|
||||
}
|
||||
|
17
day_14/Cargo.toml
Normal file
17
day_14/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "day_14"
|
||||
version = "0.1.0"
|
||||
authors = ["Smaug123 <patrick+github@patrickstevens.co.uk>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
day_10 = { path = "../day_10" }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "day_14"
|
||||
harness = false
|
24
day_14/benches/day_14.rs
Normal file
24
day_14/benches/day_14.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use day_14::day_14::{input, part_1, part_1_longhand, part_2};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let input = input();
|
||||
c.bench_function("day 14 part 1", |b| {
|
||||
b.iter(|| {
|
||||
part_1(&input);
|
||||
})
|
||||
});
|
||||
c.bench_function("day 14 part 1 longhand", |b| {
|
||||
b.iter(|| {
|
||||
part_1_longhand(&input);
|
||||
})
|
||||
});
|
||||
c.bench_function("day 14 part 2", |b| {
|
||||
b.iter(|| {
|
||||
part_2(&input);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
1
day_14/input.txt
Normal file
1
day_14/input.txt
Normal file
@@ -0,0 +1 @@
|
||||
ffayrhll
|
207
day_14/src/lib.rs
Normal file
207
day_14/src/lib.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
pub mod day_14 {
|
||||
|
||||
use day_10::day_10::knot_hash;
|
||||
|
||||
pub fn input() -> &'static str {
|
||||
include_str!("../input.txt").trim()
|
||||
}
|
||||
|
||||
fn count_ones(i: u8) -> u8 {
|
||||
let mut i = i;
|
||||
let mut ans = 0;
|
||||
while i > 0 {
|
||||
if i % 2 == 1 {
|
||||
ans += 1;
|
||||
}
|
||||
i /= 2;
|
||||
}
|
||||
ans
|
||||
}
|
||||
|
||||
pub fn part_1_longhand(key: &str) -> u32 {
|
||||
let mut buffer: Vec<u8> = key.chars().map(|i| i as u8).collect();
|
||||
buffer.extend(&[b'-', b'0']);
|
||||
let len = buffer.len();
|
||||
|
||||
let mut count = 0u32;
|
||||
|
||||
for i in 0u8..=9 {
|
||||
buffer[len - 1] = i + b'0';
|
||||
let hash = knot_hash(&buffer);
|
||||
count += hash
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| count_ones(i) as u32)
|
||||
.sum::<u32>();
|
||||
}
|
||||
|
||||
buffer.push(0);
|
||||
for i in 1u8..=9 {
|
||||
buffer[len - 1] = i + b'0';
|
||||
for j in 0u8..=9 {
|
||||
buffer[len] = j + b'0';
|
||||
count += knot_hash(&buffer)
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| count_ones(i) as u32)
|
||||
.sum::<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
buffer.push(0);
|
||||
buffer[len - 1] = b'1';
|
||||
for i in 0u8..=2 {
|
||||
buffer[len] = i + b'0';
|
||||
for j in 0u8..=(if i == 2 { 7 } else { 9 }) {
|
||||
buffer[len + 1] = j + b'0';
|
||||
count += knot_hash(&buffer)
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|i| count_ones(i) as u32)
|
||||
.sum::<u32>();
|
||||
}
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
fn value_at<T>(i: &[T], width: usize, row: usize, col: usize) -> &T {
|
||||
&i[row * width + col]
|
||||
}
|
||||
|
||||
fn set_value_at<T>(i: &mut [T], width: usize, row: usize, col: usize, value: T) {
|
||||
i[row * width + col] = value;
|
||||
}
|
||||
|
||||
fn flood_fill(i: &mut [u32], width: usize, value: u32, row: usize, col: usize) {
|
||||
let current = *value_at(i, width, row, col);
|
||||
if current != 1 {
|
||||
return;
|
||||
}
|
||||
set_value_at(i, width, row, col, value);
|
||||
if row < (i.len() / width) - 1 {
|
||||
flood_fill(i, width, value, row + 1, col);
|
||||
}
|
||||
if row > 0 {
|
||||
flood_fill(i, width, value, row - 1, col);
|
||||
}
|
||||
if col > 0 {
|
||||
flood_fill(i, width, value, row, col - 1);
|
||||
}
|
||||
if col < width - 1 {
|
||||
flood_fill(i, width, value, row, col + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn count_contiguous(mut i: Vec<u32>, width: usize) -> u32 {
|
||||
// 0 means empty, 1 means "full and not assigned a group".
|
||||
let height = i.len() / width;
|
||||
let mut next_group_number = 2;
|
||||
for row in 0..height {
|
||||
for col in 0..width {
|
||||
if *value_at(&i, width, row, col) == 1 {
|
||||
flood_fill(&mut i, width, next_group_number, row, col);
|
||||
next_group_number += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
next_group_number - 2
|
||||
}
|
||||
|
||||
pub(crate) fn render_vec(key: &str) -> Vec<u32> {
|
||||
let mut output: Vec<u32> = vec![0; 128 * 128];
|
||||
let mut buffer: Vec<u8> = key.chars().map(|i| i as u8).collect();
|
||||
buffer.extend(&[b'-', b'0']);
|
||||
let len = buffer.len();
|
||||
|
||||
let mut row = 0;
|
||||
|
||||
for i in 0u8..=9 {
|
||||
buffer[len - 1] = i + b'0';
|
||||
let hash = knot_hash(&buffer);
|
||||
let mut col = 0;
|
||||
for byte in hash {
|
||||
let mut byte = byte;
|
||||
for i in (0..8).rev() {
|
||||
set_value_at(&mut output, 128, row, col + i, (byte % 2) as u32);
|
||||
byte /= 2;
|
||||
}
|
||||
col += 8;
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
|
||||
buffer.push(0);
|
||||
for i in 1u8..=9 {
|
||||
buffer[len - 1] = i + b'0';
|
||||
for j in 0u8..=9 {
|
||||
buffer[len] = j + b'0';
|
||||
let hash = knot_hash(&buffer);
|
||||
let mut col = 0;
|
||||
for byte in hash {
|
||||
let mut byte = byte;
|
||||
for i in (0..8).rev() {
|
||||
set_value_at(&mut output, 128, row, col + i, (byte % 2) as u32);
|
||||
byte /= 2;
|
||||
}
|
||||
col += 8;
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
buffer.push(0);
|
||||
buffer[len - 1] = b'1';
|
||||
for i in 0u8..=2 {
|
||||
buffer[len] = i + b'0';
|
||||
for j in 0u8..=(if i == 2 { 7 } else { 9 }) {
|
||||
buffer[len + 1] = j + b'0';
|
||||
let hash = knot_hash(&buffer);
|
||||
let mut col = 0;
|
||||
for byte in hash {
|
||||
let mut byte = byte;
|
||||
for i in (0..8).rev() {
|
||||
set_value_at(&mut output, 128, row, col + i, (byte % 2) as u32);
|
||||
byte /= 2;
|
||||
}
|
||||
col += 8;
|
||||
}
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
pub fn part_1(key: &str) -> usize {
|
||||
render_vec(key).iter().cloned().filter(|i| *i == 1).count()
|
||||
}
|
||||
|
||||
pub fn part_2(key: &str) -> u32 {
|
||||
count_contiguous(render_vec(key), 128)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_14::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&"flqrgnkx"), 8108);
|
||||
assert_eq!(part_1_longhand(&"flqrgnkx"), 8108);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&"flqrgnkx"), 1242);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_14() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(input), 8190);
|
||||
assert_eq!(part_1_longhand(input), 8190);
|
||||
assert_eq!(part_2(&input), 1134);
|
||||
}
|
||||
}
|
7
day_14/src/main.rs
Normal file
7
day_14/src/main.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use day_14::day_14;
|
||||
|
||||
fn main() {
|
||||
let input = day_14::input();
|
||||
println!("part 1 => {}", day_14::part_1(&input));
|
||||
println!("part 2 => {}", day_14::part_2(&input));
|
||||
}
|
Reference in New Issue
Block a user