Triangle

1. Readme

三角形

确定三角形是等边、等腰还是不等边三角形.

一个等边的三角形,三条边都有相同的长度。

一个等腰的三角形,至少两边相同的长度。(有时它被指定为两边长度完全相同,但是为了这个练习的目的,我们的说法是,至少两边。)

不等边的三角形的两边各有不同的长度。

笔记

为了能形成三角形,所有的边都必须的长度>0,并且任何两边的长度之和必须大于或等于第三边的长度。见不等三角形.

挖深点

两边长度之和,是等于第三边,就叫做退化三角形 - 因它有零面积,看起来像一条直线。随意添加你自己的代码/测试来检查退化三角形.

Rust 中 三角形帮助

实现这一点可以采取多种形式。以下是一些可以帮助你的话题,这取决于你采取的方法.

或者也许你会想出一种不用那些方法的方法!

非整数长度

基础练习测试三角形的边,都是整数的识别。然而,一些三角形不能用纯整数表示。一个简单的例子是一个直角三角形(也是等边三角形,两等边分开 90 度),其等边都有 1 的长度。它的斜边是 2 的平方根,这是一个无理数: 没有简单的乘法,可以将这个数表示为整数。

重写分析函数来处理整数和浮点情况,老乏味啦,特别是对于所有潜在的整数和浮点类型的情况来说:如给定的 8, 16, 32、64 和 128 位宽度的已签名和未签名的变体,甚至再考虑浮点数,就多出了 10 个根本上相同的代码,!

这有个更好的方法:generics。 把你的三角形重写为Triangle<T>,这样您就可以编写一次代码,并将生成所有这些专门化的工作交给编译器。注意,为了使用数学运算,您需要将泛型类型限制为,支持使用特征的那些运算的类型。

有些加分测试,这些测试,能测试您在浮点数字上的实现。若要启用它们,请使用generic特征标记,像这样:

cargo test --features generic

资源

Ruby-科恩三角形项目,第 1 和 2 部分http://rubykoans.com

2. 开始你的表演

pub struct Triangle;

impl Triangle {
   pub fn build(sides: [u64; 3]) -> Option<Triangle> {
       unimplemented!("Construct new Triangle from following sides: {:?}. Return None if the sides are invalid.", sides);
   }

   pub fn is_equilateral(&self) -> bool {
       unimplemented!("Determine if the Triangle is equilateral.");
   }

   pub fn is_scalene(&self) -> bool {
       unimplemented!("Determine if the Triangle is scalene.");
   }

   pub fn is_isosceles(&self) -> bool {
       unimplemented!("Determine if the Triangle is isosceles.");
   }
}

3. 测试代码查看


# #![allow(unused_variables)]
#fn main() {
#[test]
fn positive_length_sides_are_ok() {
   let sides = [2, 2, 2];
   let triangle = Triangle::build(sides);
   assert!(triangle.is_some());
}

#[test]
//#[ignore]
fn zero_length_sides_are_illegal() {
   let sides = [0, 0, 0];
   let triangle = Triangle::build(sides);
   assert!(triangle.is_none());
}

#[test]
//#[ignore]
fn equilateral_triangles_have_equal_sides() {
   let sides = [2, 2, 2];
   let triangle = Triangle::build(sides).unwrap();
   assert!(triangle.is_equilateral());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn larger_equilateral_triangles_have_equal_sides() {
   let sides = [10, 10, 10];
   let triangle = Triangle::build(sides).unwrap();
   assert!(triangle.is_equilateral());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn isosceles_triangles_have_two_equal_sides_one() {
   let sides = [3, 4, 4];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(triangle.is_isosceles());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn isosceles_triangles_have_two_equal_sides_two() {
   let sides = [4, 4, 3];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(triangle.is_isosceles());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn isosceles_triangles_have_two_equal_sides_three() {
   let sides = [4, 3, 4];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(triangle.is_isosceles());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn isosceles_triangles_have_two_equal_sides_four() {
   let sides = [4, 7, 4];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(triangle.is_isosceles());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
fn scalene_triangle_has_no_equal_sides_one() {
   let sides = [3, 4, 5];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(!triangle.is_isosceles());
   assert!(triangle.is_scalene());
}

#[test]
//#[ignore]
fn scalene_triangle_has_no_equal_sides_two() {
   let sides = [5, 4, 6];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(!triangle.is_isosceles());
   assert!(triangle.is_scalene());
}

#[test]
//#[ignore]
fn scalene_triangle_has_no_equal_sides_three() {
   let sides = [10, 11, 12];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(!triangle.is_isosceles());
   assert!(triangle.is_scalene());
}

#[test]
//#[ignore]
fn scalene_triangle_has_no_equal_sides_four() {
   let sides = [5, 4, 2];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(!triangle.is_isosceles());
   assert!(triangle.is_scalene());
}

#[test]
//#[ignore]
fn sum_of_two_sides_must_equal_or_exceed_the_remaining_side_one() {
   let sides = [7, 3, 2];
   let triangle = Triangle::build(sides);
   assert!(triangle.is_none());
}

#[test]
//#[ignore]
fn sum_of_two_sides_must_equal_or_exceed_the_remaining_side_two() {
   let sides = [1, 1, 3];
   let triangle = Triangle::build(sides);
   assert!(triangle.is_none());
}

#[test]
//#[ignore]
#[cfg(feature = "generic")]
fn scalene_triangle_with_floating_point_sides() {
   let sides = [0.4, 0.6, 0.3];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(!triangle.is_isosceles());
   assert!(triangle.is_scalene());
}

#[test]
//#[ignore]
#[cfg(feature = "generic")]
fn equilateral_triangles_with_floating_point_sides() {
   let sides = [0.2, 0.2, 0.2];
   let triangle = Triangle::build(sides).unwrap();
   assert!(triangle.is_equilateral());
   assert!(!triangle.is_scalene());
}

#[test]
//#[ignore]
#[cfg(feature = "generic")]
fn isosceles_triangle_with_floating_point_sides() {
   let sides = [0.3, 0.4, 0.4];
   let triangle = Triangle::build(sides).unwrap();
   assert!(!triangle.is_equilateral());
   assert!(triangle.is_isosceles());
   assert!(!triangle.is_scalene());
}

#}

4. 答案


# #![allow(unused_variables)]
#fn main() {
use std::ops::Add;

pub struct Triangle<T> {
   sides: [T; 3],
}

impl<T> Triangle<T>
where
   T: Copy + PartialEq + PartialOrd + Add<Output = T> + Default,
{
   fn valid_sides(&self) -> bool {
       (self.sides.iter().all(|&s| s > T::default()))
           && (self.sides[0] + self.sides[1] >= self.sides[2])
           && (self.sides[1] + self.sides[2] >= self.sides[0])
           && (self.sides[2] + self.sides[0] >= self.sides[1])
   }

   fn count_distinct_pairs(&self) -> usize {
       [(0, 1), (0, 2), (1, 2)]
           .iter()
           .map(|&(a, b)| if self.sides[a] != self.sides[b] { 1 } else { 0 })
           .sum()
   }

   pub fn build(sides: [T; 3]) -> Option<Triangle<T>> {
       let t = Triangle { sides: sides };

       if t.valid_sides() {
           Some(t)
       } else {
           None
       }
   }

   pub fn is_equilateral(&self) -> bool {
       self.count_distinct_pairs() == 0
   }

   pub fn is_isosceles(&self) -> bool {
       self.count_distinct_pairs() == 2
   }

   pub fn is_scalene(&self) -> bool {
       self.count_distinct_pairs() == 3
   }
}

#}



填充/相关