mirror of
https://github.com/SebastianStork/advent-of-code.git
synced 2026-01-21 12:11:34 +01:00
Solve 2025 day 4 in rust
This commit is contained in:
parent
c7683b3600
commit
d8780f97a7
4 changed files with 182 additions and 3 deletions
7
2025/rust/day-04/Cargo.lock
generated
Normal file
7
2025/rust/day-04/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "day-04"
|
||||
version = "0.1.0"
|
||||
6
2025/rust/day-04/Cargo.toml
Normal file
6
2025/rust/day-04/Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day-04"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
166
2025/rust/day-04/src/main.rs
Normal file
166
2025/rust/day-04/src/main.rs
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
use std::{cell::RefCell, fs, rc::Rc};
|
||||
|
||||
struct Roll {
|
||||
neighbours: Vec<Rc<RefCell<Roll>>>,
|
||||
deleted: bool,
|
||||
}
|
||||
|
||||
impl Roll {
|
||||
fn new() -> Rc<RefCell<Roll>> {
|
||||
Rc::new(RefCell::new(Roll {
|
||||
neighbours: Vec::new(),
|
||||
deleted: false,
|
||||
}))
|
||||
}
|
||||
|
||||
fn add_neighbour(this: &Rc<RefCell<Roll>>, neighbour: &Rc<RefCell<Roll>>) {
|
||||
this.borrow_mut().neighbours.push(Rc::clone(neighbour));
|
||||
}
|
||||
|
||||
fn is_accessible(&self) -> bool {
|
||||
self.neighbours
|
||||
.iter()
|
||||
.filter(|neighbour| !neighbour.borrow().deleted)
|
||||
.count()
|
||||
< 4
|
||||
}
|
||||
|
||||
fn delete(this: &Rc<RefCell<Roll>>) {
|
||||
if this.borrow().deleted {
|
||||
return;
|
||||
}
|
||||
|
||||
this.borrow_mut().deleted = true;
|
||||
|
||||
this.borrow()
|
||||
.neighbours
|
||||
.iter()
|
||||
.filter(|neighbour| !neighbour.borrow().deleted)
|
||||
.filter(|neighbour| neighbour.borrow().is_accessible())
|
||||
.for_each(Roll::delete);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let grid = parse_input(&fs::read_to_string("../../inputs/04.txt").unwrap());
|
||||
let rolls = build_graph(grid);
|
||||
|
||||
println!(
|
||||
"Number of accessible rolls: {}",
|
||||
number_of_accessible_rolls(&rolls)
|
||||
);
|
||||
println!(
|
||||
"Number of removeable rolls: {}",
|
||||
number_of_removeable_rolls(&rolls)
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_input(contents: &str) -> Vec<Vec<Option<Rc<RefCell<Roll>>>>> {
|
||||
contents
|
||||
.trim()
|
||||
.lines()
|
||||
.map(|line: &str| {
|
||||
line.bytes()
|
||||
.map(|b| if b == b'@' { Some(Roll::new()) } else { None })
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn build_graph(grid: Vec<Vec<Option<Rc<RefCell<Roll>>>>>) -> Vec<Rc<RefCell<Roll>>> {
|
||||
for (row_index, row) in grid.iter().enumerate() {
|
||||
for (col_index, cell) in row.iter().enumerate() {
|
||||
if let Some(roll) = cell {
|
||||
for neighbour in get_neighbours(&grid, row_index, col_index) {
|
||||
Roll::add_neighbour(roll, neighbour);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grid.into_iter().flatten().flatten().collect()
|
||||
}
|
||||
|
||||
fn get_neighbours(
|
||||
grid: &[Vec<Option<Rc<RefCell<Roll>>>>],
|
||||
row: usize,
|
||||
col: usize,
|
||||
) -> Vec<&Rc<RefCell<Roll>>> {
|
||||
let offsets = [
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
(-1, 1),
|
||||
(0, -1),
|
||||
(0, 1),
|
||||
(1, -1),
|
||||
(1, 0),
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
offsets
|
||||
.iter()
|
||||
.filter_map(|(di, dj)| {
|
||||
let (ni, nj) = (row as i32 + di, col as i32 + dj);
|
||||
grid.get(ni as usize)?.get(nj as usize)?.as_ref()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn number_of_accessible_rolls(rolls: &[Rc<RefCell<Roll>>]) -> usize {
|
||||
rolls
|
||||
.iter()
|
||||
.filter(|roll| roll.borrow().is_accessible())
|
||||
.count()
|
||||
}
|
||||
|
||||
fn number_of_removeable_rolls(rolls: &[Rc<RefCell<Roll>>]) -> usize {
|
||||
loop {
|
||||
let deleted_any = rolls
|
||||
.iter()
|
||||
.filter(|roll| !roll.borrow().deleted)
|
||||
.filter(|roll| roll.borrow().is_accessible())
|
||||
.inspect(|roll| Roll::delete(roll))
|
||||
.count()
|
||||
> 0;
|
||||
|
||||
if !deleted_any {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rolls.iter().filter(|roll| roll.borrow().deleted).count()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const TEST_INPUT: &str = "
|
||||
..@@.@@@@.
|
||||
@@@.@.@.@@
|
||||
@@@@@.@.@@
|
||||
@.@@@@..@.
|
||||
@@.@@@@.@@
|
||||
.@@@@@@@.@
|
||||
.@.@.@.@@@
|
||||
@.@@@.@@@@
|
||||
.@@@@@@@@.
|
||||
@.@.@@@.@.
|
||||
";
|
||||
|
||||
#[test]
|
||||
fn test_part1() {
|
||||
assert_eq!(
|
||||
number_of_accessible_rolls(&build_graph(parse_input(TEST_INPUT))),
|
||||
13
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() {
|
||||
assert_eq!(
|
||||
number_of_removeable_rolls(&build_graph(parse_input(TEST_INPUT))),
|
||||
43
|
||||
);
|
||||
}
|
||||
}
|
||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -3,10 +3,10 @@
|
|||
"inputs": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1764767558,
|
||||
"narHash": "sha256-AqEynDX4eu61liwLdGPzk0b6J9sE+dKWSpxfO+mZpBc=",
|
||||
"lastModified": 1764840758,
|
||||
"narHash": "sha256-GTN8SBnhvv6t2oDS1H85xcYAhafy8mpUQWSrCErhtgw=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "a1a4c48fcc3eddac81d35ce2030c887ac38f4002",
|
||||
"rev": "415a59297c64d0448d22975ca5ad3d8ef064c9f0",
|
||||
"shallow": true,
|
||||
"type": "git",
|
||||
"url": "ssh://git@github.com/SebastianStork/advent-of-code-inputs.git"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue