day4 refactor with nom and allow tests

This commit is contained in:
Dylan Thies
2023-08-31 21:33:47 -04:00
parent a4408d7d16
commit 4f3bbb986d
3 changed files with 74 additions and 42 deletions

3
Cargo.lock generated
View File

@@ -65,6 +65,9 @@ version = "2022.0.0"
[[package]] [[package]]
name = "day4" name = "day4"
version = "2022.0.0" version = "2022.0.0"
dependencies = [
"nom",
]
[[package]] [[package]]
name = "day5" name = "day5"

View File

@@ -8,3 +8,4 @@ repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
nom.workspace = true

View File

@@ -1,51 +1,79 @@
#![warn(clippy::all, clippy::pedantic)] #![warn(clippy::all, clippy::pedantic)]
use std::fs::File; use std::fs;
use std::io::{prelude::*, BufReader};
fn main() -> std::io::Result<()> { use nom::{
//Read in file bytes::complete::tag,
let file = File::open("input")?; character::complete::{self, newline},
let reader = BufReader::new(file); multi::separated_list0,
sequence::separated_pair,
};
let value = reader fn parse_range(input: &str) -> nom::IResult<&str, (i32, i32)> {
.lines() separated_pair(complete::i32, tag("-"), complete::i32)(input)
.map(|line| { }
let line = line.unwrap(); fn parse_line(input: &str) -> nom::IResult<&str, ((i32, i32), (i32, i32))> {
// split and parse separated_pair(parse_range, tag(","), parse_range)(input)
let (a, b) = match line.split(',').take(2).collect::<Vec<&str>>()[..] { }
[a, b] => ( fn process_input(input: &str) -> nom::IResult<&str, Vec<((i32, i32), (i32, i32))>> {
a.split('-') separated_list0(newline, parse_line)(input)
.take(2) }
.map(|x| x.parse::<i32>().unwrap())
.collect::<Vec<i32>>(), fn part1(input: &str) -> String {
b.split('-') do_part(input, |(a, b)| {
.take(2) i32::from((a.0 <= b.0 && a.1 >= b.1) || (a.0 >= b.0 && a.1 <= b.1))
.map(|x| x.parse::<i32>().unwrap()) })
.collect::<Vec<i32>>(), }
), fn part2(input: &str) -> String {
_ => panic!("no good"), do_part(input, |(a, b)| {
};
(
// part 1 wholly overlapping
i32::from((a[0] <= b[0] && a[1] >= b[1]) || (a[0] >= b[0] && a[1] <= b[1])),
// part 2 any overlapping
i32::from( i32::from(
(a[0] >= b[0] && a[0] <= b[1]) (a.0 >= b.0 && a.0 <= b.1)
|| (a[1] >= b[0] && a[1] <= b[1]) || (a.1 >= b.0 && a.1 <= b.1)
|| (b[0] >= a[0] && b[0] <= a[1]) || (b.0 >= a.0 && b.0 <= a.1)
|| (b[1] >= a[0] && b[1] <= a[1]), || (b.1 >= a.0 && b.1 <= a.1),
),
) )
}) })
// using folding instead of sum() so that we can do both parts in one call }
.fold((0, 0), |mut acc: (i32, i32), x| {
acc.0 += x.0; fn do_part(input: &str, f: impl Fn((&(i32, i32), &(i32, i32))) -> i32) -> String {
acc.1 += x.1; let (_, ranges) = process_input(input).unwrap();
ranges
.iter()
.map(|(a, b)| f((a, b)))
.fold(0, |mut acc: i32, x: i32| {
acc += x;
acc acc
}); })
println!("Part 1: {}", value.0); .to_string()
println!("Part 2: {}", value.1); }
fn main() -> std::io::Result<()> {
//Read in file
let file = fs::read_to_string("input")?;
println!("Part 1: {}", part1(&file));
println!("Part 2: {}", part2(&file));
Ok(()) Ok(())
} }
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8";
#[test]
fn part1_works() {
assert_eq!(part1(INPUT), "2")
}
#[test]
fn part2_works() {
assert_eq!(part2(INPUT), "4")
}
}