2021: day10: part 2

This commit is contained in:
Antoine Martin 2021-12-10 14:26:31 +01:00
parent 6c7b3d9cc6
commit 7ec783fc16

View file

@ -8,6 +8,7 @@ pub fn run() -> Result<String> {
let mut res = String::with_capacity(128); let mut res = String::with_capacity(128);
writeln!(res, "part 1: {}", part1(INPUT)?)?; writeln!(res, "part 1: {}", part1(INPUT)?)?;
writeln!(res, "part 2: {}", part2(INPUT)?)?;
Ok(res) Ok(res)
} }
@ -18,7 +19,21 @@ fn part1(input: &str) -> Result<u64> {
.map(str::parse::<Line>) .map(str::parse::<Line>)
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
Ok(lines.iter().map(Line::corrupt_score).sum()) Ok(lines.iter().filter_map(Line::syntax_checking_score).sum())
}
fn part2(input: &str) -> Result<u64> {
let lines = input
.lines()
.map(str::parse::<Line>)
.collect::<Result<Vec<_>>>()?;
let mut scores: Vec<u64> = lines.iter().filter_map(Line::completion_score).collect();
scores.sort_unstable();
debug_assert!(scores.len() % 2 == 1);
Ok(scores[scores.len() / 2])
} }
enum SymbolState { enum SymbolState {
@ -47,7 +62,7 @@ enum Symbol {
} }
impl Symbol { impl Symbol {
fn score(&self) -> u64 { fn syntax_checking_score(&self) -> u64 {
match self { match self {
Symbol::Parenthesis => 3, Symbol::Parenthesis => 3,
Symbol::Bracket => 57, Symbol::Bracket => 57,
@ -55,6 +70,15 @@ impl Symbol {
Symbol::AngleBracket => 25137, Symbol::AngleBracket => 25137,
} }
} }
fn completion_score(&self) -> u64 {
match self {
Symbol::Parenthesis => 1,
Symbol::Bracket => 2,
Symbol::Brace => 3,
Symbol::AngleBracket => 4,
}
}
} }
impl TryFrom<char> for Symbol { impl TryFrom<char> for Symbol {
@ -76,7 +100,7 @@ struct Line {
} }
impl Line { impl Line {
fn corrupt_score(&self) -> u64 { fn syntax_checking_score(&self) -> Option<u64> {
let mut stack = Vec::new(); let mut stack = Vec::new();
for state in &self.symbols { for state in &self.symbols {
@ -84,12 +108,34 @@ impl Line {
SymbolState::Open(symbol) => stack.push(symbol), SymbolState::Open(symbol) => stack.push(symbol),
SymbolState::Close(symbol) => match stack.pop() { SymbolState::Close(symbol) => match stack.pop() {
Some(other_symbol) if symbol == other_symbol => continue, Some(other_symbol) if symbol == other_symbol => continue,
_ => return symbol.score(), _ => return Some(symbol.syntax_checking_score()),
}, },
} }
} }
0 None
}
fn completion_score(&self) -> Option<u64> {
let mut stack = Vec::new();
for state in &self.symbols {
match state {
SymbolState::Open(symbol) => stack.push(symbol),
SymbolState::Close(symbol) => match stack.pop() {
Some(other_symbol) if symbol == other_symbol => continue,
_ => return None, // ignore corrupt line
},
}
}
let mut score = 0;
for symbol in stack.into_iter().rev() {
score = score * 5 + symbol.completion_score();
}
Some(score)
} }
} }
@ -122,4 +168,14 @@ mod tests {
fn part1_real() { fn part1_real() {
assert_eq!(part1(INPUT).unwrap(), 394647); assert_eq!(part1(INPUT).unwrap(), 394647);
} }
#[test]
fn part2_provided() {
assert_eq!(part2(PROVIDED).unwrap(), 288957);
}
#[test]
fn part2_real() {
assert_eq!(part2(INPUT).unwrap(), 2380061249);
}
} }