Три-указатель! Но что это за вид?

24

С http://en.wikipedia.org/wiki/Triangle : введите описание изображения здесь


Напишите программу, которая берет три двумерных координатных кортежа (декартовых) и классифицирует, какую форму описывают эти три точки.

Почти во всех случаях эти точки будут описывать треугольник различных типов. В некоторых вырожденных случаях точки будут описывать особую точку или прямую линию. Программа определит, какие из следующих тегов применимы к описанной фигуре:

  • Точка (3 балла являются со-инцидентом)
  • Линия (3 точки лежат на прямой линии - может быть не более 2 точек)
  • Равносторонний (3 стороны равны, 3 угла равны)
  • Равнобедренно (2 стороны равны, 2 угла равны)
  • Scalene (0 сторон равны, 0 углов равны)
  • Право (1 угол точно π / 2 (или 90 °))
  • Наклонный (0 углов точно π / 2 (или 90 °))
  • Тупой (1 угол> π / 2 (или 90 °))
  • Острый (3 угла <π / 2 (или 90 °))

Обратите внимание, что для некоторых описанных фигур будет применяться более одного из приведенных выше тегов. Например, любой прямоугольник также будет равнобедренным или разносторонним.

вход

  • Программа может считывать 3 входные координаты из STDIN, командной строки, переменных среды или любого другого метода, удобного для вашего языка.
  • Входные координаты могут быть отформатированы, однако это удобно для вашего языка. Можно предположить, что все входные числа правильно сформированы по отношению к типам данных, которые вы в конечном итоге используете.
  • Ничего нельзя предположить о порядке ввода входных координат.

Выход

  • Программа выведет на STDOUT, диалоговое окно или любой другой способ отображения, подходящий для вашего языка.
  • Выходные данные будут отображать все теги, применимые к форме, описанной входными координатами.
  • Теги могут быть выведены в любом порядке.

Другие правила

  • Разрешены тригонометрические библиотеки / API вашего языка, но любые API, которые специально рассчитывают типы треугольников, запрещены.
  • При определении равенства углов или длин сторон вы, скорее всего, будете сравнивать значения с плавающей точкой. Два таких значения следует считать «равными», если одно находится в пределах 1% от другого.
  • Стандартные «лазейки», которые больше не смешны
  • Это , поэтому выигрывает самый короткий ответ в байтах.

Примеры

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
Цифровая травма
источник
4
Я собирался дать название этой « Треугольной метке », но она не соответствовала минимуму из 15 символов.
Цифровая травма
Что, если две точки идентичны?
Ypnypn
@Ypnypn В этом случае это строка.
Цифровая травма
Треугольный тег
Дерек 功夫 會 功夫
2
Есть проблема с определением "Острый"? невозможно, чтобы все углы были больше, чем PI / 2?
Арно

Ответы:

10

C (451 байт)

Использует только квадрат длины и уклонов.

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 (и троичный оператор заменен на 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
}

Ввод (через стандартный ввод) Формат: xyxyxy

ех. 0 0 1 1 2 0 для Isosceles Right

es1024
источник
@digitaltrauma ./triangle <<< "1 2 1 2 1 2"следует использовать с кавычками.
es1024
Да, конечно, извините за это. Хороший ответ. Мне особенно нравится, что вам удалось избежать поплавков, и, таким образом, вам не нужно беспокоиться о правиле равенства в пределах 1%. +1
цифровая травма
3

С, 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");
}

Я оставил пустое место на данный момент. Это работает, но, вероятно, можно сделать с некоторой уборкой и игрой в гольф. Аналогичен математическому @es1024ответу, но использует цикл и массивы. Формат вводаx y x y x y

переменные

t[]хранит как вход, так и квадраты длин. К концу программы это выглядит так, как показано в таблице ниже (увеличение количества итераций цикла приведет к неопределенному повторению квадратов длин.) В начале цикла квадраты длин (мусор, так как не все данные доступны ) без необходимости хранятся в ячейках 1,3 и 5, но быстро перезаписываются. scanf.Полезные данные записываются в z,b,cahd, sкогда i= 9,11,13 ( t[i]и t[i-2]к ним обращаются).

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

g[]был добавлен позднее для хранения значений dx и dy, необходимых для расчета наклона. Используются только ячейки от 6 до 9 (от 0 до 5 ненадежны, так как не все данные доступны при их записи.) Если g[6]/g[7]==g[8]/g[9]наклоны 2 линий равны, а треугольник - это просто линия (или точка). Уравнение переставлен в программе, чтобы избежать деления.

rявляется промежуточным значением, используемым для возведения в квадрат

zсчитает количество сторон длины ноль. Он имеет смещение +3, потому что цикл читает 3 пустых ячейки в t[].

cсчитает количество сторон одинаковой длины. Он также имеет смещение +3. Обратите внимание, что сторона aзаписывается t[]дважды, чтобы иметь возможность проверить a = b, b = c, c = a.

bсамая большая длина стороны в квадрате. sэто сумма квадратов всех сторон.

Обратите внимание, что сравнение длин сторон A ^ 2 + B ^ 2 + C ^ 2 с 2 * B ^ 2 аналогично сравнению A ^ 2 + C ^ 2 с B ^ 2 (просто вычтите B ^ 2 с обеих сторон). Таким образом, если B ^ 2 = A ^ 2 + C ^ 2, это прямоугольный треугольник. если B ^ 2 больше, он тупой, если меньше, то острый.

Уровень реки St
источник
Основываясь на диаграмме в вопросе, равносторонний треугольник также должен быть классифицирован как равнобедренный треугольник. (С другой стороны, невозможно создать равносторонний треугольник с целочисленными координатами.)
es1024
@ es1024 треугольник (0,0) (4,7) (8,0) оказывается так близко (длина сторон в квадрате 64,65,65). Это удобное приближение, если вы хотите нарисовать 60-градусные углы (рисование снежинок на одном из моих других ответов, создание собственной бумаги изометрической точки или рисование часов.) Вероятно, невозможно получить идеальное совпадение и с плавающей точкой. Если и когда я пересмотрю этот код, я могу добавить допуск 1% к сравнению, как описано в вопросе.
Уровень Ривер Сент-
2

Golfscript (175 байт)

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

Вы можете проверить это здесь (тестовый набор включен).

Формат ввода:

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

Комментируемая версия:

~                       # 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

НОТА:

Причина, по которой мой код не содержит "равносторонний" вывод, заключается в том, что:

  • ОП сказал, что "все входные числа правильно сформированы относительно типов данных, которые вы в конечном итоге используете"
  • Golfscript не имеет чисел с плавающей запятой - по сути, не в любом случае
  • Невозможно (в двумерной сетке) иметь равносторонний треугольник с целочисленными координатами, как доказано здесь .
Кайл Маккормик
источник
Ваши записи верны - именно поэтому я включил правило о значениях «равенство» в пределах 1%
Цифровая травма
Если я не ошибаюсь, вы сказали это для чисел с плавающей запятой, а не для целых чисел: «... вы, скорее всего, в конечном итоге будете сравнивать значения с плавающей запятой. Два таких значения следует считать« равными », если одно находится в пределах 1% от другого «.
Кайл Маккормик
0

Mathematica ( 313 307 символов)

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"
      ]
     ]
    ]
   ]
  )

Формат ввода представляет собой список точек, по которым вызывается функция:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points
фосген
источник
Я новичок математики. Где я могу скачать интерпретатор / компилятор или попробовать это онлайн (бесплатно, конечно ;-))?
Цифровая травма
Я никогда не использовал его, но у Вольфрама есть браузерное приложение CDF Player, которое утверждает, что оно запускает файлы Mathematica, хранящиеся в формате CDF, но не обычные записные книжки. Найдено здесь: wolfram.com/cdf-player Кроме того, есть основная программа, которая, я считаю, бесплатна в течение 30 дней.
Фосген