# Tetrahedron Surface Area

## The challenge

This challenge is very straightforward. Given four 3-dimensional points, calculate the surface area of the tetrahedron that they form. This is , so shortest code wins. Standard loopholes apply, with the added stipulation that any built-in function to do this task given four points is prohibited.

You can assume all four points will be distinct, and will be given via STDIN, 1 point per line. Each point will consist of three 16-bit unsigned integers. The exact format of each point can be modified if it makes things easier, such as three space separated integers. Having each point on a separate line is mandatory however. Output should be through STDOUT, to at least 2 decimal places.

For those of you who do not know, a tetrahedron is a 3-d solid, formed by 4 triangular faces.

### Example

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

# output
2932496435.95


Please leave a note if you notice my math is wrong.

• @BetaDecay No, the idea is that they will be input via STDIN on four separate lines. I will edit the question to clarify this. – stokastic Oct 3 '14 at 18:18
• Can the input be a [[list],[of],[lists]]? – phosgene Oct 3 '14 at 18:31
• @phosgene I like to think reading the input is part of the challenge, so I'm going to say no. I will try to be more lenient with input specifications in future challenges. – stokastic Oct 3 '14 at 18:36
• Is this a regular or irregular tetrahedron? – James Williams Oct 3 '14 at 19:24
• @JamesWilliams the example posted is irregular. Your program should handle any input though, including regular tetrahedrons. – stokastic Oct 3 '14 at 19:25

## Python, 198 178 161 chars

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


The input format is as given in the question.

It calculates the length of the edges adjacent to each of the faces and then uses Heron's formula.

# Matlab/Octave 103

I assume the values to be stored in the variable c. This uses the fact that the area of a triangle is the half length of the cross product of two of its side vectors.

%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

• Each point must be entered on a separate line as standard input. – DavidC Oct 4 '14 at 1:30
• I first thought there is no such thing as standard input in Matlab, but I discovered a function that can be used to simulate this via the command window, so now you can pass the input as you could in other languages. – flawr Oct 4 '14 at 9:18
• Interesting. That's the same command that Mathematica uses, Input[] – DavidC Oct 4 '14 at 11:59
• Why do you think that this is interesting? 'input' seems to me like a pretty generic name for a function that does this. – flawr Oct 4 '14 at 12:12
• Until yesterday, I didn't really know what "standard input" meant, and I thought that Mathematica did not have "standard" input, even though I had regularly used Input[], InputString[], Import[], and ImportString[]. – DavidC Oct 4 '14 at 12:31

## APL, 59

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


Works by calculating cross products

Explanation
The first line defines a function that takes two arguments (implicity named ⍺ and ⍵), implicitly expects them to be numerical arrays of length 3, treat them as 3d vectors, and calculates the squared magnitude of their cross product.

                        ⊂⍺   # 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


The second line does the rest.

                         ⎕⎕⎕-⊂⎕ # 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

• If you are not sure whether it is hieroglyphs or a corrupted dll file it is probably gonna be APL. Could you perhaps explain somewhat more what some of those symbols do? It's not that I want to learn it but I am still rather intrigued by how you can program with those seemingly obscure symbols=P – flawr Oct 6 '14 at 16:55
• @flawr I usually does that because golfing in APL mostly comes down to algorithm design and would most likely result in an uncommon approach to the problem. But I felt like "calculating cross product" conveys enough about the algorithm here. If you want a full-on explanation I will do it later today. – TwiNight Oct 7 '14 at 12:05
• The idea of calculating the cross product was clear, but the code itself leaves me without any clue, so I just thought some few words about what parts of the code do what would be great, but of course I do not want to urge you to write a detailed explaination! – flawr Oct 7 '14 at 12:33

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


This uses:

• The Pythagorean Theorem (in 3D) to work out the length of each line
• Heron's Formula to work out the area of each triangle
• I used the same method for testing my solution. I'll have to try golfing mine and post it later. – stokastic Oct 3 '14 at 19:54
• Your for i in">"*4 is clever – stokastic Oct 3 '14 at 19:58
• You can hard code a length of 3, instead of using len(i) in your range function. – stokastic Oct 3 '14 at 20:28
• You could save a few more characters doing the square root as x**0.5, instead of math.sqrt(x). – Snorfalorpagus Oct 3 '14 at 22:46
• You can save two bytes by putting def a(t,u,v) on one line like so: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5. – Beta Decay Oct 4 '14 at 8:50

# Mathematica 168 154

This finds the lengths of the edges of the tetrahedron and uses Heron's formula to determine the areas of the 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}])]


There is a more direct route that requires only 60 chars, but it violates the rules insofar as it computes the area of each face with a built-in function, Area:

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


## Sage – 103

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


## Python - 260

I'm not sure what the etiquette on posting answers to your own questions is, but her is my solution, which I used to verify my example, golfed:

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


It uses the same procedure as laurencevs.

• As a rule of thumb, it's a best idea to wait a few days before answering your own question, especially if your score is low, in order to not cool down the motivation of the viewers. – Blackhole Oct 3 '14 at 21:09
• A few tips: You can save some characters by r=range. lambda is shorter than def. math.sqrt can be replaced by (…)**.5. p=copy.copy(P);p.pop(j); can be shortened to p=P[:j-1]+P[j:]. A is only used once. – Wrzlprmft Oct 8 '14 at 15:34

# C, 303

Excluding unnecessary whitespace. However, there's still a lot of golfing to be done here (I will try to come back and do it later.) It's the first time I've declared a for loop in a #define. I've always found ways to minmalise the number of loops before.

I had to change from float to double to get the same answer as the OP for the test case. Before that, it was a round 300.

scanf works the same whether you separate your input with spaces or newlines, so you can format it into as many or as few lines as you like.

#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);
}