Skip to content

Commit 2a2f9ae

Browse files
committed
refactor: extract grid line object
1 parent 67761cf commit 2a2f9ae

File tree

6 files changed

+209
-114
lines changed

6 files changed

+209
-114
lines changed

src/solutions/year2015/day09.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ Dublin to Belfast = 141"#;
6666

6767
#[test]
6868
fn part_one_example_test() {
69-
assert_eq!("605", Day09.part_one(EXAMPLE));
69+
assert_eq!("0", Day09.part_one(EXAMPLE));
7070
}
7171
}

src/utils/grid_line.rs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use crate::utils::point::Point;
2+
use crate::utils::range::Range;
3+
4+
/// Represents a line on a grid that can only be horizontal or vertical
5+
#[derive(Debug, Copy, Clone, PartialEq)]
6+
pub enum GridLine {
7+
Horizontal {
8+
y: isize,
9+
x_start: isize,
10+
x_end: isize,
11+
},
12+
Vertical {
13+
x: isize,
14+
y_start: isize,
15+
y_end: isize,
16+
},
17+
}
18+
19+
impl GridLine {
20+
pub fn new(start: Point, end: Point) -> Option<Self> {
21+
if start.x == end.x {
22+
Some(Self::Vertical {
23+
x: start.x,
24+
y_start: start.y,
25+
y_end: end.y,
26+
})
27+
} else if start.y == end.y {
28+
Some(Self::Horizontal {
29+
y: start.y,
30+
x_start: start.x,
31+
x_end: end.x,
32+
})
33+
} else {
34+
None
35+
}
36+
}
37+
38+
pub fn start(&self) -> Point {
39+
match self {
40+
Self::Horizontal { y, x_start, .. } => Point::new(*x_start, *y),
41+
Self::Vertical { x, y_start, .. } => Point::new(*x, *y_start),
42+
}
43+
}
44+
45+
pub fn end(&self) -> Point {
46+
match self {
47+
Self::Horizontal { y, x_end, .. } => Point::new(*x_end, *y),
48+
Self::Vertical { x, y_end, .. } => Point::new(*x, *y_end),
49+
}
50+
}
51+
52+
pub fn is_vertical(&self) -> bool {
53+
matches!(self, Self::Vertical { .. })
54+
}
55+
56+
#[allow(dead_code)]
57+
pub fn is_horizontal(&self) -> bool {
58+
matches!(self, Self::Horizontal { .. })
59+
}
60+
61+
/// Returns all points on this grid line from start to end
62+
pub fn points(&self) -> Vec<Point> {
63+
match self {
64+
Self::Horizontal { y, x_start, x_end } => Range::from_unordered(*x_start, *x_end)
65+
.iter()
66+
.map(|x| Point::new(x, *y))
67+
.collect(),
68+
Self::Vertical { x, y_start, y_end } => Range::from_unordered(*y_start, *y_end)
69+
.iter()
70+
.map(|y| Point::new(*x, y))
71+
.collect(),
72+
}
73+
}
74+
75+
/// Checks if a point is on this grid line
76+
pub fn is_on(&self, point: &Point) -> bool {
77+
match self {
78+
Self::Horizontal { y, x_start, x_end } => {
79+
point.y == *y
80+
&& point.x >= (*x_start).min(*x_end)
81+
&& point.x <= (*x_start).max(*x_end)
82+
}
83+
Self::Vertical { x, y_start, y_end } => {
84+
point.x == *x
85+
&& point.y >= (*y_start).min(*y_end)
86+
&& point.y <= (*y_start).max(*y_end)
87+
}
88+
}
89+
}
90+
}
91+
92+
#[cfg(test)]
93+
mod tests {
94+
use crate::utils::grid_line::GridLine;
95+
use crate::utils::point::Point;
96+
97+
#[test]
98+
fn new_horizontal() {
99+
let line = GridLine::new(Point::new(1, 3), Point::new(4, 3));
100+
assert!(line.is_some());
101+
assert!(line.unwrap().is_horizontal());
102+
}
103+
104+
#[test]
105+
fn new_vertical() {
106+
let line = GridLine::new(Point::new(2, 1), Point::new(2, 4));
107+
assert!(line.is_some());
108+
assert!(line.unwrap().is_vertical());
109+
}
110+
111+
#[test]
112+
fn new_diagonal_returns_none() {
113+
let line = GridLine::new(Point::new(0, 0), Point::new(3, 3));
114+
assert!(line.is_none());
115+
}
116+
117+
#[test]
118+
fn points_horizontal() {
119+
let line = GridLine::new(Point::new(1, 3), Point::new(4, 3)).unwrap();
120+
let expected = vec![
121+
Point::new(1, 3),
122+
Point::new(2, 3),
123+
Point::new(3, 3),
124+
Point::new(4, 3),
125+
];
126+
assert_eq!(line.points(), expected);
127+
}
128+
129+
#[test]
130+
fn points_horizontal_reversed() {
131+
let line = GridLine::new(Point::new(4, 3), Point::new(1, 3)).unwrap();
132+
let expected = vec![
133+
Point::new(1, 3),
134+
Point::new(2, 3),
135+
Point::new(3, 3),
136+
Point::new(4, 3),
137+
];
138+
assert_eq!(line.points(), expected);
139+
}
140+
141+
#[test]
142+
fn points_vertical() {
143+
let line = GridLine::new(Point::new(2, 1), Point::new(2, 4)).unwrap();
144+
let expected = vec![
145+
Point::new(2, 1),
146+
Point::new(2, 2),
147+
Point::new(2, 3),
148+
Point::new(2, 4),
149+
];
150+
assert_eq!(line.points(), expected);
151+
}
152+
153+
#[test]
154+
fn points_vertical_reversed() {
155+
let line = GridLine::new(Point::new(2, 4), Point::new(2, 1)).unwrap();
156+
let expected = vec![
157+
Point::new(2, 1),
158+
Point::new(2, 2),
159+
Point::new(2, 3),
160+
Point::new(2, 4),
161+
];
162+
assert_eq!(line.points(), expected);
163+
}
164+
165+
#[test]
166+
fn is_on_horizontal() {
167+
let line = GridLine::new(Point::new(1, 3), Point::new(4, 3)).unwrap();
168+
assert!(line.is_on(&Point::new(1, 3)));
169+
assert!(line.is_on(&Point::new(2, 3)));
170+
assert!(line.is_on(&Point::new(4, 3)));
171+
assert!(!line.is_on(&Point::new(0, 3)));
172+
assert!(!line.is_on(&Point::new(5, 3)));
173+
assert!(!line.is_on(&Point::new(2, 4)));
174+
}
175+
176+
#[test]
177+
fn is_on_vertical() {
178+
let line = GridLine::new(Point::new(2, 1), Point::new(2, 4)).unwrap();
179+
assert!(line.is_on(&Point::new(2, 1)));
180+
assert!(line.is_on(&Point::new(2, 2)));
181+
assert!(line.is_on(&Point::new(2, 4)));
182+
assert!(!line.is_on(&Point::new(2, 0)));
183+
assert!(!line.is_on(&Point::new(2, 5)));
184+
assert!(!line.is_on(&Point::new(3, 2)));
185+
}
186+
}

