157 lines
4.0 KiB
Rust
157 lines
4.0 KiB
Rust
|
use std::collections::VecDeque;
|
||
|
|
||
|
pub fn day10() {
|
||
|
let corrupted = "{([(<{}[<>[]}>{[]{[(<()>";
|
||
|
let result = parse_line(corrupted);
|
||
|
println!(
|
||
|
"corrupted: {:?}, score: {:?}",
|
||
|
&result,
|
||
|
error_score(&result)
|
||
|
);
|
||
|
|
||
|
let incomplete = "[(()[<>])]({[<{<<[]>>(";
|
||
|
println!("incomplete: {:#?}", parse_line(incomplete));
|
||
|
|
||
|
// let input = r#"
|
||
|
// [({(<(())[]>[[{[]{<()<>>
|
||
|
// [(()[<>])]({[<{<<[]>>(
|
||
|
// {([(<{}[<>[]}>{[]{[(<()>
|
||
|
// (((({<>}<{<{<>}{[]{[]{}
|
||
|
// [[<[([]))<([[{}[[()]]]
|
||
|
// [{[{({}]{}}([{[{{{}}([]
|
||
|
// {<[[]]>}<{[{[{[]{()[[[]
|
||
|
// [<(<(<(<{}))><([]([]()
|
||
|
// <{([([[(<>()){}]>(<<{{
|
||
|
// <{([{{}}[<[[[<>{}]]]>[]]
|
||
|
// "#;
|
||
|
let input = include_str!("../input/day10.txt");
|
||
|
|
||
|
let parsed_lines = input.trim().lines().map(parse_line);
|
||
|
|
||
|
let total_error_score: u64 = parsed_lines
|
||
|
.clone()
|
||
|
.filter_map(|res| error_score(&res))
|
||
|
.sum();
|
||
|
println!("total error score: {}", total_error_score);
|
||
|
|
||
|
let completion = autocomplete(&parse_line(incomplete)).unwrap();
|
||
|
println!(
|
||
|
"to complete: {:?}, score: {}",
|
||
|
&completion,
|
||
|
autocomplete_score(&completion)
|
||
|
);
|
||
|
|
||
|
let mut autocomplete_scores = parsed_lines
|
||
|
.filter_map(|res| autocomplete(&res))
|
||
|
.map(|completion| autocomplete_score(&completion))
|
||
|
.collect::<Vec<_>>();
|
||
|
autocomplete_scores.sort();
|
||
|
println!(
|
||
|
"middle score: {}",
|
||
|
autocomplete_scores[autocomplete_scores.len() / 2]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
static OPENERS: &[char] = &['(', '[', '{', '<'];
|
||
|
static CLOSERS: &[char] = &[')', ']', '}', '>'];
|
||
|
|
||
|
fn parse_line(line: &str) -> ParseResult {
|
||
|
let mut iter = line.trim().chars().peekable();
|
||
|
let mut finished = vec![];
|
||
|
let mut in_progress: VecDeque<Chunk> = VecDeque::new();
|
||
|
while let Some(c) = iter.next() {
|
||
|
if OPENERS.contains(&c) {
|
||
|
let index = OPENERS.iter().position(|&e| e == c).unwrap();
|
||
|
let new = Chunk {
|
||
|
opener: c,
|
||
|
closer: CLOSERS[index],
|
||
|
chunks: vec![],
|
||
|
};
|
||
|
in_progress.push_front(new);
|
||
|
} else if CLOSERS.contains(&c) {
|
||
|
if in_progress.front().unwrap().closer == c {
|
||
|
let closed = in_progress.pop_front().unwrap();
|
||
|
match in_progress.front_mut() {
|
||
|
Some(new_cur) => new_cur.chunks.push(closed),
|
||
|
None => {
|
||
|
finished.push(closed);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
return ParseResult::Error {
|
||
|
expected: in_progress.front().unwrap().closer,
|
||
|
found: c,
|
||
|
};
|
||
|
}
|
||
|
} else {
|
||
|
panic!("unreachable");
|
||
|
}
|
||
|
}
|
||
|
if in_progress.is_empty() {
|
||
|
ParseResult::Chunks(finished)
|
||
|
} else {
|
||
|
ParseResult::Incomplete {
|
||
|
finished,
|
||
|
in_progress,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn error_score(result: &ParseResult) -> Option<u64> {
|
||
|
match result {
|
||
|
ParseResult::Error { expected: _, found } => Some(match found {
|
||
|
')' => 3,
|
||
|
']' => 57,
|
||
|
'}' => 1197,
|
||
|
'>' => 25137,
|
||
|
_ => 0,
|
||
|
}),
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn autocomplete(result: &ParseResult) -> Option<Vec<char>> {
|
||
|
match result {
|
||
|
ParseResult::Incomplete {
|
||
|
finished: _,
|
||
|
in_progress,
|
||
|
} => Some(in_progress.iter().map(|chunk| chunk.closer).collect()),
|
||
|
_ => None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn autocomplete_score(completion: &[char]) -> u64 {
|
||
|
let mut score = 0;
|
||
|
for c in completion {
|
||
|
score *= 5;
|
||
|
score += match c {
|
||
|
')' => 1,
|
||
|
']' => 2,
|
||
|
'}' => 3,
|
||
|
'>' => 4,
|
||
|
_ => 0,
|
||
|
};
|
||
|
}
|
||
|
score
|
||
|
}
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
struct Chunk {
|
||
|
opener: char,
|
||
|
closer: char,
|
||
|
chunks: Vec<Chunk>,
|
||
|
}
|
||
|
|
||
|
#[derive(Debug)]
|
||
|
enum ParseResult {
|
||
|
Chunks(Vec<Chunk>),
|
||
|
Error {
|
||
|
expected: char,
|
||
|
found: char,
|
||
|
},
|
||
|
Incomplete {
|
||
|
finished: Vec<Chunk>,
|
||
|
in_progress: VecDeque<Chunk>,
|
||
|
},
|
||
|
}
|