Three-pointer! But what kind?

24

2

From http://en.wikipedia.org/wiki/Triangle: enter image description here


Write a program that takes three 2d coordinate tuples (Cartesian), and classifies what shape these three points describe.

In almost all cases these points will describe a triangle of varying types. In some degenerate cases, the points will either describe a singular point or a straight line. The program will determine which of the following tags apply to the described shape:

  • Point (3 points are co-incident)
  • Line (3 points lie on a straight line - no more than 2 points may be co-incident)
  • Equilateral (3 sides equal, 3 angles equal)
  • Isosceles (2 sides equal, 2 angles equal)
  • Scalene (0 sides equal, 0 angles equal)
  • Right (1 angle exactly π/2 (or 90°))
  • Oblique (0 angles exactly π/2 (or 90°))
  • Obtuse (1 angle > π/2 (or 90°))
  • Acute (3 angles < π/2 (or 90°))

Note that for some described shapes, more than one of the above tags will apply. For example, any right-angled will also either be isosceles or scalene.

Input

  • The program may read the 3 input coordinates from STDIN, command-line, environment variables or whatever method is convenient for your language of choice.
  • The input co-ordinates my be formatted however is convenient for your language of choice. It can be assumed that all input numbers are well-formed with respect to the datatypes you end up using.
  • Nothing can be assumed about the ordering of the input coordinates.

Output

  • The program will output to STDOUT, dialog box or whatever display method is convenient for your language of choice.
  • The output will display all the tags applicable to the shape described by the input coordinates.
  • Tags may be output in any order.

Other Rules

  • Your language's trigonometric libraries/APIs are allowed, but any APIs that specifically calculate triangle types are banned.
  • When determining equality of angles or lengths of sides, you will likely end up comparing floating-point values. Two such values are to be considered "equal" if one is within 1% of the other.
  • Standard “loopholes” which are no longer funny
  • This is , so the shortest answer in bytes wins.

Examples

Input                   Output
(1,2) (1,2) (1,2)       Point
(1,2) (3,4) (5,6)       Line
(0,0) (1,1) (2,0)       Isosceles Right
(0,0) (2,1) (10,1)      Scalene Oblique Obtuse

Digital Trauma

Posted 2014-07-24T23:31:53.960

Reputation: 64 644

4I was going to entitle this "Triangle Tag" but it fell short of the 15-character minimum. – Digital Trauma – 2014-07-24T23:36:06.547

What if two points are identical? – Ypnypn – 2014-07-24T23:51:10.543

@Ypnypn In that case it is a line. – Digital Trauma – 2014-07-24T23:52:50.100

Triangle Tag­­­ – Derek 朕會功夫 – 2014-07-24T23:57:24.227

(Minimum character counts is for loser :v) – Derek 朕會功夫 – 2014-07-24T23:58:26.643

2There is a problem with "Acute" definition ? it's impossible that all angles are greater than PI/2 ? – Arnaud – 2014-07-25T01:29:48.043

@SuperChafouin Oops - good catch! I've fixed it now. – Digital Trauma – 2014-07-25T01:31:43.507

Does it matter how we treat invalid inputs? (i.e. a word, 2 or 4 coordinates, etc.) – NinjaBearMonkey – 2014-07-25T19:43:26.600

@hsl No you don't need to worry about invalid inputs. I think the 2nd part of the input rules explains this. – Digital Trauma – 2014-07-25T19:59:29.070

For any equilateral triangle, should it also output "isosceles"? It technically satisfies the conditions – Kyle McCormick – 2014-07-27T20:30:50.783

@KyleMcCormick I'd prefer that equilateral and isosceles are mutually exclusive. But since the original spec was a bit ambiguous in this respect, I will accept it either way. – Digital Trauma – 2014-07-28T17:13:13.063

Answers

10

C (451 bytes)

Uses only squared lengths and slopes.

p[2],q[2],r[2];z(c){char*y[]={"Line","Point","Isosceles ","Equilateral ","Scalene ","Right","Oblique ","Acute","Obtuse"};printf(y[c]);}d(int*a,int*b){int c=*a++-*b++,e=*a-*b;return c*c+e*e;}main(){scanf("%d%d%d%d%d%d",p,p+1,q,q+1,r,r+1);int a=d(p,q),b=d(q,r),c=d(r,p),e=!a+!b+!c,f=(a==b)+(b==c)+(c==a),g=a>b&&b>c?a:b>c?b:c,h=g^a?g^b?a+b:c+a:b+c;e?z(e/2):(1[q]-1[p])*(*r-*q)^(1[r]-1[q])*(*q-*p)?f?z(2+f/2),f-1&&z(2):z(4),h^g?z(6),z(7+(h<g)):z(5):z(0);}

Ungolfed (and ternary operator replaced with if/else):

int p[2],q[2],r[2];

void print(c){
    char *y[]={"Line","Point","Isosceles ","Equilateral ","Scalene ","Right","Oblique ","Acute","Obtuse"};
    printf(y[c]);
}
squared_distance(int *a,int *b){
    int c = *a++ - *b++, e = *a - *b;
    return c*c+e*e;
}
main(){
    scanf("%d%d%d%d%d%d",p,p+1,q,q+1,r,r+1); // read in coordinates
    int a = squared_distance(p,q),b = squared_distance(q,r),c = squared_distance(r,p),
    e=!a+!b+!c, // number of sides of length 0
    f=(a==b)+(b==c)+(c==a), // number of equal-length pairs
    g = a > b && b > c ? a : (b > c ? b : c), // longest side
    h = g != a ? g != b ? a + b : c + a : b + c; // sum of squares of length of other two sides
    if(e)
        print(e/2); // 1 side of len 0: line, 3 sides: point
    // comparing slopes PQ and QR
    else if((q[1]-p[1])*(*r-*q) != (r[1]-q[1])*(*q-*p)){ // not line
        if(f){
            print(2+f/2); // 1 pair of equal length sides: isosceles, 3: equilateral
            if(f-1) print(2); // equilateral therefore also isosceles
        }else print(4); // 0: scalene
        if(h!=g){ // a^2+b^2!=c^2: not right
            print(6); // oblique
            print(7+(h<g)); // a^2+b^2<c^2:obtuse, acute otherwise 
        }else print(5); // right
    }else
        print(0); // line
}

Input (through stdin) Format: x y x y x y

ex. 0 0 1 1 2 0 for Isosceles Right

es1024

Posted 2014-07-24T23:31:53.960

Reputation: 8 953

@digitaltrauma ./triangle <<< "1 2 1 2 1 2" should be used, with the quotes. – es1024 – 2014-07-25T21:55:04.620

Yes, of course, sorry about that. Nice answer. I particularly like that you were able to avoid floats, and thus not have to worry about the within 1% equality rule thing. +1 – Digital Trauma – 2014-07-25T22:02:40.120

3

C,333

z,c,r,b,s,i,t[14],g[14];
main(){ 
  for(;i<14;i++){
    g[i]=r=t[(i+2)%6]-t[i%6];r*=r;t[i|1]+=r;
    i<6&&scanf("%d",t+i);
    i>7&&(b<t[i]&&(b=t[i]),s+=t[i],z+=!t[i],c+=t[i]==t[i-2]);  
  }

  if(g[6]*g[9]==g[8]*g[7])puts(z==6?"point":"line");else
    printf(b*2==s?"right ":"oblique %s",b*2>s?"obtuse ":"acute "),puts(c>3?c>5?"equilateral":"isosceles":"scalene");
}

I left the whitespace in for the moment. This works but could probably do with some tidying up and golfing. Similar math to @es1024's answer, but uses a loop and arrays. Input format x y x y x y

Variables

t[] stores both the input and the squares of the lengths. By the end of the program it looks like the table below (increasing the number of iterations of the loop would lead to indefinite repitition of the squared lengths.) At the start of the loop squares of lengths (garbage as not all the data is available) are needlessly stored in cells 1,3 and 5, but are promptly overwritten by scanf. Useful data is written to z,b,c ahd s when i=9,11,13 (t[i] and t[i-2] are accessed.)

01 23 45 67 89 1011 1213
aa bb cc  a  b    c    a
xy xy xy  L  L    L    L

g[] was added late on to hold the dx and dy values needed for slope calculation. The only cells used are 6 through 9 (0 through 5 are unreliable as not all the data is available when they are written.) If g[6]/g[7]==g[8]/g[9] the slopes of 2 lines are equal and the triangle is just a line (or a point.) The equation is rearranged in the program to avoid division.

ris an intermediate value used for squaring

zcounts the number of sides of length zero. It has an offset of +3 because the loop reads 3 blank cells in t[].

ccounts the number of sides that are of identical length. It also has an offset of +3. Note that side a is written to t[] twice in order to be able to check a=b,b=c,c=a.

bis the biggest length of a side, squared. sis the sum of the squares of all sides.

Note that comparing side lengths A^2+B^2+C^2 with 2*B^2 is the same as comparing A^2+C^2 with B^2 (just subtract B^2 from both sides.) Thus if B^2=A^2+C^2 it is a right triangle. if B^2 is greater it is obtuse, if smaller it is acute.

Level River St

Posted 2014-07-24T23:31:53.960

Reputation: 22 049

Based on the diagram in the question, an equilateral triangle should also be classified as an isosceles triangle. (On the other hand, it's impossible to create an equilateral triangle with integer coordinates.) – es1024 – 2014-07-26T02:14:47.773

@es1024 the triangle (0,0) (4,7) (8,0) gets so close (squared side lengths 64,65,65). It's a handy approximation if you want to draw 60 degree angles (drawing snowflakes per one of my other answers, making your own isometric dot paper, or drawing clocks.) It's probably impossible to get a perfect match with floats too. If and when I revise this code I may add a 1% tolerance to the comparison, as described in the question. – Level River St – 2014-07-26T09:29:53.967

2

Golfscript (175 bytes)

~..|,({.)2$([\;\]@(;]{{~}/@- 2?@@- 2?+}%$.{2-1??100*}/-+abs 1<{;"Line"}{.[]|,((["Isosceles ""Scalene "]=\~-+.!["Oblique ""Right "]=\.!\0>-)["Acute ""Obtuse "]=}if}{;"Point "}if

You can test it here (test set included).

Input format:

"[x y][x y][x y]"

Commented version:

~                       # evaluates input string          
..|,(                   # pushes the number of unique coords - 1
{
  .)2$([\;\]@(;]        # makes all 3 possible pairings of coords
  {{~}/@- 2?@@- 2?+}%$  # gets all squares of side lengths 
  .{2-1??100*}/-+abs 1< # 0 if triangle, 1 if line
  {;"Line"}
  {
     .[]|,((["Isosceles ""Scalene "]=\   # removes duplicate side-squares,
                                         #   and use the count to determine
                                         #   if isosceles or scalene (no
                                         #   equilaterals will exist)
     ~-+.!["Oblique ""Right "]=\         # compute a^2 + b^2 - c^2. Use to
                                         #   determine if oblique or right.
                                         #   c = max side length 
     .!\0>-)["Acute ""Obtuse "]=         # use same value to determine if
                                         #   acute, obtuse, or right
  }
  if
}
{;"Point "}
if

NOTE:

The reason my code contains no "equilateral" output is because:

  • OP said "all input numbers are well-formed with respect to the datatypes you end up using"
  • Golfscript does not have floating point numbers - not inherently anyway
  • It's impossible (in a 2-dimensional grid) to have an equilateral triangle with integer coordinates, as proven here.

Kyle McCormick

Posted 2014-07-24T23:31:53.960

Reputation: 3 651

Your notes are correct - that is why I included the rule about "equality" meaning values within 1% – Digital Trauma – 2014-07-28T17:07:13.073

If I'm not mistaken, you said this for floats, not for integers: "..you will likely end up comparing floating-point values. Two such values are to be considered 'equal' if one is within 1% of the other." – Kyle McCormick – 2014-07-29T00:02:53.920

0

Mathematica (313 307 characters)

Golfed:

f@p_:=(P=Print;R=RotateLeft;L=Length;U=Union;If[L@U@p==1,P@"Point",If[Det[Join[#,{1}]&/@p]==0,P@"Line",v=p-R@p;a=MapThread[VectorAngle[#,#2]&,{-v,R@v}];u=L@U[Norm/@v];If[u==1,P@"Equilateral",If[u==2,P@"Isosceles",P@"Scalene"]];If[MemberQ[a,Pi/2],P@"Right",P@"Oblique";If[Max@a>Pi/2,P@"Obtuse",P@"Acute"]]]])

Ungolfed:

f@p_ := (
  P = Print;    (* make aliases for functions used more than once *)
  R = RotateLeft;
  L = Length;
  U = Union;
  If[L@U@p == 1,    (* if all points identical *)
   P@"Point",
   If[Det[Join[#, {1}] & /@ p] == 0,    (* if area is zero *)
    P@"Line",
    v = p - R@p;    (* cyclic vectors *)
    a = MapThread[VectorAngle[#, #2] &, {-v, R@v}];    (* interior angles *)
    u = L@U[Norm /@ v];    (* number of unique side lengths *)
    If[u == 1,
     P@"Equilateral",
     If[u == 2,
      P@"Isosceles",
      P@"Scalene"
      ]
     ];
    If[MemberQ[a, Pi/2],
     P@"Right",
     P@"Oblique";
     If[Max@a > Pi/2,
      P@"Obtuse",
      P@"Acute"
      ]
     ]
    ]
   ]
  )

The input format is a list of points, upon which the function is called:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points

phosgene

Posted 2014-07-24T23:31:53.960

Reputation: 1 145

I'm a mathematica rookie. Where can I download an interpreter/compiler, or try this online (for free, of course ;-))? – Digital Trauma – 2014-07-28T17:16:25.970

I've never used it, but Wolfram has a 'CDF Player' browser application which claims to run Mathematica files stored in the CDF format, but not regular notebooks. Found here: http://www.wolfram.com/cdf-player/ Beyond that, there's the main program, which I believe is free for 30 days.

– phosgene – 2014-07-28T19:58:48.513