Três ponteiros! Mas que tipo?

24

De http://en.wikipedia.org/wiki/Triangle : insira a descrição da imagem aqui


Escreva um programa que use três tuplas de coordenadas 2D (cartesianas) e classifique o formato que esses três pontos descrevem.

Em quase todos os casos, esses pontos descreverão um triângulo de tipos variados. Em alguns casos degenerados, os pontos descrevem um ponto singular ou uma linha reta. O programa determinará quais das seguintes tags se aplicam à forma descrita:

  • Ponto (3 pontos são co-incidentes)
  • Linha (3 pontos em uma linha reta - não mais que 2 pontos podem ser co-incidentes)
  • Equilateral (3 lados iguais, 3 ângulos iguais)
  • Isósceles (2 lados iguais, 2 ângulos iguais)
  • Escaleno (0 lados iguais, 0 ângulos iguais)
  • Direita (1 ângulo exatamente π / 2 (ou 90 °))
  • Oblíquo (0 ângulo exatamente π / 2 (ou 90 °))
  • Obtuso (1 ângulo> π / 2 (ou 90 °))
  • Agudo (3 ângulos <π / 2 (ou 90 °))

Observe que, para algumas formas descritas, mais de uma das tags acima será aplicada. Por exemplo, qualquer ângulo reto também será isósceles ou escaleno.

Entrada

  • O programa pode ler as 3 coordenadas de entrada de STDIN, linha de comando, variáveis ​​de ambiente ou qualquer outro método conveniente para o seu idioma de escolha.
  • A entrada coordena minha formatação, mas é conveniente para o seu idioma de escolha. Pode-se supor que todos os números de entrada sejam bem formados com relação aos tipos de dados que você acaba usando.
  • Nada pode ser assumido sobre a ordem das coordenadas de entrada.

Saída

  • O programa exibirá STDOUT, caixa de diálogo ou qualquer outro método de exibição conveniente para o seu idioma de escolha.
  • A saída exibirá todos os tags aplicáveis ​​à forma descrita pelas coordenadas de entrada.
  • As tags podem ser exibidas em qualquer ordem.

Outras regras

  • As bibliotecas / APIs trigonométricas do seu idioma são permitidas, mas quaisquer APIs que calculam especificamente tipos de triângulo são proibidas.
  • Ao determinar a igualdade de ângulos ou comprimentos de lados, você provavelmente acabará comparando valores de ponto flutuante. Dois desses valores devem ser considerados "iguais" se um estiver dentro de 1% do outro.
  • “Brechas” padrão que não são mais engraçadas
  • Isso é , então a resposta mais curta em bytes vence.

Exemplos

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
Trauma Digital
fonte
4
Eu estava intitulando esse " Triangle Tag ", mas ficou aquém do mínimo de 15 caracteres.
Digital Trauma
E se dois pontos forem idênticos?
Ypnypn
@Ypnypn Nesse caso, é uma linha.
Digital Trauma
Triangle Tag
Derek,
2
Há um problema com a definição "Aguda"? é impossível que todos os ângulos sejam maiores que PI / 2?
Arnaud

Respostas:

10

C (451 bytes)

Usa apenas comprimentos e inclinações ao quadrado.

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 (e operador ternário substituído por 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
}

Formato de entrada (através de stdin): xyxyxy

ex. 0 0 1 1 2 0 para Isosceles Right

es1024
fonte
@digitaltrauma ./triangle <<< "1 2 1 2 1 2"deve ser usado, com as aspas.
es1024
Sim, claro, desculpe por isso. Boa resposta. Eu particularmente gosto que você foi capaz de evitar carros alegóricos e, portanto, não precisa se preocupar com a regra de igualdade de 1%. +1
Trauma digital
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");
}

Deixei o espaço em branco por enquanto. Isso funciona, mas provavelmente poderia funcionar com algumas tarefas de arrumação e golfe. Matemática semelhante à @es1024resposta, mas usa um loop e matrizes. Formato de entradax y x y x y

Variáveis

