Day 4
This commit is contained in:
parent
9c43a0f50e
commit
d953f3c6ad
8 changed files with 1254 additions and 1 deletions
1
.idea/advent_of_code_2022.iml
generated
1
.idea/advent_of_code_2022.iml
generated
|
@ -7,6 +7,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/day_01/src" isTestSource="false" />
|
<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_02/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/day_03/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" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ['common', 'cli', 'day_01', 'day_02', 'day_03']
|
members = ['common', 'cli', 'day_01', 'day_02', 'day_03', 'day_04']
|
||||||
|
|
|
@ -10,4 +10,5 @@ clap = { version = "4.0", features = ["derive"] }
|
||||||
day_01 = { path = "../day_01"}
|
day_01 = { path = "../day_01"}
|
||||||
day_02 = { path = "../day_02"}
|
day_02 = { path = "../day_02"}
|
||||||
day_03 = { path = "../day_03"}
|
day_03 = { path = "../day_03"}
|
||||||
|
day_04 = { path = "../day_04"}
|
||||||
common = { path = "../common"}
|
common = { path = "../common"}
|
||||||
|
|
|
@ -71,6 +71,21 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
);
|
);
|
||||||
Ok(())
|
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!()
|
unimplemented!()
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub enum Day {
|
||||||
One,
|
One,
|
||||||
Two,
|
Two,
|
||||||
Three,
|
Three,
|
||||||
|
Four,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Copy, Clone, Debug)]
|
#[derive(ValueEnum, Copy, Clone, Debug)]
|
||||||
|
|
10
day_04/Cargo.toml
Normal file
10
day_04/Cargo.toml
Normal 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
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
225
day_04/src/lib.rs
Normal 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"#
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue