HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Decide whether a triangle is isosceles or not

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
isoscelestriangledecidewhethernot

Problem

I think I have pretty much the best code you can get when it comes to this particular task, but I'm always open to improvement. This code will check everything I can think of to make sure that it will actually work and if it is an isosceles triangle. It will make sure that none of the sides are 0, it will check whether the lengths of the sides are even possible and it will make sure that the user actually inputted a number.

```
import time

print("I am going to ask you for three numbers. These numbers can be integers or decimals. They will be the sides of a triangle, and I will tell you if it is an isosceles triangle or not.")
time.sleep(2.5)
while 2>1:
try:
side1 = float(input("How long is the first side of the triangle? "))
if float(side1) == 0.0:
print("This is an impossible triangle!")
time.sleep(2.5)
break
else:
0
except ValueError:
print("That's not a number...")
time.sleep(2.5)
break
time.sleep(0.25)
try:
side2 = float(input("How long is the second side? "))
if float(side2) == 0.0:
print("This is an impossible triangle!")
time.sleep(2.5)
break
else:
0
except ValueError:
print("That's not a number...")
time.sleep(2.5)
break
time.sleep(0.25)
try:
side3 = float(input("How long is the third side? "))
if float(side3) == 0.0:
print("This is an impossible triangle!")
time.sleep(2.5)
break
else:
0
except ValueError:
print("That's not a number...")
time.sleep(2.5)
break
time.sleep(1)
if side1 == side2 == side3:
print("This is not an isosceles triangle!")
elif float(side1)>float(side2) and float(side1)>float(side3):
if (float(side2)+float(side3))float(side1) and float(side2)>float(side3):
if (float(side1)+float(side3))

Solution

It's a little hard to approach your code because you have a large amount of repetition. Modularize and reuse individual parts.

Example framework

One of the other answers goes a long way to improving it with a Triangle class, but I suspect that that's a little farther ahead of where you are right now. Here's an easy framework to consider that's essentially modular.

def prompt_float():
    """Prompt the user for a float until they provide a valid one. Return that float."""

def is_valid_side(side):
    """side is a float representing the side of a triangle. Return True iff it is > 0."""

def has_isosceles_relationship(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    exactly two are equal.
    """

    # Hint: use a set here rather than many nearly identical comparisons

def is_possible_triangle(sides):
    """
    sides is a list of 3 floats representing the sides of an isosceles triangle. Return
    True iff the triangle is possible. A possible triangle is defined as one whose two
    equal sides are at least the length of its third side.
    """

    # Hint: sort sides and determine which side is unique, then do one comparison

def evaluate_isosceles_triangle(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    that triangle is an isosceles triangle. (Equilateral should fail.)
    """

    # Validate individual sides
    for side in sides:
        if not is_valid_side(side):
            return False

    # Validate basic isosceles relationship
    if not has_isosceles_relationship(sides):
        return False

    # Validate that the triangle's dimensions are possible
    if not is_possible_triangle(sides):
        return False

    # Otherwise we are good
    return True

# Execute when this module is run directly
if __name__ == "__main__":

    # Prompt for three sides
    sides = []
    for _ in range(3):
       sides.append(prompt_float())

    # Evaluate and print result
    result = evaluate_isosceles_triangle(sides)
    if result:
        print("That is an isosceles triangle!")
    else:
        print("That is not an isosceles triangle.")


As has also been said, you can dispense with the time.sleep() calls and empty else blocks.

Doctesting

At some point you should also write unit tests for these functions. I think it's a bit much at once to put them in here, but for now you could consider at least adding simpler doctests to be sure the functions work the way they should with sample inputs. Here's an example:

def has_isosceles_relationship(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    exactly two are equal.

    >>> has_isosceles_relationship([1, 2, 3])
    False
    >>> has_isosceles_relationship([2, 2, 3])
    True
    >>> has_isosceles_relationship([3, 2, 3])
    True
    >>> has_isosceles_relationship([2, 2, 2])
    False
    """


Here we test four cases: all 3 sides different; 2/3 sides equal; 2/3 sides equal, not adjacent; 3/3 equal. You can run these docstring examples automatically by including this code at the bottom of a file:

if __name__ == "__main__":
    import doctest
    doctest.testmod()


Why modular?

A word on modularity and why this is being proposed to you by several people. There are several benefits to breaking code into smaller parts. Among them:

-
Less repetition. By giving a block of lines a name, i.e. making it a function, you can call it more than once without repeating those lines. (In your code, there are actually stronger ways to remove repetition, but it still helps.)

-
More organization. By breaking up and naming the various functions your code has, you get a better sense of how your program works. This also helps people understand your code (including yourself three months from now!), and that helps maintain it.

-
Easier documentation and testing. Again, by isolating functions, you can target them directly with more detailed comments and more precise tests. This also means that if something breaks, you know what broke and where.

-
Clearer abstraction. Think about whether your code does anything more than once, and extract common parts. For example, you have three blocks prompting for sides. This is really just one kind of thing — prompting for a float. I didn't do it above, but you could maintain the distinct nature of these blocks via parametrization: add a message argument to the prompt_float function that gets printed with input, so that you can still have different behaviour each time.

These are all interconnected and there are other ways to see the benefits. But the key thing is that you give yourself the power to take your program apart, reconstruct it, analyze it, change your mind about individual things, and more. One of the other answers says that modularity would be "too much abstraction" for an easy problem like this. But you have to get your

Code Snippets

def prompt_float():
    """Prompt the user for a float until they provide a valid one. Return that float."""

def is_valid_side(side):
    """side is a float representing the side of a triangle. Return True iff it is > 0."""

def has_isosceles_relationship(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    exactly two are equal.
    """

    # Hint: use a set here rather than many nearly identical comparisons

def is_possible_triangle(sides):
    """
    sides is a list of 3 floats representing the sides of an isosceles triangle. Return
    True iff the triangle is possible. A possible triangle is defined as one whose two
    equal sides are at least the length of its third side.
    """

    # Hint: sort sides and determine which side is unique, then do one comparison

def evaluate_isosceles_triangle(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    that triangle is an isosceles triangle. (Equilateral should fail.)
    """

    # Validate individual sides
    for side in sides:
        if not is_valid_side(side):
            return False

    # Validate basic isosceles relationship
    if not has_isosceles_relationship(sides):
        return False

    # Validate that the triangle's dimensions are possible
    if not is_possible_triangle(sides):
        return False

    # Otherwise we are good
    return True


# Execute when this module is run directly
if __name__ == "__main__":

    # Prompt for three sides
    sides = []
    for _ in range(3):
       sides.append(prompt_float())

    # Evaluate and print result
    result = evaluate_isosceles_triangle(sides)
    if result:
        print("That is an isosceles triangle!")
    else:
        print("That is not an isosceles triangle.")
def has_isosceles_relationship(sides):
    """
    sides is a list of 3 floats representing the sides of a triangle. Return True iff
    exactly two are equal.

    >>> has_isosceles_relationship([1, 2, 3])
    False
    >>> has_isosceles_relationship([2, 2, 3])
    True
    >>> has_isosceles_relationship([3, 2, 3])
    True
    >>> has_isosceles_relationship([2, 2, 2])
    False
    """
if __name__ == "__main__":
    import doctest
    doctest.testmod()

Context

StackExchange Code Review Q#159173, answer score: 11

Revisions (0)

No revisions yet.