Ruby developer. CTO. Swimmer. Always trying to write more

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.