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_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" />
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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!()
|
||||
|
|
|
@ -5,6 +5,7 @@ pub enum Day {
|
|||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
#[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