t[]armazena a entrada e os quadrados dos comprimentos. No final do programa, ele se parece com a tabela abaixo (aumentar o número de iterações do loop levaria a uma repetição indefinida dos comprimentos quadrados). No início do loop, quadrados de comprimentos (lixo, pois nem todos os dados estão disponíveis ) são desnecessariamente armazenados nas células 1,3 e 5, mas são imediatamente substituídos por scanf.Dados úteis são gravados em z,b,cahd squando i= 9,11,13 ( t[i]e t[i-2]são acessados.)

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

g[]foi adicionado tarde para manter os valores dx e dy necessários para o cálculo da inclinação. As únicas células usadas são de 6 a 9 (0 a 5 não são confiáveis, pois nem todos os dados estão disponíveis quando são gravados.) Se g[6]/g[7]==g[8]/g[9]as inclinações de 2 linhas forem iguais e o triângulo for apenas uma linha (ou um ponto). A equação é reorganizado no programa para evitar divisão.

ré um valor intermediário usado para quadratura

zconta o número de lados do comprimento zero. Ele tem um deslocamento de +3 porque o loop lê 3 células em branco t[].

cconta o número de lados de comprimento idêntico. Ele também tem um deslocamento de +3. Observe que o lado aé gravado t[]duas vezes para poder verificar a = b, b = c, c = a.

bé o maior comprimento de um lado ao quadrado. sé a soma dos quadrados de todos os lados.

Observe que comparar comprimentos laterais A ^ 2 + B ^ 2 + C ^ 2 com 2 * B ^ 2 é o mesmo que comparar A ^ 2 + C ^ 2 com B ^ 2 (basta subtrair B ^ 2 de ambos os lados.) se B ^ 2 = A ^ 2 + C ^ 2, é um triângulo retângulo. se B ^ 2 é maior, é obtuso; se menor, é agudo.

Level River St
fonte
Com base no diagrama da pergunta, um triângulo equilátero também deve ser classificado como um triângulo isósceles. (Por outro lado, é impossível criar um triângulo equilátero com coordenadas inteiras.)
es1024
@ es1024 o triângulo (0,0) (4,7) (8,0) fica tão próximo (comprimentos laterais ao quadrado 64,65,65). É uma aproximação útil se você deseja desenhar ângulos de 60 graus (desenhar flocos de neve por uma das minhas outras respostas, fazer seu próprio papel isométrico com pontos ou desenhar relógios.) Provavelmente também é impossível obter uma combinação perfeita com os carros alegóricos. Se e quando revisar este código, posso adicionar uma tolerância de 1% à comparação, conforme descrito na pergunta.
Level River St
2

Golfscript (175 bytes)

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

Você pode testá-lo aqui (conjunto de testes incluído).

Formato de entrada:

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

Versão comentada:

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

NOTA:

A razão pela qual meu código não contém saída "equilateral" é porque:

  • A OP disse que "todos os números de entrada são bem formados com relação aos tipos de dados que você acaba usando"
  • O Golfscript não possui números de ponto flutuante - não é inerentemente de qualquer maneira
  • É impossível (em uma grade bidimensional) ter um triângulo equilátero com coordenadas inteiras, como comprovado aqui .
Kyle McCormick
fonte
Suas notas estão corretas - é por isso que incluiu a regra sobre "igualdade" valores que significam dentro de 1%
Trauma Digital
Se não me engano, você disse isso para carros alegóricos, não para números inteiros: "... você provavelmente acabará comparando valores de ponto flutuante. Dois desses valores devem ser considerados 'iguais' se um estiver dentro de 1% do outro . "
Kyle McCormick
0

Mathematica ( 313 307 caracteres)

Golfe:

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

O formato de entrada é uma lista de pontos, sobre os quais a função é chamada:

points = {{x1,y1},{x2,y2},{x3,y3}};
f@points
fosgênio
fonte
Eu sou um novato mathematica. Onde posso baixar um intérprete / compilador ou tentar isso on-line (de graça, é claro ;-))?
Digital Trauma
Eu nunca o usei, mas o Wolfram possui um aplicativo de navegador 'CDF Player' que afirma executar arquivos do Mathematica armazenados no formato CDF, mas não notebooks comuns. Encontrado aqui: wolfram.com/cdf-player Além disso, existe o programa principal, que eu acredito que é gratuito por 30 dias.
phosgene