-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 2024/05/p1 * 2024/05/p2 * cargo fmt
- Loading branch information
Showing
8 changed files
with
316 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[package] | ||
name = "day05_2024" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[lib] | ||
name = "day05_2024" | ||
path = "src/lib.rs" | ||
|
||
[dependencies] | ||
aoc-solution = { path = "../../aoc-solution" } | ||
aoc-common = { path = "../../common" } | ||
anyhow = { workspace = true } | ||
winnow = { workspace = true } | ||
|
||
[dev-dependencies] | ||
criterion = { workspace = true } | ||
|
||
[[bench]] | ||
name = "benchmarks" | ||
harness = false | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// Copyright 2023 Jedrzej Stuczynski | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use aoc_common::define_aoc_benchmark; | ||
use day05_2024::Day05; | ||
|
||
define_aoc_benchmark!("inputs/2024/day05", Day05); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// Copyright 2024 Jedrzej Stuczynski | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use aoc_common::parsing::combinators::parse_number; | ||
use std::collections::HashMap; | ||
use std::str::FromStr; | ||
use winnow::ascii::line_ending; | ||
use winnow::combinator::{alt, separated, separated_pair}; | ||
use winnow::{PResult, Parser}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct PrintingRules { | ||
// map of rules where the key value must come before any of the specified values | ||
ordering_rules: HashMap<usize, Vec<usize>>, | ||
printing_updates: Vec<PrintingUpdate>, | ||
} | ||
|
||
impl PrintingRules { | ||
fn can_be_printed_before(&self, page: usize, after: &[usize]) -> bool { | ||
if after.is_empty() { | ||
return true; | ||
} | ||
|
||
let Some(rules) = self.ordering_rules.get(&page) else { | ||
return false; | ||
}; | ||
|
||
for next in after { | ||
if next == &page { | ||
continue; | ||
} | ||
|
||
if !rules.contains(next) { | ||
return false; | ||
} | ||
} | ||
|
||
true | ||
} | ||
|
||
pub fn is_update_valid(&self, update: &PrintingUpdate) -> bool { | ||
for (i, page) in update.pages_to_produce.iter().enumerate() { | ||
if !self.can_be_printed_before(*page, &update.pages_to_produce[i + 1..]) { | ||
return false; | ||
} | ||
} | ||
true | ||
} | ||
|
||
pub fn fix_update(&self, update: &PrintingUpdate) -> PrintingUpdate { | ||
let mut fixed = Vec::with_capacity(update.pages_to_produce.len()); | ||
|
||
let mut pages_to_insert = update.pages_to_produce.clone(); | ||
// first page is the one that comes before **all** remaining ones (there can only be one) | ||
// second page includes all but the first, etc... | ||
// is this the most efficient? lol, no, insertion sort is one of the worst ones, | ||
// but given the size of the input, it's a perfectly valid solution to this problem | ||
while !pages_to_insert.is_empty() { | ||
if pages_to_insert.len() == 1 { | ||
fixed.push(pages_to_insert[0]); | ||
break; | ||
} | ||
for (i, page) in pages_to_insert.iter().enumerate() { | ||
if self.can_be_printed_before(*page, &pages_to_insert) { | ||
fixed.push(*page); | ||
pages_to_insert.remove(i); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
PrintingUpdate { | ||
pages_to_produce: fixed, | ||
} | ||
} | ||
|
||
pub fn updates(&self) -> &[PrintingUpdate] { | ||
&self.printing_updates | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub struct RawOrderingRule { | ||
first: usize, | ||
second: usize, | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct PrintingUpdate { | ||
pages_to_produce: Vec<usize>, | ||
} | ||
|
||
impl PrintingUpdate { | ||
pub fn middle_value(&self) -> usize { | ||
self.pages_to_produce[self.pages_to_produce.len() / 2] | ||
} | ||
} | ||
|
||
fn ordering_rule_parser(input: &mut &str) -> PResult<RawOrderingRule> { | ||
separated_pair(parse_number, '|', parse_number) | ||
.map(|(first, second)| RawOrderingRule { first, second }) | ||
.parse_next(input) | ||
} | ||
|
||
fn raw_ordering_rules_parser(input: &mut &str) -> PResult<Vec<RawOrderingRule>> { | ||
separated(1.., ordering_rule_parser, line_ending).parse_next(input) | ||
} | ||
|
||
fn printing_update_parser(input: &mut &str) -> PResult<PrintingUpdate> { | ||
separated(1.., parse_number::<usize>, ',') | ||
.map(|pages_to_produce| PrintingUpdate { pages_to_produce }) | ||
.parse_next(input) | ||
} | ||
|
||
impl FromStr for PrintingRules { | ||
type Err = anyhow::Error; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
let (raw_ordering_rules, printing_updates) = separated_pair( | ||
raw_ordering_rules_parser, | ||
alt(("\n\n", "\r\n\r\n")), | ||
separated(1.., printing_update_parser, line_ending), | ||
) | ||
.parse(s.trim()) | ||
.map_err(|err| anyhow::format_err!("{err}"))?; | ||
|
||
let mut ordering_rules = HashMap::new(); | ||
for raw in raw_ordering_rules { | ||
ordering_rules | ||
.entry(raw.first) | ||
.or_insert_with(Vec::new) | ||
.push(raw.second); | ||
} | ||
|
||
Ok(PrintingRules { | ||
ordering_rules, | ||
printing_updates, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2024 Jedrzej Stuczynski | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use crate::common::PrintingRules; | ||
use aoc_common::parsing::FromStrParser; | ||
use aoc_solution::Aoc; | ||
|
||
mod common; | ||
|
||
#[derive(Aoc)] | ||
#[aoc(input = PrintingRules)] | ||
#[aoc(parser = FromStrParser)] | ||
#[aoc(part1(output = usize, runner = part1))] | ||
#[aoc(part2(output = usize, runner = part2))] | ||
pub struct Day05; | ||
|
||
pub fn part1(input: PrintingRules) -> usize { | ||
input | ||
.updates() | ||
.iter() | ||
.filter(|u| input.is_update_valid(u)) | ||
.map(|u| u.middle_value()) | ||
.sum() | ||
} | ||
|
||
pub fn part2(input: PrintingRules) -> usize { | ||
input | ||
.updates() | ||
.iter() | ||
.filter(|u| !input.is_update_valid(u)) | ||
.map(|u| input.fix_update(u).middle_value()) | ||
.sum() | ||
} | ||
|
||
#[cfg(test)] | ||
#[allow(clippy::unwrap_used)] | ||
mod tests { | ||
use super::*; | ||
|
||
fn sample_input() -> PrintingRules { | ||
r#"47|53 | ||
97|13 | ||
97|61 | ||
97|47 | ||
75|29 | ||
61|13 | ||
75|53 | ||
29|13 | ||
97|29 | ||
53|29 | ||
61|53 | ||
97|53 | ||
61|29 | ||
47|13 | ||
75|47 | ||
97|75 | ||
47|61 | ||
75|61 | ||
47|29 | ||
75|13 | ||
53|13 | ||
75,47,61,53,29 | ||
97,61,53,29,13 | ||
75,29,13 | ||
75,97,47,61,53 | ||
61,13,29 | ||
97,13,75,29,47"# | ||
.parse() | ||
.unwrap() | ||
} | ||
|
||
#[test] | ||
fn part1_sample_input() { | ||
let expected = 143; | ||
assert_eq!(expected, part1(sample_input())) | ||
} | ||
|
||
#[test] | ||
fn part2_sample_input() { | ||
let expected = 123; | ||
assert_eq!(expected, part2(sample_input())) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2024 Jedrzej Stuczynski | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
use aoc_common::helpers::root_path; | ||
use aoc_solution::AocSolutionSolver; | ||
use day05_2024::Day05; | ||
|
||
#[cfg(not(tarpaulin_include))] | ||
fn main() { | ||
Day05::try_solve_from_file(root_path("inputs/2024/day05")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters