implement day 10
This commit is contained in:
parent
0416116a65
commit
5eb76e73ca
62
src/day_10/mod.rs
Normal file
62
src/day_10/mod.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
mod model;
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use self::model::Mistake;
|
||||||
|
|
||||||
|
#[aoc_generator(day10)]
|
||||||
|
pub fn parse_input(input: &str) -> Vec<Mistake> {
|
||||||
|
input.lines().filter_map(model::find_mistake).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day10, part1)]
|
||||||
|
pub fn part1(input: &[Mistake]) -> usize {
|
||||||
|
input
|
||||||
|
.iter()
|
||||||
|
.filter_map(|mistake| mistake.unexpected_char_score())
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day10, part2)]
|
||||||
|
pub fn part2(input: &[Mistake]) -> usize {
|
||||||
|
let scores: Vec<usize> = input
|
||||||
|
.iter()
|
||||||
|
.filter_map(|mistake| mistake.autocomplete_score())
|
||||||
|
.sorted()
|
||||||
|
.collect();
|
||||||
|
scores[scores.len() / 2]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
const EXAMPLE_INPUT: &str = "[({(<(())[]>[[{[]{<()<>>
|
||||||
|
[(()[<>])]({[<{<<[]>>(
|
||||||
|
{([(<{}[<>[]}>{[]{[(<()>
|
||||||
|
(((({<>}<{<{<>}{[]{[]{}
|
||||||
|
[[<[([]))<([[{}[[()]]]
|
||||||
|
[{[{({}]{}}([{[{{{}}([]
|
||||||
|
{<[[]]>}<{[{[{[]{()[[[]
|
||||||
|
[<(<(<(<{}))><([]([]()
|
||||||
|
<{([([[(<>()){}]>(<<{{
|
||||||
|
<{([{{}}[<[[[<>{}]]]>[]]";
|
||||||
|
const RESULT_PART_1: usize = 26397;
|
||||||
|
const RESULT_PART_2: usize = 288957;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||||
|
assert_eq!(result, RESULT_PART_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||||
|
assert_eq!(result, RESULT_PART_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_example() {
|
||||||
|
super::parse_input(EXAMPLE_INPUT);
|
||||||
|
}
|
||||||
|
}
|
217
src/day_10/model.rs
Normal file
217
src/day_10/model.rs
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
#[derive(PartialEq, Clone, Copy, Debug)]
|
||||||
|
pub enum Kind {
|
||||||
|
Round,
|
||||||
|
Square,
|
||||||
|
Curly,
|
||||||
|
Pointy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Kind {
|
||||||
|
pub fn unexpected_char_score(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Kind::Round => 3,
|
||||||
|
Kind::Square => 57,
|
||||||
|
Kind::Curly => 1197,
|
||||||
|
Kind::Pointy => 25137,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Mistake {
|
||||||
|
Incomplete(Vec<Kind>),
|
||||||
|
Unexpected(Kind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mistake {
|
||||||
|
pub fn autocomplete_score(&self) -> Option<usize> {
|
||||||
|
if let Self::Incomplete(missing) = self {
|
||||||
|
let mut score = 0;
|
||||||
|
for kind in missing {
|
||||||
|
score *= 5;
|
||||||
|
score += match kind {
|
||||||
|
Kind::Round => 1,
|
||||||
|
Kind::Square => 2,
|
||||||
|
Kind::Curly => 3,
|
||||||
|
Kind::Pointy => 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Some(score)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unexpected_char_score(&self) -> Option<usize> {
|
||||||
|
if let Self::Unexpected(kind) = self {
|
||||||
|
Some(kind.unexpected_char_score())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_mistake(s: &str) -> Option<Mistake> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for kind in s.chars() {
|
||||||
|
match kind {
|
||||||
|
'(' => vec.push(Kind::Round),
|
||||||
|
'[' => vec.push(Kind::Square),
|
||||||
|
'{' => vec.push(Kind::Curly),
|
||||||
|
'<' => vec.push(Kind::Pointy),
|
||||||
|
')' => {
|
||||||
|
if vec.pop().unwrap() != Kind::Round {
|
||||||
|
return Some(Mistake::Unexpected(Kind::Round));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
']' => {
|
||||||
|
if vec.pop().unwrap() != Kind::Square {
|
||||||
|
return Some(Mistake::Unexpected(Kind::Square));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'}' => {
|
||||||
|
if vec.pop().unwrap() != Kind::Curly {
|
||||||
|
return Some(Mistake::Unexpected(Kind::Curly));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'>' => {
|
||||||
|
if vec.pop().unwrap() != Kind::Pointy {
|
||||||
|
return Some(Mistake::Unexpected(Kind::Pointy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("illegal character"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vec.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
vec.reverse();
|
||||||
|
Some(Mistake::Incomplete(vec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//use std::{rc::Rc, sync::RwLock};
|
||||||
|
//
|
||||||
|
//#[derive(Debug)]
|
||||||
|
//pub struct Chunk {
|
||||||
|
// kind: Kind,
|
||||||
|
// children: Vec<Rc<RwLock<Chunk>>>,
|
||||||
|
// parent: Option<Rc<RwLock<Chunk>>>,
|
||||||
|
// closing: Option<Kind>,
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl Chunk {
|
||||||
|
// pub fn find_first_illegal_char(&self) -> Option<Kind> {
|
||||||
|
// for child in &self.children {
|
||||||
|
// if let Some(kind) = child.try_read().unwrap().find_first_illegal_char() {
|
||||||
|
// return Some(kind);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if Some(self.kind) != self.closing {
|
||||||
|
// self.closing.clone()
|
||||||
|
// } else {
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn new(kind: Kind, parent: Option<Rc<RwLock<Chunk>>>) -> Rc<RwLock<Self>> {
|
||||||
|
// let new = Rc::new(RwLock::new(Self {
|
||||||
|
// kind,
|
||||||
|
// children: Vec::new(),
|
||||||
|
// parent: parent.clone(),
|
||||||
|
// closing: None
|
||||||
|
// }));
|
||||||
|
// if let Some(mut parent) = parent {
|
||||||
|
// if let Ok(mut parent_locked) = RwLock::try_write(&mut parent) {
|
||||||
|
// parent_locked.children.push(new.clone());
|
||||||
|
// } else {
|
||||||
|
// panic!("can't access parent to insert child")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// new
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn close(&mut self, kind: Kind) {
|
||||||
|
// self.closing = Some(kind);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn parse(s: &str) -> Result<Rc<RwLock<Self>>, &'static str> {
|
||||||
|
// let mut current: Option<Rc<RwLock<Self>>> = None;
|
||||||
|
//
|
||||||
|
// let open = |kind, current| {
|
||||||
|
// Some(Chunk::new(kind, current))
|
||||||
|
// };
|
||||||
|
// let close = |kind, current: Option<Rc<RwLock<Self>>>| {
|
||||||
|
// if let Some(mut current_some) = current {
|
||||||
|
// if let Ok(mut current_locked) = RwLock::try_write(&mut current_some) {
|
||||||
|
// current_locked.close(kind);
|
||||||
|
// Ok(current_locked.parent.clone())
|
||||||
|
// } else {
|
||||||
|
// Err("can't get a lock to the current chunk")
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// Ok(None)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// for kind in s.chars() {
|
||||||
|
// match kind {
|
||||||
|
// '(' => current = open(Kind::Round, current),
|
||||||
|
// '[' => current = open(Kind::Square, current),
|
||||||
|
// '{' => current = open(Kind::Curly, current),
|
||||||
|
// '<' => current = open(Kind::Pointy, current),
|
||||||
|
// ')' => current = close(Kind::Round, current)?,
|
||||||
|
// ']' => current = close(Kind::Square, current)?,
|
||||||
|
// '}' => current = close(Kind::Curly, current)?,
|
||||||
|
// '>' => current = close(Kind::Pointy, current)?,
|
||||||
|
// _ => return Err("Illegal character!"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// current.ok_or("String seems to have been empty")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//impl ToString for Chunk {
|
||||||
|
// fn to_string(&self) -> String {
|
||||||
|
// let mut ret_val = String::new();
|
||||||
|
// match self.kind {
|
||||||
|
// Kind::Round => ret_val.push('('),
|
||||||
|
// Kind::Square => ret_val.push('['),
|
||||||
|
// Kind::Curly => ret_val.push('{'),
|
||||||
|
// Kind::Pointy => ret_val.push('<'),
|
||||||
|
// }
|
||||||
|
// for child in &self.children {
|
||||||
|
// ret_val.push_str(&child.try_read().unwrap().to_string())
|
||||||
|
// }
|
||||||
|
// match self.closing {
|
||||||
|
// Some(Kind::Round) => ret_val.push(')'),
|
||||||
|
// Some(Kind::Square) => ret_val.push(']'),
|
||||||
|
// Some(Kind::Curly) => ret_val.push('}'),
|
||||||
|
// Some(Kind::Pointy) => ret_val.push('>'),
|
||||||
|
// None => (),
|
||||||
|
// }
|
||||||
|
// ret_val
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn unexpected_char() {
|
||||||
|
let res = super::find_mistake("{([(<{}[<>[]}>{[]{[(<()>");
|
||||||
|
assert!(res.is_some());
|
||||||
|
let res = res.unwrap();
|
||||||
|
assert_eq!(res.unexpected_char_score(), Some(1197));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incomplete_chunk() {
|
||||||
|
let res = super::find_mistake("<{([{{}}[<[[[<>{}]]]>[]]");
|
||||||
|
assert!(res.is_some());
|
||||||
|
let res = res.unwrap();
|
||||||
|
assert_eq!(res.autocomplete_score(), Some(294));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,5 +11,6 @@ pub mod day_06;
|
||||||
pub mod day_07;
|
pub mod day_07;
|
||||||
pub mod day_08;
|
pub mod day_08;
|
||||||
pub mod day_09;
|
pub mod day_09;
|
||||||
|
pub mod day_10;
|
||||||
|
|
||||||
aoc_lib! { year = 2021 }
|
aoc_lib! { year = 2021 }
|
||||||
|
|
Loading…
Reference in a new issue