Skip to content

Commit f990327

Browse files
committed
feat(11/2025): solve first part
1 parent e1d24c9 commit f990327

File tree

7 files changed

+182
-17
lines changed

7 files changed

+182
-17
lines changed

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
| [Day 7: Laboratories](src/solutions/year2025/day07.rs) | ⭐⭐ | 6.711 | 5.789 |
2121
| [Day 8: Playground](src/solutions/year2025/day08.rs) | ⭐⭐ | 46.993 | 44.599 |
2222
| [Day 9: Movie Theater](src/solutions/year2025/day09.rs) || 0.387 | - |
23+
| [Day 10: Factory](src/solutions/year2025/day10.rs) | | - | - |
24+
| [Day 11: Reactor](src/solutions/year2025/day11.rs) || 0.897 | - |
2325

2426
# 2024
2527

src/solutions/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub fn solution(puzzle_day: PuzzleDay) -> Box<dyn Solution> {
2424
7 => Box::new(year2025::day07::Day07),
2525
8 => Box::new(year2025::day08::Day08::default()),
2626
9 => Box::new(year2025::day09::Day09),
27+
11 => Box::new(year2025::day11::Day11),
2728
_ => panic!("Day not exist"),
2829
},
2930
Year::Year2024 => match i {

src/solutions/year2025/day11.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::solutions::Solution;
2+
use crate::utils::graphs::all_paths::AllPaths;
3+
use crate::utils::graphs::graph::Graph;
4+
5+
pub struct Day11;
6+
7+
const LABEL_YOU: &str = "you";
8+
const LABEL_OUT: &str = "out";
9+
10+
impl Solution for Day11 {
11+
fn part_one(&self, input: &str) -> String {
12+
let graph = self.parse(input);
13+
let all_paths: AllPaths<&str> = (&graph).into();
14+
15+
all_paths.paths(LABEL_YOU, LABEL_OUT).len().to_string()
16+
}
17+
18+
fn part_two(&self, _input: &str) -> String {
19+
String::from("0")
20+
}
21+
}
22+
23+
impl Day11 {
24+
fn parse<'a>(&self, input: &'a str) -> Graph<&'a str> {
25+
let mut graph = Graph::directed();
26+
27+
input.lines().for_each(|line| {
28+
let (node, outputs) = line.split_once(": ").unwrap();
29+
let outputs_vec = outputs.split_whitespace();
30+
31+
for output in outputs_vec {
32+
graph.add_edge(node, output);
33+
}
34+
});
35+
36+
graph
37+
}
38+
}
39+
40+
#[cfg(test)]
41+
mod tests {
42+
use crate::solutions::year2025::day11::Day11;
43+
use crate::solutions::Solution;
44+
45+
const EXAMPLE: &str = r#"aaa: you hhh
46+
you: bbb ccc
47+
bbb: ddd eee
48+
ccc: ddd eee fff
49+
ddd: ggg
50+
eee: out
51+
fff: out
52+
ggg: out
53+
hhh: ccc fff iii
54+
iii: out"#;
55+
56+
#[test]
57+
fn part_one_example_test() {
58+
assert_eq!("5", Day11.part_one(EXAMPLE));
59+
}
60+
}

src/solutions/year2025/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ pub mod day06;
77
pub mod day07;
88
pub mod day08;
99
pub mod day09;
10+
pub mod day11;

src/utils/graphs/all_paths.rs

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,87 @@
1-
use std::collections::VecDeque;
1+
use crate::utils::graphs::graph::Graph;
2+
use std::collections::{HashMap, VecDeque};
3+
use std::hash::Hash;
24

3-
pub struct AllPaths<'a, T> {
4-
adjacency: &'a dyn Fn(T) -> Vec<T>,
5+
pub trait IsEnd<T> {
6+
fn is_end(&self, value: &T) -> bool;
57
}
68

9+
impl<T: PartialEq> IsEnd<T> for T {
10+
fn is_end(&self, value: &T) -> bool {
11+
self == value
12+
}
13+
}
14+
15+
impl<T: PartialEq> IsEnd<T> for Vec<T> {
16+
fn is_end(&self, value: &T) -> bool {
17+
self.contains(value)
18+
}
19+
}
20+
21+
pub struct AllPaths<'a, T: 'a> {
22+
adjacency: Box<dyn Fn(T) -> Vec<T> + 'a>,
23+
}
24+
25+
impl<'a, T> From<&'a Graph<T>> for AllPaths<'a, T>
26+
where
27+
T: Eq + Hash + Copy + PartialEq + Clone,
28+
{
29+
fn from(graph: &'a Graph<T>) -> Self {
30+
Self::new(move |p: T| graph.neighbours(&p))
31+
}
32+
}
33+
34+
impl<'a, T> From<&'a HashMap<T, Vec<T>>> for AllPaths<'a, T>
35+
where
36+
T: Eq + Hash + Copy + PartialEq + Clone,
37+
{
38+
fn from(value: &'a HashMap<T, Vec<T>>) -> Self {
39+
Self::new(move |p: T| value.get(&p).unwrap().to_vec())
40+
}
41+
}
742
impl<'a, T> AllPaths<'a, T>
843
where
944
T: PartialEq + Clone,
1045
{
11-
pub fn new(adjacency: &'a dyn Fn(T) -> Vec<T>) -> Self {
12-
Self { adjacency }
46+
pub fn new(adjacency: impl Fn(T) -> Vec<T> + 'a) -> Self {
47+
Self {
48+
adjacency: Box::new(adjacency),
49+
}
1350
}
1451

15-
pub fn generate(&self, start: T, end: T) -> Vec<VecDeque<T>> {
52+
pub fn paths<E>(&self, start: T, end: E) -> Vec<VecDeque<T>>
53+
where
54+
E: IsEnd<T>,
55+
{
1656
let mut paths: Vec<VecDeque<T>> = Vec::new();
1757

18-
self.visit(start, end, Vec::new(), VecDeque::new(), &mut paths);
58+
self.visit(start, &end, Vec::new(), VecDeque::new(), &mut paths);
1959

2060
paths
2161
}
2262

23-
fn visit(
63+
fn visit<E>(
2464
&self,
2565
from: T,
26-
end: T,
66+
end: &E,
2767
mut visited: Vec<T>,
2868
mut path: VecDeque<T>,
2969
paths: &mut Vec<VecDeque<T>>,
30-
) {
70+
) where
71+
E: IsEnd<T>,
72+
{
3173
visited.push(from.clone());
3274
path.push_back(from.clone());
3375

34-
if from == end {
76+
if end.is_end(&from) {
3577
paths.push(path.clone());
3678

3779
return;
3880
}
3981

4082
for p in (self.adjacency)(from) {
4183
if !visited.contains(&p) {
42-
self.visit(p, end.clone(), visited.clone(), path.clone(), paths);
84+
self.visit(p, end, visited.clone(), path.clone(), paths);
4385
}
4486
}
4587
}
@@ -48,6 +90,7 @@ where
4890
#[cfg(test)]
4991
mod tests {
5092
use crate::utils::graphs::all_paths::AllPaths;
93+
use crate::utils::graphs::graph::Graph;
5194
use crate::utils::point::Point;
5295
use std::collections::{HashMap, VecDeque};
5396

@@ -66,13 +109,63 @@ mod tests {
66109
]);
67110
let adjacency = |p: Point| graph.get(&p).unwrap().to_vec();
68111

69-
let all_paths: AllPaths<Point> = AllPaths::new(&adjacency);
112+
let all_paths: AllPaths<Point> = AllPaths::new(adjacency);
70113

71-
let paths = all_paths.generate(p2, p3);
114+
let paths = all_paths.paths(p2, p3);
72115

73116
assert_eq!(3, paths.len());
74117
assert!(paths.contains(&VecDeque::from(vec![p2, p1, p3])));
75118
assert!(paths.contains(&VecDeque::from(vec![p2, p0, p3])));
76119
assert!(paths.contains(&VecDeque::from(vec![p2, p0, p1, p3])));
77120
}
121+
122+
#[test]
123+
fn paths_vec_end() {
124+
let p0 = Point::new(0, 0);
125+
let p1 = Point::new(1, 1);
126+
let p2 = Point::new(2, 2);
127+
let p3 = Point::new(3, 3);
128+
let p4 = Point::new(4, 4);
129+
130+
let graph: HashMap<Point, Vec<Point>> = HashMap::from([
131+
(p0, vec![p1, p2]),
132+
(p1, vec![p3]),
133+
(p2, vec![p4]),
134+
(p3, vec![]),
135+
(p4, vec![]),
136+
]);
137+
let adjacency = |p: Point| graph.get(&p).unwrap().to_vec();
138+
139+
let all_paths: AllPaths<Point> = AllPaths::new(adjacency);
140+
141+
let paths = all_paths.paths(p0, vec![p3, p4]);
142+
143+
assert_eq!(2, paths.len());
144+
assert!(paths.contains(&VecDeque::from(vec![p0, p1, p3])));
145+
assert!(paths.contains(&VecDeque::from(vec![p0, p2, p4])));
146+
}
147+
148+
#[test]
149+
fn paths_from_graph() {
150+
let p0 = Point::new(0, 0);
151+
let p1 = Point::new(1, 1);
152+
let p2 = Point::new(2, 2);
153+
let p3 = Point::new(3, 3);
154+
155+
let mut graph = Graph::undirected();
156+
graph.add_edge(p0, p1);
157+
graph.add_edge(p0, p2);
158+
graph.add_edge(p0, p3);
159+
graph.add_edge(p1, p3);
160+
graph.add_edge(p2, p1);
161+
162+
let all_paths = AllPaths::from(&graph);
163+
let paths = all_paths.paths(p2, p3);
164+
165+
assert_eq!(4, paths.len());
166+
assert!(paths.contains(&VecDeque::from(vec![p2, p1, p3])));
167+
assert!(paths.contains(&VecDeque::from(vec![p2, p0, p3])));
168+
assert!(paths.contains(&VecDeque::from(vec![p2, p0, p1, p3])));
169+
assert!(paths.contains(&VecDeque::from(vec![p2, p1, p0, p3])));
170+
}
78171
}

src/utils/graphs/graph.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::collections::{HashMap, HashSet};
22
use std::hash::Hash;
33

44
enum GraphType {
5-
#[allow(dead_code)]
65
Directed,
76
Undirected,
87
}
@@ -24,6 +23,15 @@ impl<T> Graph<T> {
2423
}
2524
}
2625

26+
pub fn directed() -> Self {
27+
Self {
28+
nodes: HashSet::new(),
29+
edges: HashSet::new(),
30+
neighbours: HashMap::new(),
31+
graph_type: GraphType::Directed,
32+
}
33+
}
34+
2735
pub fn add_edge(&mut self, a: T, b: T)
2836
where
2937
T: Eq + Hash + Copy,
@@ -59,7 +67,7 @@ impl<T> Graph<T> {
5967
&self.edges
6068
}
6169

62-
fn neighbours(&self, node: &T) -> Vec<T>
70+
pub fn neighbours(&self, node: &T) -> Vec<T>
6371
where
6472
T: Eq + Hash + Copy,
6573
{

src/utils/graphs/longest_path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ where
1717

1818
pub fn cost(&self, start: T, end: T) -> usize {
1919
let all_paths: AllPaths<T> = AllPaths::new(self.adjacency);
20-
let paths = all_paths.generate(start, end);
20+
let paths = all_paths.paths(start, end);
2121

2222
paths
2323
.into_iter()

0 commit comments

Comments
 (0)