This commit is contained in:
Anthony Cicchetti 2022-12-04 14:03:03 -05:00
parent 9c43a0f50e
commit d953f3c6ad
8 changed files with 1254 additions and 1 deletions

View file

@ -7,6 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/day_01/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/day_02/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/day_03/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/day_04/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />

View file

@ -1,2 +1,2 @@
[workspace]
members = ['common', 'cli', 'day_01', 'day_02', 'day_03']
members = ['common', 'cli', 'day_01', 'day_02', 'day_03', 'day_04']

View file

@ -10,4 +10,5 @@ clap = { version = "4.0", features = ["derive"] }
day_01 = { path = "../day_01"}
day_02 = { path = "../day_02"}
day_03 = { path = "../day_03"}
day_04 = { path = "../day_04"}
common = { path = "../common"}

View file

@ -71,6 +71,21 @@ fn main() -> Result<(), Box<dyn Error>> {
);
Ok(())
}
(day @ Day::Four, part @ Part::One) => {
println!(
"{}",
day_04::run_day_and_part(day, part, input_str.as_str())
);
Ok(())
}
(day @ Day::Four, part @ Part::Two) => {
println!(
"{}",
day_04::run_day_and_part(day, part, input_str.as_str())
);
Ok(())
}
(_, _) => {
unimplemented!()

View file

@ -5,6 +5,7 @@ pub enum Day {
One,
Two,
Three,
Four,
}
#[derive(ValueEnum, Copy, Clone, Debug)]

10
day_04/Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "day_04"
version = "0.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
common = {path = '../common'}
nom = "7.1.1"

1000
day_04/input/input Normal file

File diff suppressed because it is too large Load diff

225
day_04/src/lib.rs Normal file
View file

@ -0,0 +1,225 @@
use common::{Day, Part};
use nom::character::complete::{char, digit1, line_ending};
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::IResult;
use std::ops::RangeInclusive;
pub fn run_day_and_part(day: Day, part: Part, inp: &str) -> usize {
match (day, part) {
(Day::Four, Part::One) => {
part_01_do(inp)
.into_iter()
.fold(0, |acc, it| if it { acc + 1 } else { acc })
}
(Day::Four, Part::Two) => {
part_02_do(inp)
.into_iter()
.fold(0, |acc, it| if it { acc + 1 } else { acc })
}
(_, _) => unimplemented!(),
}
}
fn elf_range(s: &str) -> IResult<&str, RangeInclusive<usize>> {
let (s, elf_range): (&str, (&str, &str)) = separated_pair(digit1, char('-'), digit1)(s)?;
let left: usize = elf_range.0.parse::<_>().unwrap();
let right: usize = elf_range.1.parse::<_>().unwrap();
Ok((s, RangeInclusive::new(left, right)))
}
#[derive(Debug, Eq, PartialEq, Clone)]
struct ElfRangeLine {
first: RangeInclusive<usize>,
second: RangeInclusive<usize>,
}
impl ElfRangeLine {
fn one_contained_in_other(&self) -> bool {
self.first.clone().all(|a| self.second.clone().contains(&a))
|| self.second.clone().all(|a| self.first.clone().contains(&a))
}
fn any_overlap(&self) -> bool {
self.first.clone().any(|a| self.second.clone().contains(&a))
|| self.second.clone().any(|a| self.first.clone().contains(&a))
}
}
fn elf_range_line(s: &str) -> IResult<&str, ElfRangeLine> {
let (s, elf_ranges): (&str, (RangeInclusive<usize>, RangeInclusive<usize>)) =
separated_pair(elf_range, char(','), elf_range)(s)?;
Ok((
s,
ElfRangeLine {
first: elf_ranges.0,
second: elf_ranges.1,
},
))
}
fn elf_range_sequence(s: &str) -> IResult<&str, Vec<ElfRangeLine>> {
separated_list1(line_ending, elf_range_line)(s)
}
fn part_01_do(inp: &str) -> Vec<bool> {
let (_, ranges): (_, Vec<ElfRangeLine>) = elf_range_sequence(inp).unwrap();
ranges
.iter()
.map(|r: &ElfRangeLine| r.one_contained_in_other())
.collect()
}
fn part_02_do(inp: &str) -> Vec<bool> {
let (_, ranges): (_, Vec<ElfRangeLine>) = elf_range_sequence(inp).unwrap();
ranges
.iter()
.map(|r: &ElfRangeLine| r.any_overlap())
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn elf_range_creation() {
assert_eq!(Ok(("", (0..=4))), elf_range("0-4"))
}
#[test]
fn elf_range_line_creation() {
assert_eq!(
Ok((
"",
ElfRangeLine {
first: (0..=4),
second: (2..=5)
}
)),
elf_range_line("0-4,2-5")
)
}
#[test]
fn elf_range_contains_works_in_obvious_case() {
let expected = true;
let under_test = ElfRangeLine {
first: (2..=8),
second: (3..=7),
};
let res = under_test.one_contained_in_other();
assert_eq!(expected, res)
}
#[test]
fn elf_range_contains_fails_correctly() {
let expected = false;
let under_test = ElfRangeLine {
first: (2..=8),
second: (3..=9),
};
let res = under_test.one_contained_in_other();
assert_eq!(expected, res)
}
#[test]
fn elf_range_contains_reflexive() {
let expected = true;
let under_test = ElfRangeLine {
first: (3..=7),
second: (2..=8),
};
let res = under_test.one_contained_in_other();
assert_eq!(expected, res)
}
#[test]
fn part_01_example_parsed_correctly() {
let expected = Ok((
"",
vec![
ElfRangeLine {
first: (2..=4),
second: (6..=8),
},
ElfRangeLine {
first: (2..=3),
second: (4..=5),
},
ElfRangeLine {
first: (5..=7),
second: (7..=9),
},
ElfRangeLine {
first: (2..=8),
second: (3..=7),
},
ElfRangeLine {
first: (6..=6),
second: (4..=6),
},
ElfRangeLine {
first: (2..=6),
second: (4..=8),
},
],
));
assert_eq!(
expected,
elf_range_sequence(
r#"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 part_01_example_score_is_correct() {
assert_eq!(
2,
run_day_and_part(
Day::Four,
Part::One,
r#"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 part_02_example_score_is_correct() {
assert_eq!(
4,
run_day_and_part(
Day::Four,
Part::Two,
r#"2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8"#
)
)
}
}