Surface du tétraèdre

16

Le défi

Ce défi est très simple. Étant donné quatre points tridimensionnels, calculez la surface du tétraèdre qu'ils forment. C'est le , donc le code le plus court l'emporte. Les lacunes standard s'appliquent, avec la stipulation supplémentaire que toute fonction intégrée pour effectuer cette tâche étant donné quatre points est interdite.

Vous pouvez supposer que les quatre points seront distincts et seront donnés via STDIN, 1 point par ligne. Chaque point sera composé de trois entiers non signés 16 bits. Le format exact de chaque point peut être modifié si cela facilite les choses, comme trois entiers séparés par des espaces. Cependant, avoir chaque point sur une ligne distincte est obligatoire. La sortie doit être via STDOUT, à au moins 2 décimales.

Pour ceux d'entre vous qui ne connaissent pas, un tétraèdre est un solide tridimensionnel, formé de 4 faces triangulaires.

Exemple

# input (format is up to you, see clarification above)
[23822, 47484, 57901]
[3305, 23847, 42159]
[19804, 11366, 14013]
[52278, 28626, 52757]

# output
2932496435.95

Veuillez laisser une note si vous remarquez que mes calculs sont erronés.

stokastic
la source
@BetaDecay Non, l'idée est qu'ils seront entrés via STDIN sur quatre lignes distinctes. Je vais modifier la question pour clarifier cela.
stokastic
L'entrée peut-elle être un [[list],[of],[lists]]?
phosgene
@phosgene J'aime penser que lire l'entrée fait partie du défi, donc je vais dire non. J'essaierai d'être plus indulgent avec les spécifications d'entrée dans les défis futurs.
Stokastic
S'agit-il d'un tétraèdre régulier ou irrégulier?
James Williams
@JamesWilliams l'exemple publié est irrégulier. Cependant, votre programme doit gérer toutes les entrées, y compris les tétraèdres réguliers.
stokastic

Réponses:

5

Python, 198 178 161 161 caractères

V=eval('input(),'*4)
A=0
for i in range(4):F=V[:i]+V[i+1:];a,b,c=map(lambda e:sum((a-b)**2for a,b in zip(*e)),zip(F,F[1:]+F));A+=(4*a*b-(a+b-c)**2)**.5
print A/4

Le format d'entrée est celui indiqué dans la question.

Il calcule la longueur des bords adjacents à chacune des faces, puis utilise la formule de Heron .

Keith Randall
la source
4

Matlab / Octave 103

Je suppose que les valeurs doivent être stockées dans la variable c. Cela utilise le fait que l'aire d'un triangle est la demi-longueur du produit croisé de deux de ses vecteurs latéraux.

%input
[23822, 47484, 57901;
3305, 23847, 42159;
19804, 11366, 14013;
52278, 28626, 52757]



%actual code
c=input('');
a=0;
for i=1:4;
    d=c;d(i,:)=[];
    d=d(1:2,:)-[1 1]'*d(3,:);
    a=a+norm(cross(d(1,:),d(2,:)))/2;
end
a
flawr
la source
Chaque point doit être entré sur une ligne distincte comme entrée standard.
DavidC
J'ai d'abord pensé qu'il n'y avait pas d'entrée standard dans Matlab, mais j'ai découvert une fonction qui peut être utilisée pour simuler cela via la fenêtre de commande, alors maintenant vous pouvez passer l'entrée comme vous le pourriez dans d'autres langues.
flawr
Intéressant. C'est la même commande que Mathematica utilise,Input[]
DavidC
Pourquoi pensez-vous que c'est intéressant? «entrée» me semble être un nom assez générique pour une fonction qui fait cela.
flawr
Jusqu'à hier, je ne savais pas vraiment ce que « l' entrée standard » signifiait, et je pensais que Mathematica n'avait pas entrée « standard », même si je l' avais régulièrement utilisé Input[], InputString[], Import[]et ImportString[].
DavidC
4

