day4 refactor with nom and allow tests
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
112
day4/src/main.rs
112
day4/src/main.rs
@@ -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};
|
|
||||||
|
|
||||||
|
use nom::{
|
||||||
|
bytes::complete::tag,
|
||||||
|
character::complete::{self, newline},
|
||||||
|
multi::separated_list0,
|
||||||
|
sequence::separated_pair,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parse_range(input: &str) -> nom::IResult<&str, (i32, i32)> {
|
||||||
|
separated_pair(complete::i32, tag("-"), complete::i32)(input)
|
||||||
|
}
|
||||||
|
fn parse_line(input: &str) -> nom::IResult<&str, ((i32, i32), (i32, i32))> {
|
||||||
|
separated_pair(parse_range, tag(","), parse_range)(input)
|
||||||
|
}
|
||||||
|
fn process_input(input: &str) -> nom::IResult<&str, Vec<((i32, i32), (i32, i32))>> {
|
||||||
|
separated_list0(newline, parse_line)(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> String {
|
||||||
|
do_part(input, |(a, b)| {
|
||||||
|
i32::from((a.0 <= b.0 && a.1 >= b.1) || (a.0 >= b.0 && a.1 <= b.1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn part2(input: &str) -> String {
|
||||||
|
do_part(input, |(a, b)| {
|
||||||
|
i32::from(
|
||||||
|
(a.0 >= b.0 && a.0 <= b.1)
|
||||||
|
|| (a.1 >= b.0 && a.1 <= b.1)
|
||||||
|
|| (b.0 >= a.0 && b.0 <= a.1)
|
||||||
|
|| (b.1 >= a.0 && b.1 <= a.1),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_part(input: &str, f: impl Fn((&(i32, i32), &(i32, i32))) -> i32) -> String {
|
||||||
|
let (_, ranges) = process_input(input).unwrap();
|
||||||
|
ranges
|
||||||
|
.iter()
|
||||||
|
.map(|(a, b)| f((a, b)))
|
||||||
|
.fold(0, |mut acc: i32, x: i32| {
|
||||||
|
acc += x;
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
//Read in file
|
//Read in file
|
||||||
let file = File::open("input")?;
|
let file = fs::read_to_string("input")?;
|
||||||
let reader = BufReader::new(file);
|
|
||||||
|
|
||||||
let value = reader
|
println!("Part 1: {}", part1(&file));
|
||||||
.lines()
|
println!("Part 2: {}", part2(&file));
|
||||||
.map(|line| {
|
|
||||||
let line = line.unwrap();
|
|
||||||
// split and parse
|
|
||||||
let (a, b) = match line.split(',').take(2).collect::<Vec<&str>>()[..] {
|
|
||||||
[a, b] => (
|
|
||||||
a.split('-')
|
|
||||||
.take(2)
|
|
||||||
.map(|x| x.parse::<i32>().unwrap())
|
|
||||||
.collect::<Vec<i32>>(),
|
|
||||||
b.split('-')
|
|
||||||
.take(2)
|
|
||||||
.map(|x| x.parse::<i32>().unwrap())
|
|
||||||
.collect::<Vec<i32>>(),
|
|
||||||
),
|
|
||||||
_ => panic!("no good"),
|
|
||||||
};
|
|
||||||
(
|
|
||||||
// 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(
|
|
||||||
(a[0] >= b[0] && a[0] <= b[1])
|
|
||||||
|| (a[1] >= b[0] && a[1] <= b[1])
|
|
||||||
|| (b[0] >= a[0] && b[0] <= 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;
|
|
||||||
acc.1 += x.1;
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
println!("Part 1: {}", value.0);
|
|
||||||
println!("Part 2: {}", value.1);
|
|
||||||
|
|
||||||
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user