mirror of
https://github.com/mx42/aoc2016.git
synced 2026-01-14 05:39:51 +01:00
feat: add day 14
This commit is contained in:
@@ -42,8 +42,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
|
|||||||
| [Day 11](./src/bin/11.rs) | `30.5s` | `-` |
|
| [Day 11](./src/bin/11.rs) | `30.5s` | `-` |
|
||||||
| [Day 12](./src/bin/12.rs) | `3.1ms` | `91.5ms` |
|
| [Day 12](./src/bin/12.rs) | `3.1ms` | `91.5ms` |
|
||||||
| [Day 13](./src/bin/13.rs) | `730.1µs` | `144.7µs` |
|
| [Day 13](./src/bin/13.rs) | `730.1µs` | `144.7µs` |
|
||||||
|
| [Day 14](./src/bin/14.rs) | `229.0ms` | `26.4s` |
|
||||||
|
|
||||||
**Total: 47929.23ms**
|
**Total: 74558.23ms**
|
||||||
<!--- benchmarking table --->
|
<!--- benchmarking table --->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
1
data/examples/14.txt
Normal file
1
data/examples/14.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
abc
|
||||||
@@ -191,7 +191,7 @@ fn parse_line(input: &str) -> Floor {
|
|||||||
let mut words = input.split_whitespace();
|
let mut words = input.split_whitespace();
|
||||||
let mut items: Vec<Item> = Vec::new();
|
let mut items: Vec<Item> = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
words.by_ref().skip_while(|&w| w != "a").next();
|
words.by_ref().find(|&w| w == "a"); // skip_while(|&w| w != "a").next();
|
||||||
if let Some(matter) = words.next() {
|
if let Some(matter) = words.next() {
|
||||||
if let Some(it_type) = words.next() {
|
if let Some(it_type) = words.next() {
|
||||||
// let it_type = it_type.strip_suffix(".").unwrap_or(it_type);
|
// let it_type = it_type.strip_suffix(".").unwrap_or(it_type);
|
||||||
|
|||||||
205
src/bin/14.rs
Normal file
205
src/bin/14.rs
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
advent_of_code::solution!(14);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Key {
|
||||||
|
index: u32,
|
||||||
|
threes: Vec<usize>,
|
||||||
|
fives: Vec<usize>,
|
||||||
|
// digest: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct State {
|
||||||
|
valid_keys: Vec<u32>,
|
||||||
|
pending_keys: [Vec<Key>; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for State {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(f, "{{ valid keys: {:?}, pending => ", self.valid_keys)?;
|
||||||
|
for p in 0..16 {
|
||||||
|
write!(f, "[{}] -> {}, ", p, self.pending_keys[p].len())?;
|
||||||
|
}
|
||||||
|
writeln!(f, "}}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_char_idx(c: char) -> usize {
|
||||||
|
match c {
|
||||||
|
'0'..='9' => c as usize - '0' as usize,
|
||||||
|
'a'..='f' => c as usize - 'a' as usize + 10,
|
||||||
|
_ => {
|
||||||
|
println!("char: {}", c);
|
||||||
|
panic!("invalid char !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ARRAY_REPEAT: Vec<Key> = Vec::new();
|
||||||
|
impl State {
|
||||||
|
fn init() -> Self {
|
||||||
|
Self {
|
||||||
|
valid_keys: Vec::new(),
|
||||||
|
pending_keys: [ARRAY_REPEAT; 16],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_state(&mut self, new_key: &Key) -> Self {
|
||||||
|
// println!("Update state with key {:?}", new_key);
|
||||||
|
for idx in &new_key.fives {
|
||||||
|
for pkey in &self.pending_keys[*idx] {
|
||||||
|
if pkey.index + 1000 >= new_key.index && !self.valid_keys.contains(&pkey.index) {
|
||||||
|
self.valid_keys.push(pkey.index);
|
||||||
|
// println!("{:4} New key validated: {:?}", self.valid_keys.len(), pkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.pending_keys[*idx] = vec![];
|
||||||
|
}
|
||||||
|
for idx in &new_key.threes {
|
||||||
|
self.pending_keys[*idx].push(new_key.clone());
|
||||||
|
}
|
||||||
|
self.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
fn init(index: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
index,
|
||||||
|
// digest,
|
||||||
|
threes: Vec::new(),
|
||||||
|
fives: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_3streak(&mut self, c: char) {
|
||||||
|
let idx = get_char_idx(c);
|
||||||
|
if self.threes.is_empty() {
|
||||||
|
// if !self.threes.contains(&idx) {
|
||||||
|
self.threes.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn add_5streak(&mut self, c: char) {
|
||||||
|
let idx = get_char_idx(c);
|
||||||
|
if !self.fives.contains(&idx) {
|
||||||
|
self.fives.push(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_streak(self) -> Option<Self> {
|
||||||
|
if !self.threes.is_empty() {
|
||||||
|
Some(self)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_key_p1(salt: &str, index: u32) -> Option<Key> {
|
||||||
|
let digest = format!("{:x}", md5::compute(format!("{}{}", salt, index)));
|
||||||
|
let mut res = Key::init(index); // , digest.clone());
|
||||||
|
let mut cs = digest.chars().peekable();
|
||||||
|
let mut cur_streak = 1;
|
||||||
|
while let Some(c) = cs.next() {
|
||||||
|
if Some(c) == cs.peek().copied() {
|
||||||
|
cur_streak += 1;
|
||||||
|
if cur_streak == 3 {
|
||||||
|
res.add_3streak(c);
|
||||||
|
} else if cur_streak == 5 {
|
||||||
|
res.add_5streak(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur_streak = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.has_streak()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn md5_loop(data: String, times: usize) -> String {
|
||||||
|
let digest = format!("{:x}", md5::compute(data));
|
||||||
|
if times > 0 {
|
||||||
|
md5_loop(digest, times - 1)
|
||||||
|
} else {
|
||||||
|
digest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_key_p2(salt: &str, index: u32) -> Option<Key> {
|
||||||
|
let digest = md5_loop(format!("{}{}", salt, index), 2016);
|
||||||
|
let mut res = Key::init(index); // , digest.clone());
|
||||||
|
let mut cs = digest.chars().peekable();
|
||||||
|
let mut cur_streak = 1;
|
||||||
|
while let Some(c) = cs.next() {
|
||||||
|
if Some(c) == cs.peek().copied() {
|
||||||
|
cur_streak += 1;
|
||||||
|
if cur_streak == 3 {
|
||||||
|
res.add_3streak(c);
|
||||||
|
} else if cur_streak == 5 {
|
||||||
|
res.add_5streak(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur_streak = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.has_streak()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve<F: Fn(&str, u32) -> Option<Key>>(input: &str, key_fn: F) -> Option<u32> {
|
||||||
|
let input = input.strip_suffix("\n").unwrap_or(input);
|
||||||
|
let states = (0..)
|
||||||
|
.flat_map(|i| key_fn(input, i))
|
||||||
|
.scan((State::init(), false), |(state, done), key| {
|
||||||
|
if *done {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let new_state = state.update_state(&key);
|
||||||
|
let valid_keys = new_state.valid_keys.len();
|
||||||
|
*done = valid_keys >= 80;
|
||||||
|
Some((new_state, valid_keys >= 80))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if let Some((last, _)) = states.last() {
|
||||||
|
if last.valid_keys.len() < 64 {
|
||||||
|
panic!("?!?! stopped before 64??");
|
||||||
|
}
|
||||||
|
let mut keys = last.valid_keys.clone();
|
||||||
|
keys.sort();
|
||||||
|
keys.get(63).copied()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_one(input: &str) -> Option<u32> {
|
||||||
|
solve(input, build_key_p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part_two(input: &str) -> Option<u32> {
|
||||||
|
solve(input, build_key_p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_md5_loop() {
|
||||||
|
let res = md5_loop("abc0".into(), 2016);
|
||||||
|
assert_eq!(res, "a107ff634856bb300138cac6568c0f24".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_one() {
|
||||||
|
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(22728));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part_two() {
|
||||||
|
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||||
|
assert_eq!(result, Some(22551));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user