Day 2 Morning Exercises

Points and Polygons

(back to exercise)

  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  15. // ANCHOR: Point
  16. pub struct Point {
  17. // ANCHOR_END: Point
  18. x: i32,
  19. y: i32,
  20. }
  21. // ANCHOR: Point-impl
  22. impl Point {
  23. // ANCHOR_END: Point-impl
  24. pub fn new(x: i32, y: i32) -> Point {
  25. Point { x, y }
  26. }
  27. pub fn magnitude(self) -> f64 {
  28. f64::from(self.x.pow(2) + self.y.pow(2)).sqrt()
  29. }
  30. pub fn dist(self, other: Point) -> f64 {
  31. (self - other).magnitude()
  32. }
  33. }
  34. impl std::ops::Add for Point {
  35. type Output = Self;
  36. fn add(self, other: Self) -> Self::Output {
  37. Self {
  38. x: self.x + other.x,
  39. y: self.y + other.y,
  40. }
  41. }
  42. }
  43. impl std::ops::Sub for Point {
  44. type Output = Self;
  45. fn sub(self, other: Self) -> Self::Output {
  46. Self {
  47. x: self.x - other.x,
  48. y: self.y - other.y,
  49. }
  50. }
  51. }
  52. // ANCHOR: Polygon
  53. pub struct Polygon {
  54. // ANCHOR_END: Polygon
  55. points: Vec<Point>,
  56. }
  57. // ANCHOR: Polygon-impl
  58. impl Polygon {
  59. // ANCHOR_END: Polygon-impl
  60. pub fn new() -> Polygon {
  61. Polygon { points: Vec::new() }
  62. }
  63. pub fn add_point(&mut self, point: Point) {
  64. self.points.push(point);
  65. }
  66. pub fn left_most_point(&self) -> Option<Point> {
  67. self.points.iter().min_by_key(|p| p.x).copied()
  68. }
  69. pub fn iter(&self) -> impl Iterator<Item = &Point> {
  70. self.points.iter()
  71. }
  72. pub fn length(&self) -> f64 {
  73. if self.points.is_empty() {
  74. return 0.0;
  75. }
  76. let mut result = 0.0;
  77. let mut last_point = self.points[0];
  78. for point in &self.points[1..] {
  79. result += last_point.dist(*point);
  80. last_point = *point;
  81. }
  82. result += last_point.dist(self.points[0]);
  83. result
  84. }
  85. }
  86. // ANCHOR: Circle
  87. pub struct Circle {
  88. // ANCHOR_END: Circle
  89. center: Point,
  90. radius: i32,
  91. }
  92. // ANCHOR: Circle-impl
  93. impl Circle {
  94. // ANCHOR_END: Circle-impl
  95. pub fn new(center: Point, radius: i32) -> Circle {
  96. Circle { center, radius }
  97. }
  98. pub fn circumference(&self) -> f64 {
  99. 2.0 * std::f64::consts::PI * f64::from(self.radius)
  100. }
  101. pub fn dist(&self, other: &Self) -> f64 {
  102. self.center.dist(other.center)
  103. }
  104. }
  105. // ANCHOR: Shape
  106. pub enum Shape {
  107. Polygon(Polygon),
  108. Circle(Circle),
  109. }
  110. // ANCHOR_END: Shape
  111. impl From<Polygon> for Shape {
  112. fn from(poly: Polygon) -> Self {
  113. Shape::Polygon(poly)
  114. }
  115. }
  116. impl From<Circle> for Shape {
  117. fn from(circle: Circle) -> Self {
  118. Shape::Circle(circle)
  119. }
  120. }
  121. impl Shape {
  122. pub fn perimeter(&self) -> f64 {
  123. match self {
  124. Shape::Polygon(poly) => poly.length(),
  125. Shape::Circle(circle) => circle.circumference(),
  126. }
  127. }
  128. }
  129. // ANCHOR: unit-tests
  130. #[cfg(test)]
  131. mod tests {
  132. use super::*;
  133. fn round_two_digits(x: f64) -> f64 {
  134. (x * 100.0).round() / 100.0
  135. }
  136. #[test]
  137. fn test_point_magnitude() {
  138. let p1 = Point::new(12, 13);
  139. assert_eq!(round_two_digits(p1.magnitude()), 17.69);
  140. }
  141. #[test]
  142. fn test_point_dist() {
  143. let p1 = Point::new(10, 10);
  144. let p2 = Point::new(14, 13);
  145. assert_eq!(round_two_digits(p1.dist(p2)), 5.00);
  146. }
  147. #[test]
  148. fn test_point_add() {
  149. let p1 = Point::new(16, 16);
  150. let p2 = p1 + Point::new(-4, 3);
  151. assert_eq!(p2, Point::new(12, 19));
  152. }
  153. #[test]
  154. fn test_polygon_left_most_point() {
  155. let p1 = Point::new(12, 13);
  156. let p2 = Point::new(16, 16);
  157. let mut poly = Polygon::new();
  158. poly.add_point(p1);
  159. poly.add_point(p2);
  160. assert_eq!(poly.left_most_point(), Some(p1));
  161. }
  162. #[test]
  163. fn test_polygon_iter() {
  164. let p1 = Point::new(12, 13);
  165. let p2 = Point::new(16, 16);
  166. let mut poly = Polygon::new();
  167. poly.add_point(p1);
  168. poly.add_point(p2);
  169. let points = poly.iter().cloned().collect::<Vec<_>>();
  170. assert_eq!(points, vec![Point::new(12, 13), Point::new(16, 16)]);
  171. }
  172. #[test]
  173. fn test_shape_perimeters() {
  174. let mut poly = Polygon::new();
  175. poly.add_point(Point::new(12, 13));
  176. poly.add_point(Point::new(17, 11));
  177. poly.add_point(Point::new(16, 16));
  178. let shapes = vec![
  179. Shape::from(poly),
  180. Shape::from(Circle::new(Point::new(10, 20), 5)),
  181. ];
  182. let perimeters = shapes
  183. .iter()
  184. .map(Shape::perimeter)
  185. .map(round_two_digits)
  186. .collect::<Vec<_>>();
  187. assert_eq!(perimeters, vec![15.48, 31.42]);
  188. }
  189. }
  190. // ANCHOR_END: unit-tests
  191. fn main() {}