22
\$\begingroup\$

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
\$\endgroup\$
  • 4
    \$\begingroup\$ I was going to entitle this "Triangle Tag" but it fell short of the 15-character minimum. \$\endgroup\$ – Digital Trauma Jul 24 '14 at 23:36
  • \$\begingroup\$ What if two points are identical? \$\endgroup\$ – Ypnypn Jul 24 '14 at 23:51
  • \$\begingroup\$ @Ypnypn In that case it is a line. \$\endgroup\$ – Digital Trauma Jul 24 '14 at 23:52
  • \$\begingroup\$ Triangle Tag­­­ \$\endgroup\$ – Derek 朕會功夫 Jul 24 '14 at 23:57
  • 2
    \$\begingroup\$ There is a problem with "Acute" definition ? it's impossible that all angles are greater than PI/2 ? \$\endgroup\$ – Arnaud Jul 25 '14 at 1:29
10
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ @digitaltrauma ./triangle <<< "1 2 1 2 1 2" should be used, with the quotes. \$\endgroup\$ – es1024 Jul 25 '14 at 21:55
  • \$\begingroup\$ 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 \$\endgroup\$ – Digital Trauma Jul 25 '14 at 22:02
3
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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.) \$\endgroup\$ – es1024 Jul 26 '14 at 2:14
  • \$\begingroup\$ @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. \$\endgroup\$ – Level River St Jul 26 '14 at 9:29
2
\$\begingroup\$

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.
\$\endgroup\$
  • \$\begingroup\$ Your notes are correct - that is why I included the rule about "equality" meaning values within 1% \$\endgroup\$ – Digital Trauma Jul 28 '14 at 17:07
  • \$\begingroup\$ 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." \$\endgroup\$ – Kyle McCormick Jul 29 '14 at 0:02
0
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ I'm a mathematica rookie. Where can I download an interpreter/compiler, or try this online (for free, of course ;-))? \$\endgroup\$ – Digital Trauma Jul 28 '14 at 17:16
  • \$\begingroup\$ 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: wolfram.com/cdf-player Beyond that, there's the main program, which I believe is free for 30 days. \$\endgroup\$ – phosgene Jul 28 '14 at 19:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.