Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/badges/completion2025.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"label": "2025",
"message": "04/50",
"message": "06/50",
"color": "red",
"style": "for-the-badge"
}
31 changes: 31 additions & 0 deletions 2025/day03/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "day03_2025"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
edition.workspace = true
license.workspace = true
rust-version.workspace = true
readme.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "day03_2025"
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
18 changes: 18 additions & 0 deletions 2025/day03/benches/benchmarks.rs
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 day03_2025::Day03;

define_aoc_benchmark!("inputs/2025/day03", Day03);
127 changes: 127 additions & 0 deletions 2025/day03/src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// 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 anyhow::Context;
use aoc_common::helpers::digits_to_number;
use std::str::FromStr;

#[derive(Debug, Clone)]
pub struct BatteryBank {
pub batteries: Vec<usize>,
}

impl BatteryBank {
fn maximum_joltage(&self, num_digits: usize) -> usize {
let mut digits = Vec::new();
let mut remaining_to_choose = num_digits;

let len = self.batteries.len();
if len < num_digits {
return 0;
}
if len == num_digits {
return digits_to_number(&self.batteries);
}

let mut window_start = 0;
for _ in 0..num_digits {
let mut chosen = 0;

// our unused window must always be sufficiently big for the remaining digits
let selection_window = &self.batteries[window_start..len - remaining_to_choose + 1];

// check if we simply run out of choices
if self.batteries[window_start..].len() == remaining_to_choose {
digits.extend_from_slice(&self.batteries[window_start..]);
break;
}

let mut found_at_index = 0;
for (i, value) in selection_window.iter().enumerate() {
if *value > chosen {
chosen = *value;
found_at_index = i;
}
if *value == 9 {
break;
}
}
window_start += found_at_index + 1;
remaining_to_choose -= 1;

digits.push(chosen);
}

digits_to_number(&digits)
}

pub fn maximum_joltage_with_two(&self) -> usize {
self.maximum_joltage(2)
}

pub fn maximum_joltage_with_twelve(&self) -> usize {
self.maximum_joltage(12)
}
}

impl FromStr for BatteryBank {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let batteries = s
.chars()
.map(|c| {
c.to_digit(10)
.map(|d| d as usize)
.context("invalid battery value")
})
.collect::<Result<Vec<_>, _>>()?;
Ok(BatteryBank { batteries })
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn maximum_joltage_with_two() {
let bank = BatteryBank::from_str("987654321111111").unwrap();
assert_eq!(bank.maximum_joltage_with_two(), 98);

let bank = BatteryBank::from_str("811111111111119").unwrap();
assert_eq!(bank.maximum_joltage_with_two(), 89);

let bank = BatteryBank::from_str("234234234234278").unwrap();
assert_eq!(bank.maximum_joltage_with_two(), 78);

let bank = BatteryBank::from_str("818181911112111").unwrap();
assert_eq!(bank.maximum_joltage_with_two(), 92);
}

#[test]
fn maximum_joltage_with_twelve() {
let bank = BatteryBank::from_str("987654321111111").unwrap();
assert_eq!(bank.maximum_joltage_with_twelve(), 987654321111);

let bank = BatteryBank::from_str("811111111111119").unwrap();
assert_eq!(bank.maximum_joltage_with_twelve(), 811111111119);

let bank = BatteryBank::from_str("234234234234278").unwrap();
assert_eq!(bank.maximum_joltage_with_twelve(), 434234234278);

let bank = BatteryBank::from_str("818181911112111").unwrap();
assert_eq!(bank.maximum_joltage_with_twelve(), 888911112111);
}
}
68 changes: 68 additions & 0 deletions 2025/day03/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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::BatteryBank;
use aoc_common::parsing::LineParser;
use aoc_solution::Aoc;

mod common;

#[derive(Aoc)]
#[aoc(input = Vec<BatteryBank>)]
#[aoc(parser = LineParser)]
#[aoc(part1(output = usize, runner = part1))]
#[aoc(part2(output = usize, runner = part2))]
pub struct Day03;

pub fn part1(input: Vec<BatteryBank>) -> usize {
input
.into_iter()
.map(|b| b.maximum_joltage_with_two())
.sum()
}

pub fn part2(input: Vec<BatteryBank>) -> usize {
input
.into_iter()
.map(|b| b.maximum_joltage_with_twelve())
.sum()
}

#[cfg(test)]
mod tests {
use super::*;
use aoc_solution::parser::AocInputParser;

fn sample_input() -> Vec<BatteryBank> {
LineParser::parse_input(
r#"987654321111111
811111111111119
234234234234278
818181911112111"#,
)
.unwrap()
}

#[test]
fn part1_sample_input() {
let expected = 357;
assert_eq!(expected, part1(sample_input()))
}

#[test]
fn part2_sample_input() {
let expected = 3121910778619;
assert_eq!(expected, part2(sample_input()))
}
}
22 changes: 22 additions & 0 deletions 2025/day03/src/main.rs
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 day03_2025::Day03;

#[cfg(not(tarpaulin_include))]
fn main() {
Day03::try_solve_from_file(root_path("inputs/2025/day03"))
}
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ members = [
"2024/day10",
"2024/day11",
"2025/day01",
"2025/day02"
"2025/day02",
"2025/day03"
]

[workspace.package]
Expand Down
6 changes: 3 additions & 3 deletions common/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ macro_rules! define_aoc_benchmark {

use aoc_common::helpers::root_path;
use aoc_common::input_read::read_input;
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
use std::fs;

fn get_input() -> <$typ as AocSolution>::Input {
Expand All @@ -42,7 +42,7 @@ macro_rules! define_aoc_benchmark {
c.bench_function(&bench_name, move |b| {
b.iter_batched(
|| input.clone(),
|input| <$typ as AocSolution>::part1((black_box(input))),
|input| <$typ as AocSolution>::part1((std::hint::black_box(input))),
BatchSize::SmallInput,
)
});
Expand All @@ -54,7 +54,7 @@ macro_rules! define_aoc_benchmark {
c.bench_function(&bench_name, move |b| {
b.iter_batched(
|| input.clone(),
|input| <$typ as AocSolution>::part2((black_box(input))),
|input| <$typ as AocSolution>::part2((std::hint::black_box(input))),
BatchSize::SmallInput,
)
});
Expand Down
24 changes: 24 additions & 0 deletions common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,27 @@

pub const FILLED_PIXEL: char = '█';
pub const EMPTY_PIXEL: char = '⠀';

pub const POWERS_OF_TEN: [usize; 21] = [
0,
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
];
1 change: 1 addition & 0 deletions solution-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,4 @@ day10_2024 = { path = "../2024/day10" }
day11_2024 = { path = "../2024/day11" }
day01_2025 = { path = "../2025/day01" }
day02_2025 = { path = "../2025/day02" }
day03_2025 = { path = "../2025/day03" }
1 change: 1 addition & 0 deletions solution-runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ fn main() {
define_solution!(args, 2024, 11, "inputs/2024/day11", day11_2024::Day11);
define_solution!(args, 2025, 1, "inputs/2025/day01", day01_2025::Day01);
define_solution!(args, 2025, 2, "inputs/2025/day02", day02_2025::Day02);
define_solution!(args, 2025, 3, "inputs/2025/day03", day03_2025::Day03);
// AUTOGENERATED SOLUTIONS END

println!("no solution found for year {}, day {}", args.year, args.day);
Expand Down
Loading