1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
use nom::{
branch::alt, character::complete::char as nom_char, combinator::map, multi::many0, IResult,
};
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = fs::read_to_string("inputs/day_10.txt")?;
let mut syntax_error_score = 0;
let mut autocomplete_scores = Vec::new();
for line in input.split("\n") {
match parse_lisp(line) {
Ok(_) => {
// boring
}
Err(nom::Err::Failure(ParseError::MismatchedExpectation(_, actual))) => {
syntax_error_score += match actual {
')' => 3,
']' => 57,
'}' => 1197,
'>' => 25137,
_ => 0,
}
}
Err(nom::Err::Failure(ParseError::EndOfInput(_))) => {
let mut line = line.to_owned();
let mut autocomplete_score = 0u64;
while let Err(nom::Err::Failure(ParseError::EndOfInput(expected))) =
parse_lisp(&line)
{
autocomplete_score *= 5;
autocomplete_score += match expected {
')' => 1,
']' => 2,
'}' => 3,
'>' => 4,
_ => 0,
};
line.push(expected);
}
autocomplete_scores.push(autocomplete_score);
}
Err(_) => panic!("Unexpected nom error type"),
}
}
dbg!(syntax_error_score);
autocomplete_scores.sort();
dbg!(autocomplete_scores[autocomplete_scores.len() / 2]);
Ok(())
}
#[derive(Debug)]
enum ParseError<'a> {
MismatchedExpectation(char, char),
EndOfInput(char),
Other(nom::error::Error<&'a str>),
}
impl<'a> From<nom::error::Error<&'a str>> for ParseError<'a> {
fn from(e: nom::error::Error<&'a str>) -> Self {
ParseError::Other(e)
}
}
impl<'a> nom::error::ParseError<&'a str> for ParseError<'a> {
fn from_error_kind(input: &'a str, kind: nom::error::ErrorKind) -> Self {
nom::error::Error::from_error_kind(input, kind).into()
}
fn append(_input: &'a str, _kind: nom::error::ErrorKind, other: Self) -> Self {
other
}
fn from_char(input: &'a str, c: char) -> Self {
nom::error::Error::from_char(input, c).into()
}
}
#[derive(Debug)]
struct Lisp {
blocks: Vec<Block>,
}
#[derive(Debug)]
struct Block {
opening: char,
blocks: Vec<Block>,
}
fn parse_lisp(input: &str) -> IResult<&str, Lisp, ParseError> {
map(parse_blocks, |blocks| Lisp { blocks })(input)
}
fn parse_blocks(input: &str) -> IResult<&str, Vec<Block>, ParseError> {
many0(parse_block)(input)
}
fn parse_block(input: &str) -> IResult<&str, Block, ParseError> {
alt((
block('{', '}'),
block('[', ']'),
block('(', ')'),
block('<', '>'),
))(input)
}
fn block(opening: char, closing: char) -> impl Fn(&str) -> IResult<&str, Block, ParseError> {
move |input: &str| {
let (input, _) = nom_char(opening)(input)?;
let (input, blocks) = parse_blocks(input)?;
let (input, _) = match nom_char(closing)(input) {
Ok((input, closing)) => (input, closing),
Err(nom::Err::Error(_)) => {
return Err(nom::Err::Failure(match input.chars().next() {
Some(actual) => ParseError::MismatchedExpectation(closing, actual),
None => ParseError::EndOfInput(closing),
}))
}
Err(e) => return Err(e),
};
Ok((input, Block { opening, blocks }))
}
}
|