# The Triangle Question

I’m currently entertaining myself by working through the Ruby Koans which I’d somehow missed over the last few years.

Most of the questions are fairly mundane like

```
def test_iterating_with_each
array = [1, 2, 3]
sum = 0
array.each do |item|
sum += item
end
assert_equal __, sum
end
```

but the “Triangle question is a bit of fun. You’re given a test like:

```
class AboutTriangleProject < Neo::Koan
def test_equilateral_triangles_have_equal_sides
assert_equal :equilateral, triangle(2, 2, 2)
assert_equal :equilateral, triangle(10, 10, 10)
end
def test_isosceles_triangles_have_exactly_two_sides_equal
assert_equal :isosceles, triangle(3, 4, 4)
assert_equal :isosceles, triangle(4, 3, 4)
assert_equal :isosceles, triangle(4, 4, 3)
assert_equal :isosceles, triangle(10, 10, 2)
end
def test_scalene_triangles_have_no_equal_sides
assert_equal :scalene, triangle(3, 4, 5)
assert_equal :scalene, triangle(10, 11, 12)
assert_equal :scalene, triangle(5, 4, 2)
end
end
```

and told to implement the `triangle`

method

```
# Triangle Project Code.
# Triangle analyzes the lengths of the sides of a triangle
# (represented by a, b and c) and returns the type of triangle.
#
# It returns:
# :equilateral if all sides are equal
# :isosceles if exactly 2 sides are equal
# :scalene if no sides are equal
#
# The tests for this method can be found in
# about_triangle_project.rb
# and
# about_triangle_project_2.rb
#
def triangle(a, b, c)
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
```

I started typing `if a == b…`

but quickly realised that there was no branching logic needed at all. All the triangle method needed to do count the number of unique sides so instead of a messy conditional statement like

```
if (a==b and a==c)
value = :equilateral
else
if (a==b or a==c or b==c)
value = :isosceles
else
value = :scalene
end
end
```

…we can just say:

```
def triangle(a, b, c)
sides = [a, b, c]
unique_sides = sides.uniq.length
types = [nil, :equilateral, :isosceles, :scalene]
types[unique_sides]
end
```

This uses the number of unique sides as the array index to determine the triangle type. Even adding the error checking required later, can be done without messy conditionals:

```
def triangle(a, b, c)
sides = [a, b, c].sort
raise TriangleError, "No negative or zero length sides" if sides.any? { |s| s <= 0 }
# Must conform to triangle equality (sum of two shortest sides must exceed the third)
raise TriangleError, "Impossible triangle!" unless (sides[0] + sides[1]) > sides[2]
unique_sides = sides.uniq.length
types = [nil, :equilateral, :isosceles, :scalene]
types[unique_sides]
end
```

I think this would make a good interview question. Not because it’s particularly hard or tricky (interview questions shouldn’t be) but because there are multiple ways to solve it and it encourages a good discussion.

How could we rewrite `if a <= 0 || b <= 0 || c <= 0`

using a block? What are the disadvantages of my array indexing approach? How would you rewrite it to use a `case…when`

structure?

Note: The Koans are about learning and *enlightenment* and are not a test. Don’t set them all as interview test — they’re too long, and easy to “cheat” because the test suite will give you the next expected answer. This triangle question could be extracted though. Also, setting up a Nitrous.io instance for your candidate means they don’t have to set anything up on their own machine.