APL, 59

f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺}
.5×.5+.*⍨(f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕

Fonctionne en calculant des produits croisés

Explication
La première ligne définit une fonction qui prend deux arguments (implicite nommé et ), s'attend implicitement à ce qu'ils soient des tableaux numériques de longueur 3, les traite comme des vecteurs 3D et calcule la magnitude au carré de leur produit croisé.

                        ⊂⍺   # Wrap the argument in a scalar
                   1 2⌽¨     # Create an array of 2 arrays, by rotating `⊂⍺` by 1 and 2 places
             (⊂⍵)×           # Coordinate-wise multiply each of them with the other argument
        1 2-.⌽               # This is a shorthand for:
        1 2  ⌽               #   Rotate the first array item by 1 and the second by 2
           -.                #   Then subtract the second from the first, coordinate-wise
       ⊃                     # Unwrap the resulting scalar to get the (sorta) cross product
   +.×                       # Calculate the dot product of that...
      ⍨                      # ...with itself
f←{+.×⍨⊃1 2-.⌽(⊂⍵)×1 2⌽¨⊂⍺} # Assign function to `f`

La deuxième ligne fait le reste.

                         ⎕⎕⎕-⊂⎕ # Take 4 array inputs, create an array of arrays by subtracting one of them from the other 3
                       x←        # Assign that to x
                     4⍴          # Duplicate the first item and append to the end
                  2f/            # Apply f to each consecutive pair
            2-/x                 # Apply subtraction to consecutive pairs in x
          f/                     # Apply f to the 2 resulting arrays
         (f/2-/x),2f/4⍴x←⎕⎕⎕-⊂⎕ # Concatenate to an array of 4 squared cross products
   .5+.*⍨                        # Again a shorthand for:
   .5  *⍨                        #   Take square root of each element (by raising to 0.5)
     +.                          #   And sum the results
.5×                              # Finally, divide by 2 to get the answer
TwiNight
la source
Si vous n'êtes pas sûr qu'il s'agisse de hiéroglyphes ou d'un fichier dll corrompu, ce sera probablement APL. Pourriez-vous peut-être expliquer un peu plus ce que font certains de ces symboles? Ce n'est pas que je veuille l'apprendre, mais je suis toujours plutôt intrigué par la façon dont vous pouvez programmer avec ces symboles apparemment obscurs = P
flawr
@flawr Je le fais habituellement parce que jouer au golf dans APL se résume principalement à la conception d'algorithmes et entraînerait très probablement une approche peu commune du problème. Mais j'avais l'impression que le «calcul du produit croisé» en dit assez sur l'algorithme ici. Si vous voulez une explication complète, je le ferai plus tard dans la journée.
TwiNight
L'idée de calculer le produit croisé était claire, mais le code lui-même me laisse sans aucun indice, alors j'ai juste pensé quelques mots sur les parties du code qui feraient ce qui serait génial, mais bien sûr, je ne veux pas vous exhorter à écrivez une explication détaillée!
flawr
3

Python 3, 308 298 292 279 258 254

from itertools import*
def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**.5
z,x,c,v,b,n=((lambda i,j:(sum((i[x]-j[x])**2for x in[0,1,2]))**.5)(x[0],x[1])for*x,in combinations([eval(input())for i in">"*4],2))
print(a(z,x,v)+a(z,c,b)+a(b,v,n)+a(x,c,n))

Cela utilise:

  • Le théorème de Pythagore (en 3D) pour calculer la longueur de chaque ligne
  • La formule de Heron pour déterminer l'aire de chaque triangle
monopole
la source
1
J'ai utilisé la même méthode pour tester ma solution. Je vais devoir essayer la mienne et la poster plus tard.
stokastic
1
Votre for i in">"*4est intelligent
stokastic
Vous pouvez coder en dur une longueur de 3, au lieu d'utiliser len (i) dans votre fonction de plage.
stokastic
1
Vous pouvez enregistrer quelques caractères supplémentaires en utilisant la racine carrée au x**0.5lieu de math.sqrt(x).
Snorfalorpagus
1
Vous pouvez enregistrer deux octets en mettant def a(t,u,v)sur une ligne comme ceci: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5.
Beta Decay du
2

Mathematica 168 154

Cela trouve les longueurs des bords du tétraèdre et utilise la formule de Heron pour déterminer les zones des faces.

t = Subsets; p = Table[Input[], {4}];
f@{a_, b_, c_} := Module[{s = (a + b + c)/2}, N[Sqrt[s (s - #) (s - #2) (s -#3)] &[a, b, c], 25]]
  Tr[f /@ (EuclideanDistance @@@ t[#, {2}] & /@ t[p, {3}])]

Il existe un itinéraire plus direct qui ne nécessite que 60 caractères , mais il viole les règles dans la mesure où il calcule l'aire de chaque face avec une fonction intégrée Area,:

p = Table[Input[], {4}];
N[Tr[Area /@ Polygon /@ Subsets[p, {3}]], 25]
DavidC
la source
1

Sauge - 103

print sum((x*x*y*y-x*y*x*y)^.5for x,y in map(differences,Combinations(eval('vector(input()),'*4),3)))/2

La partie lecture-entrée est adaptée de la réponse de Keith Randall .

Wrzlprmft
la source
0

Python - 260

Je ne sais pas quelle est l'étiquette sur l'affichage des réponses à vos propres questions, mais elle est ma solution, que j'ai utilisée pour vérifier mon exemple, a joué au golf:

import copy,math
P=[input()for i in"1234"]
def e(a, b):return math.sqrt(sum([(b[i]-a[i])**2 for i in range(3)]))
o=0
for j in range(4):p=copy.copy(P);p.pop(j);a,b,c=[e(p[i],p[(i+1)%3])for i in range(3)];s=(a+b+c)/2;A=math.sqrt(s*(s-a)*(s-b)*(s-c));o+=A
print o

Il utilise la même procédure que laurencevs.

stokastic
la source
4
En règle générale, il est préférable d'attendre quelques jours avant de répondre à votre propre question, surtout si votre score est faible, afin de ne pas refroidir la motivation des téléspectateurs.
Blackhole
Quelques conseils: vous pouvez enregistrer certains caractères en r=range. lambdaest plus court que def. math.sqrtpeut être remplacé par (…)**.5. p=copy.copy(P);p.pop(j);peut être raccourci p=P[:j-1]+P[j:]. An'est utilisé qu'une seule fois.
Wrzlprmft
0

C, 303

À l'exclusion des espaces inutiles. Cependant, il y a encore beaucoup de golf à faire ici (j'essaierai de revenir et de le faire plus tard.) C'est la première fois que je déclare une forboucle dans un#define . J'ai toujours trouvé des moyens de minimiser le nombre de boucles auparavant.

J'ai dû changer de floatpour doubleobtenir la même réponse que l'OP pour le cas de test. Avant cela, c'était un round 300.

scanf fonctionne de la même manière si vous séparez votre entrée par des espaces ou des sauts de ligne, vous pouvez donc la formater en autant de lignes que vous le souhaitez.

#define F ;for(i=0;i<12;i++)
#define D(k) (q[i]-q[(i+k)%12])
double q[12],r[12],s[4],p,n;

main(i){
  F scanf("%lf",&q[i])
  F r[i/3*3]+=D(3)*D(3),r[i/3*3+1]+=D(6)*D(6)
  F r[i]=sqrt(r[i])
  F i%3||(s[i/3]=r[(i+3)%12]/2),s[i/3]+=r[i]/2
  F i%3||(p=s[i/3]-r[(i+3)%12]),p*=s[i/3]-r[i],n+=(i%3>1)*sqrt(p)   
  ;printf("%lf",n);       
}
Level River St
la source