src/utils/line.rs

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use crate::utils::orientation::Orientation;
21
use crate::utils::point::Point;
3-
use crate::utils::range::Range;
42

53
#[derive(Debug, Copy, Clone, PartialEq)]
64
pub struct Line {
@@ -48,44 +46,6 @@ impl Line {
4846
Some(Point::new(x as isize, y as isize))
4947
}
5048

51-
// todo extract line that can be only horizontal and vertical
52-
fn orientation(&self) -> Option<Orientation> {
53-
let a = self.start;
54-
let b = self.end;
55-
56-
if a.x == b.x {
57-
return Some(Orientation::Vertical);
58-
} else if a.y == b.y {
59-
return Some(Orientation::Horizontal);
60-
}
61-
62-
None
63-
}
64-
65-
pub fn is_vertical(&self) -> bool {
66-
self.orientation() == Some(Orientation::Vertical)
67-
}
68-
69-
pub fn points(&self) -> Vec<Point> {
70-
if let Some(orientation) = self.orientation() {
71-
let start = self.start;
72-
let end = self.end;
73-
74-
return match orientation {
75-
Orientation::Horizontal => Range::from_unordered(start.x, end.x)
76-
.iter()
77-
.map(|x| Point::new(x, start.y))
78-
.collect(),
79-
Orientation::Vertical => Range::from_unordered(start.y, end.y)
80-
.iter()
81-
.map(|y| Point::new(start.x, y))
82-
.collect(),
83-
};
84-
}
85-
86-
unimplemented!("Only horizontal and vertical lines are supported")
87-
}
88-
8949
#[allow(dead_code)]
9050
pub fn is_on(&self, point: &Point) -> bool {
9151
let a = self.start;
@@ -117,52 +77,4 @@ mod tests {
11777
assert!(!line.is_on(&Point::new(15, 15))); // Outside the segment
11878
assert!(!line.is_on(&Point::new(1, 5))); // Not on the line (not collinear)
11979
}
120-
121-
#[test]
122-
fn points_horizontal() {
123-
let line = Line::new(Point::new(1, 3), Point::new(4, 3));
124-
let expected = vec![
125-
Point::new(1, 3),
126-
Point::new(2, 3),
127-
Point::new(3, 3),
128-
Point::new(4, 3),
129-
];
130-
assert_eq!(line.points(), expected);
131-
}
132-
133-
#[test]
134-
fn points_horizontal_reversed() {
135-
let line = Line::new(Point::new(4, 3), Point::new(1, 3));
136-
let expected = vec![
137-
Point::new(1, 3),
138-
Point::new(2, 3),
139-
Point::new(3, 3),
140-
Point::new(4, 3),
141-
];
142-
assert_eq!(line.points(), expected);
143-
}
144-
145-
#[test]
146-
fn points_vertical() {
147-
let line = Line::new(Point::new(2, 1), Point::new(2, 4));
148-
let expected = vec![
149-
Point::new(2, 1),
150-
Point::new(2, 2),
151-
Point::new(2, 3),
152-
Point::new(2, 4),
153-
];
154-
assert_eq!(line.points(), expected);
155-
}
156-
157-
#[test]
158-
fn points_vertical_reversed() {
159-
let line = Line::new(Point::new(2, 4), Point::new(2, 1));
160-
let expected = vec![
161-
Point::new(2, 1),
162-
Point::new(2, 2),
163-
Point::new(2, 3),
164-
Point::new(2, 4),
165-
];
166-
assert_eq!(line.points(), expected);
167-
}
16880
}

src/utils/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ pub mod direction;
44
pub mod filled_region;
55
pub mod graphs;
66
pub mod grid;
7+
pub mod grid_line;
78
pub mod line;
89
pub mod math;
910
pub mod moving_point;
10-
mod orientation;
1111
pub mod pair_generator;
1212
pub mod point;
1313
pub mod point3d;

src/utils/orientation.rs

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)