Skip to content

Commit 0803798

Browse files
committed
Day 04 in the morning
1 parent afb6396 commit 0803798

File tree

5 files changed

+263
-1
lines changed

5 files changed

+263
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ This should start the server at `localhost:8080`.
8989
❄️ [Day 01](aoc-solver/src/y2025/day01.rs)
9090
❄️ [Day 02](aoc-solver/src/y2025/day02.rs)
9191
❄️ [Day 03](aoc-solver/src/y2025/day03.rs)
92+
❄️ [Day 04](aoc-solver/src/y2025/day04.rs)

aoc-solver/src/y2025/day04.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::collections::HashSet;
2+
3+
use crate::solution::{AocError, Solution};
4+
5+
pub type Coords = (isize, isize);
6+
7+
#[rustfmt::skip]
8+
const NEIGHBOURS: [Coords; 8] = [
9+
(-1, -1), (0, -1), (1, -1),
10+
(-1, 0), (1, 0),
11+
(-1, 1), (0, 1), (1, 1),
12+
];
13+
14+
pub struct Day04;
15+
16+
fn parse(input: &str) -> Result<HashSet<Coords>, AocError> {
17+
let mut result = HashSet::new();
18+
19+
for (y, row) in input.trim().lines().enumerate() {
20+
for (x, tile) in row.chars().enumerate() {
21+
if tile == '@' {
22+
result.insert((x as isize, y as isize));
23+
}
24+
}
25+
}
26+
27+
Ok(result)
28+
}
29+
30+
fn count_neighbours((x, y): &Coords, occupied: &HashSet<Coords>) -> usize {
31+
NEIGHBOURS
32+
.iter()
33+
.filter(|(dx, dy)| occupied.contains(&(x + dx, y + dy)))
34+
.count()
35+
}
36+
37+
impl Solution for Day04 {
38+
type Part1 = usize;
39+
type Part2 = usize;
40+
41+
fn default_input(&self) -> &'static str {
42+
include_str!("../../../inputs/2025/day04.txt")
43+
}
44+
45+
fn part_1(&self, input: &str) -> Result<usize, AocError> {
46+
let occupied = parse(input)?;
47+
48+
let result = occupied
49+
.iter()
50+
.filter(|roll| count_neighbours(roll, &occupied) < 4)
51+
.count();
52+
53+
Ok(result)
54+
}
55+
56+
fn part_2(&self, input: &str) -> Result<usize, AocError> {
57+
let mut occupied = parse(input)?;
58+
let mut removed = 0;
59+
60+
loop {
61+
let before = occupied.len();
62+
let current = occupied.clone();
63+
occupied.retain(|roll| count_neighbours(roll, &current) >= 4);
64+
let after = occupied.len();
65+
66+
removed += before - after;
67+
68+
if before == after {
69+
break;
70+
}
71+
}
72+
73+
Ok(removed)
74+
}
75+
}
76+
77+
#[cfg(test)]
78+
mod tests {
79+
use super::*;
80+
81+
#[test]
82+
fn it_solves_part1_example() {
83+
assert_eq!(
84+
Day04.part_1(
85+
"..@@.@@@@.\n\
86+
@@@.@.@.@@\n\
87+
@@@@@.@.@@\n\
88+
@.@@@@..@.\n\
89+
@@.@@@@.@@\n\
90+
.@@@@@@@.@\n\
91+
.@.@.@.@@@\n\
92+
@.@@@.@@@@\n\
93+
.@@@@@@@@.\n\
94+
@.@.@@@.@."
95+
),
96+
Ok(13)
97+
);
98+
}
99+
100+
#[test]
101+
fn it_solves_part2_example() {
102+
assert_eq!(
103+
Day04.part_2(
104+
"..@@.@@@@.\n\
105+
@@@.@.@.@@\n\
106+
@@@@@.@.@@\n\
107+
@.@@@@..@.\n\
108+
@@.@@@@.@@\n\
109+
.@@@@@@@.@\n\
110+
.@.@.@.@@@\n\
111+
@.@@@.@@@@\n\
112+
.@@@@@@@@.\n\
113+
@.@.@@@.@."
114+
),
115+
Ok(43)
116+
);
117+
}
118+
}

aoc-solver/src/y2025/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use crate::solution::{Solution, Solver};
33
pub mod day01;
44
pub mod day02;
55
pub mod day03;
6+
pub mod day04;
67

7-
pub const MAX_DAYS: u8 = 3;
8+
pub const MAX_DAYS: u8 = 4;
89

910
pub struct Y2025;
1011

@@ -14,6 +15,7 @@ impl Solver for Y2025 {
1415
1 => day01::Day01.run(input, 1, 2025),
1516
2 => day02::Day02.run(input, 2, 2025),
1617
3 => day03::Day03.run(input, 3, 2025),
18+
4 => day04::Day04.run(input, 4, 2025),
1719
_ => vec![String::from("Solution not implemented (yet?)")],
1820
}
1921
}
@@ -34,6 +36,7 @@ impl Solver for Y2025 {
3436
1 => include_str!("./day01.rs"),
3537
2 => include_str!("./day02.rs"),
3638
3 => include_str!("./day03.rs"),
39+
4 => include_str!("./day04.rs"),
3740
_ => unimplemented!(),
3841
}
3942
}

aoc-web/src/header.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub fn header(props: &HeaderProps) -> Html {
2222
<NavLink route={Route::Solution { year: 2025, day: 1 }} current={props.route.clone()} text={"1"}/>
2323
<NavLink route={Route::Solution { year: 2025, day: 2 }} current={props.route.clone()} text={"2"}/>
2424
<NavLink route={Route::Solution { year: 2025, day: 3 }} current={props.route.clone()} text={"3"}/>
25+
<NavLink route={Route::Solution { year: 2025, day: 4 }} current={props.route.clone()} text={"4"}/>
2526
</>
2627
}
2728
},

0 commit comments

Comments
 (0)