day18 without nom
This commit is contained in:
parent
ee5ee9447a
commit
00ec9c2867
@ -9,4 +9,3 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
aoc-runner = "0.3.0"
|
aoc-runner = "0.3.0"
|
||||||
aoc-runner-derive = "0.3.0"
|
aoc-runner-derive = "0.3.0"
|
||||||
nom = "6.0.1"
|
|
||||||
|
|||||||
146
src/day18.rs
146
src/day18.rs
@ -1,45 +1,78 @@
|
|||||||
use aoc_runner_derive::aoc;
|
use aoc_runner_derive::aoc;
|
||||||
use nom::branch::alt;
|
|
||||||
use nom::bytes::complete::tag;
|
|
||||||
use nom::character::complete::{char, digit1, space0};
|
|
||||||
use nom::combinator::map_res;
|
|
||||||
use nom::multi::fold_many0;
|
|
||||||
use nom::sequence::{delimited, pair, preceded};
|
|
||||||
use nom::IResult;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
fn num(i: &str) -> IResult<&str, usize> {
|
fn num(i: &str) -> Option<(&str, usize)> {
|
||||||
map_res(delimited(space0, digit1, space0), FromStr::from_str)(i)
|
let i = i.trim_start();
|
||||||
|
let end_idx = i
|
||||||
|
.as_bytes()
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.position(|b| !(b'0'..=b'9').contains(&b))
|
||||||
|
.unwrap_or(i.len());
|
||||||
|
let n = (&i[..end_idx]).parse().ok()?;
|
||||||
|
let rem = &i[end_idx..];
|
||||||
|
Some((rem, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day18, part1)]
|
#[aoc(day18, part1)]
|
||||||
fn solve_d18_p1(input: &str) -> usize {
|
fn solve_d18_p1(input: &str) -> usize {
|
||||||
fn paren(i: &str) -> IResult<&str, usize> {
|
#[derive(Debug, Copy, Clone)]
|
||||||
delimited(space0, delimited(tag("("), expr, tag(")")), space0)(i)
|
enum Operator {
|
||||||
|
Add,
|
||||||
|
Mul,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_or_paren(i: &str) -> IResult<&str, usize> {
|
fn operator(i: &str) -> Option<(&str, Operator)> {
|
||||||
alt((num, paren))(i)
|
let i = i.trim_start();
|
||||||
|
let op = match i.as_bytes()[0] {
|
||||||
|
b'+' => Operator::Add,
|
||||||
|
b'*' => Operator::Mul,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some((&i[1..], op))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_or_paren(i: &str) -> IResult<&str, usize> {
|
fn paren(i: &str) -> Option<(&str, usize)> {
|
||||||
let (i, lhs) = num_or_paren(i)?;
|
let i = i.trim_start();
|
||||||
|
if i.is_empty() || i.as_bytes()[0] != b'(' {
|
||||||
fold_many0(preceded(char('+'), num_or_paren), lhs, |lhs, rhs| lhs + rhs)(i)
|
return None;
|
||||||
|
}
|
||||||
|
let (rem, n) = expr(&i[1..])?;
|
||||||
|
if rem.is_empty() || rem.as_bytes()[0] != b')' {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let rem = &rem[1..];
|
||||||
|
Some((rem, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(i: &str) -> IResult<&str, usize> {
|
fn num_or_paren(i: &str) -> Option<(&str, usize)> {
|
||||||
let (i, lhs) = add_or_paren(i)?;
|
num(i).or_else(|| paren(i))
|
||||||
|
}
|
||||||
|
|
||||||
fold_many0(
|
fn operator_and_rhs(i: &str) -> Option<(&str, (Operator, usize))> {
|
||||||
pair(alt((char('+'), char('*'))), num_or_paren),
|
let (i, op) = operator(i)?;
|
||||||
lhs,
|
let (i, rhs) = num_or_paren(i)?;
|
||||||
|lhs, (op, rhs)| match op {
|
Some((i, (op, rhs)))
|
||||||
'+' => lhs + rhs,
|
}
|
||||||
'*' => lhs * rhs,
|
|
||||||
_ => unreachable!(),
|
fn expr(i: &str) -> Option<(&str, usize)> {
|
||||||
},
|
let (mut rem, mut lhs) = num_or_paren(i)?;
|
||||||
)(i)
|
|
||||||
|
loop {
|
||||||
|
if rem.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((irem, (op, rhs))) = operator_and_rhs(rem) {
|
||||||
|
rem = irem;
|
||||||
|
lhs = match op {
|
||||||
|
Operator::Add => lhs + rhs,
|
||||||
|
Operator::Mul => lhs * rhs,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some((rem, lhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
input.split('\n').map(|line| expr(line).unwrap().1).sum()
|
input.split('\n').map(|line| expr(line).unwrap().1).sum()
|
||||||
@ -47,24 +80,59 @@ fn solve_d18_p1(input: &str) -> usize {
|
|||||||
|
|
||||||
#[aoc(day18, part2)]
|
#[aoc(day18, part2)]
|
||||||
fn solve_d18_p2(input: &str) -> usize {
|
fn solve_d18_p2(input: &str) -> usize {
|
||||||
fn paren(i: &str) -> IResult<&str, usize> {
|
fn paren(i: &str) -> Option<(&str, usize)> {
|
||||||
delimited(space0, delimited(tag("("), expr, tag(")")), space0)(i)
|
let i = i.trim_start();
|
||||||
|
if i.is_empty() || i.as_bytes()[0] != b'(' {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let (rem, n) = expr(&i[1..])?;
|
||||||
|
if rem.is_empty() || rem.as_bytes()[0] != b')' {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let rem = &rem[1..];
|
||||||
|
Some((rem, n))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_or_paren(i: &str) -> IResult<&str, usize> {
|
fn num_or_paren(i: &str) -> Option<(&str, usize)> {
|
||||||
alt((num, paren))(i)
|
num(i).or_else(|| paren(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_or_paren(i: &str) -> IResult<&str, usize> {
|
fn add_or_paren(i: &str) -> Option<(&str, usize)> {
|
||||||
let (i, lhs) = num_or_paren(i)?;
|
let (mut i, mut lhs) = num_or_paren(i)?;
|
||||||
|
|
||||||
fold_many0(preceded(char('+'), num_or_paren), lhs, |lhs, rhs| lhs + rhs)(i)
|
loop {
|
||||||
|
i = i.trim_start();
|
||||||
|
if i.is_empty() || i.as_bytes()[0] != b'+' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = &i[1..];
|
||||||
|
if let Some((rem, rhs)) = num_or_paren(i) {
|
||||||
|
lhs += rhs;
|
||||||
|
i = rem;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some((i, lhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(i: &str) -> IResult<&str, usize> {
|
fn expr(i: &str) -> Option<(&str, usize)> {
|
||||||
let (i, lhs) = add_or_paren(i)?;
|
let (mut i, mut lhs) = add_or_paren(i)?;
|
||||||
|
|
||||||
fold_many0(preceded(char('*'), add_or_paren), lhs, |lhs, rhs| lhs * rhs)(i)
|
loop {
|
||||||
|
i = i.trim_start();
|
||||||
|
if i.is_empty() || i.as_bytes()[0] != b'*' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = &i[1..];
|
||||||
|
if let Some((rem, rhs)) = add_or_paren(i) {
|
||||||
|
lhs *= rhs;
|
||||||
|
i = rem;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some((i, lhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
input.split('\n').map(|line| expr(line).unwrap().1).sum()
|
input.split('\n').map(|line| expr(line).unwrap().1).sum()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user