Skip to content

Commit c2b3955

Browse files
committed
feat(07/2025): implement foundations; add printable on grid trait to simplify printing on grid
1 parent ba1ac7b commit c2b3955

File tree

3 files changed

+185
-4
lines changed

3 files changed

+185
-4
lines changed

src/solutions/year2025/day07.rs

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,141 @@
11
use crate::solutions::Solution;
2+
use crate::utils::grid::{Grid, PrintableOnGrid};
3+
use crate::utils::line::Line;
4+
use crate::utils::point::Point;
5+
use std::collections::{HashSet, VecDeque};
6+
7+
const START: char = 'S';
8+
const SPLITTER: char = '^';
9+
const BEAM: char = '|';
210

311
pub struct Day07;
412

513
impl Solution for Day07 {
6-
fn part_one(&self, _input: &str) -> String {
7-
String::from("0")
14+
fn part_one(&self, input: &str) -> String {
15+
let grid: Grid<char> = Grid::from(input);
16+
let max_height = grid.columns_range().end();
17+
let start = grid.get_first_position(&START).unwrap();
18+
19+
let splitters: HashSet<Point> = grid.get_all_positions(&SPLITTER).into_iter().collect();
20+
21+
let mut result_beams: Vec<Beam> = Vec::new();
22+
let mut current_beams: VecDeque<Beam> = VecDeque::from(vec![start.into()]);
23+
24+
while let Some(current_beam) = current_beams.pop_front() {
25+
let down = current_beam.down();
26+
27+
if splitters.contains(&down.current()) {
28+
result_beams.push(current_beam);
29+
30+
for other in down.split() {
31+
if result_beams.iter().any(|beam| beam.is_on(&other)) {
32+
continue;
33+
}
34+
35+
current_beams.push_back(other);
36+
}
37+
38+
continue;
39+
}
40+
41+
if down.current().y > max_height + 1 {
42+
result_beams.push(current_beam);
43+
continue;
44+
}
45+
46+
current_beams.push_front(down);
47+
}
48+
49+
let mut new = grid.clone();
50+
new.print(&result_beams[..]);
51+
52+
println!("{}", new);
53+
54+
result_beams.len().to_string()
855
}
956

1057
fn part_two(&self, _input: &str) -> String {
1158
String::from("0")
1259
}
1360
}
1461

62+
#[derive(Copy, Clone)]
63+
struct Beam {
64+
line: Line,
65+
}
66+
67+
impl Beam {
68+
fn is_on(&self, other: &Self) -> bool {
69+
if other.line.start() != other.line.end() {
70+
panic!("We only support beam that just started");
71+
}
72+
73+
self.line.is_on(&other.line.start())
74+
}
75+
76+
fn down(&self) -> Self {
77+
Self {
78+
line: Line::new(self.line.start(), self.line.end().south()),
79+
}
80+
}
81+
82+
fn current(&self) -> Point {
83+
self.line.end()
84+
}
85+
86+
fn split(&self) -> Vec<Beam> {
87+
vec![self.current().west().into(), self.current().east().into()]
88+
}
89+
}
90+
91+
impl From<Point> for Beam {
92+
fn from(value: Point) -> Self {
93+
Self {
94+
line: Line::new(value, value),
95+
}
96+
}
97+
}
98+
99+
impl PrintableOnGrid for Beam {
100+
type Cell = char;
101+
102+
fn print_on_grid(&self, grid: &mut Grid<char>) {
103+
let mut moved = self.line.start();
104+
105+
loop {
106+
grid.modify(moved, BEAM);
107+
if moved == self.line.end() {
108+
break;
109+
}
110+
moved = moved.south();
111+
}
112+
}
113+
}
114+
15115
#[cfg(test)]
16116
mod tests {
17117
use crate::solutions::year2025::day07::Day07;
18118
use crate::solutions::Solution;
19119

20-
const EXAMPLE: &str = r#""#;
120+
const EXAMPLE: &str = r#".......S.......
121+
...............
122+
.......^.......
123+
...............
124+
......^.^......
125+
...............
126+
.....^.^.^.....
127+
...............
128+
....^.^...^....
129+
...............
130+
...^.^...^.^...
131+
...............
132+
..^...^.....^..
133+
...............
134+
.^.^.^.^.^...^.
135+
..............."#;
21136

22137
#[test]
23138
fn part_one_example_test() {
24-
assert_eq!("0", Day07.part_one(EXAMPLE));
139+
assert_eq!("21", Day07.part_one(EXAMPLE));
25140
}
26141
}

src/utils/grid.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,14 @@ where
361361

362362
self.get_for_point(&top_left)
363363
}
364+
365+
#[allow(dead_code)]
366+
pub fn print<P>(&mut self, printable: &P)
367+
where
368+
P: PrintableOnGrid<Cell = T> + ?Sized,
369+
{
370+
printable.print_on_grid(self)
371+
}
364372
}
365373

366374
impl<T> Display for Grid<T>
@@ -403,6 +411,23 @@ where
403411
}
404412
}
405413

414+
pub trait PrintableOnGrid {
415+
type Cell;
416+
fn print_on_grid(&self, grid: &mut Grid<Self::Cell>);
417+
}
418+
419+
impl<U> PrintableOnGrid for [U]
420+
where
421+
U: PrintableOnGrid,
422+
{
423+
type Cell = U::Cell;
424+
fn print_on_grid(&self, grid: &mut Grid<Self::Cell>) {
425+
for item in self {
426+
item.print_on_grid(grid);
427+
}
428+
}
429+
}
430+
406431
#[cfg(test)]
407432
mod tests {
408433
use crate::utils::grid::Grid;

src/utils/line.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@ pub struct Line {
77
}
88

99
impl Line {
10+
pub fn start(&self) -> Point {
11+
self.start
12+
}
13+
14+
pub fn end(&self) -> Point {
15+
self.end
16+
}
17+
1018
pub fn new(start: Point, end: Point) -> Self {
19+
// check if it is vertical, horizontal or diagonal only
20+
1121
Self { start, end }
1222
}
1323

@@ -35,4 +45,35 @@ impl Line {
3545

3646
Some(Point::new(x as isize, y as isize))
3747
}
48+
49+
pub fn is_on(&self, point: &Point) -> bool {
50+
let a = self.start;
51+
let b = self.end;
52+
let p = *point;
53+
54+
let cross_product = (p.y - a.y) * (b.x - a.x) - (p.x - a.x) * (b.y - a.y);
55+
56+
if cross_product != 0 {
57+
return false;
58+
}
59+
60+
p.x >= a.x.min(b.x) && p.x <= a.x.max(b.x) && p.y >= a.y.min(b.y) && p.y <= a.y.max(b.y)
61+
}
62+
}
63+
64+
#[cfg(test)]
65+
mod tests {
66+
use crate::utils::line::Line;
67+
use crate::utils::point::Point;
68+
69+
#[test]
70+
fn is_on() {
71+
let line = Line::new(Point::new(0, 0), Point::new(10, 10));
72+
73+
assert!(line.is_on(&Point::new(0, 0))); // Start point
74+
assert!(line.is_on(&Point::new(5, 5))); // On the line
75+
assert!(line.is_on(&Point::new(10, 10))); // End point
76+
assert!(!line.is_on(&Point::new(15, 15))); // Outside the segment
77+
assert!(!line.is_on(&Point::new(1, 5))); // Not on the line (not collinear)
78+
}
3879
}

0 commit comments

Comments
 (0)