16
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ @BetaDecay No, the idea is that they will be input via STDIN on four separate lines. I will edit the question to clarify this. \$\endgroup\$ – stokastic Oct 3 '14 at 18:18
  • \$\begingroup\$ Can the input be a [[list],[of],[lists]]? \$\endgroup\$ – phosgene Oct 3 '14 at 18:31
  • \$\begingroup\$ @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. \$\endgroup\$ – stokastic Oct 3 '14 at 18:36
  • \$\begingroup\$ Is this a regular or irregular tetrahedron? \$\endgroup\$ – James Williams Oct 3 '14 at 19:24
  • \$\begingroup\$ @JamesWilliams the example posted is irregular. Your program should handle any input though, including regular tetrahedrons. \$\endgroup\$ – stokastic Oct 3 '14 at 19:25
5
\$\begingroup\$

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.

\$\endgroup\$
4
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Each point must be entered on a separate line as standard input. \$\endgroup\$ – DavidC Oct 4 '14 at 1:30
  • \$\begingroup\$ 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. \$\endgroup\$ – flawr Oct 4 '14 at 9:18
  • \$\begingroup\$ Interesting. That's the same command that Mathematica uses, Input[] \$\endgroup\$ – DavidC Oct 4 '14 at 11:59
  • \$\begingroup\$ Why do you think that this is interesting? 'input' seems to me like a pretty generic name for a function that does this. \$\endgroup\$ – flawr Oct 4 '14 at 12:12
  • \$\begingroup\$ 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[]. \$\endgroup\$ – DavidC Oct 4 '14 at 12:31
4
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ 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 \$\endgroup\$ – flawr Oct 6 '14 at 16:55
  • \$\begingroup\$ @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. \$\endgroup\$ – TwiNight Oct 7 '14 at 12:05
  • \$\begingroup\$ 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! \$\endgroup\$ – flawr Oct 7 '14 at 12:33
3
\$\begingroup\$

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
\$\endgroup\$
  • 1
    \$\begingroup\$ I used the same method for testing my solution. I'll have to try golfing mine and post it later. \$\endgroup\$ – stokastic Oct 3 '14 at 19:54
  • 1
    \$\begingroup\$ Your for i in">"*4 is clever \$\endgroup\$ – stokastic Oct 3 '14 at 19:58
  • \$\begingroup\$ You can hard code a length of 3, instead of using len(i) in your range function. \$\endgroup\$ – stokastic Oct 3 '14 at 20:28
  • 1
    \$\begingroup\$ You could save a few more characters doing the square root as x**0.5, instead of math.sqrt(x). \$\endgroup\$ – Snorfalorpagus Oct 3 '14 at 22:46
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – Beta Decay Oct 4 '14 at 8:50
2
\$\begingroup\$

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]
\$\endgroup\$
1
\$\begingroup\$

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

The input-reading part is adapted from Keith Randall’s answer.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
  • 4
    \$\begingroup\$ 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. \$\endgroup\$ – Blackhole Oct 3 '14 at 21:09
  • \$\begingroup\$ 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. \$\endgroup\$ – Wrzlprmft Oct 8 '14 at 15:34
0
\$\begingroup\$

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);       
}
\$\endgroup\$

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.