Powierzchnia czworościanu

16

Wyzwanie

To wyzwanie jest bardzo proste. Biorąc pod uwagę cztery trójwymiarowe punkty, oblicz pole powierzchni czworościanu, który tworzą. To jest , więc wygrywa najkrótszy kod. Obowiązują standardowe luki, z dodatkowym zastrzeżeniem, że żadna wbudowana funkcja do wykonania tego zadania, biorąc pod uwagę cztery punkty, jest zabroniona.

Możesz założyć, że wszystkie cztery punkty będą odrębne i będą przyznawane za pośrednictwem STDIN, 1 punkt na linię. Każdy punkt będzie się składał z trzech 16-bitowych liczb całkowitych bez znaku. Dokładny format każdego punktu można zmodyfikować, jeśli to ułatwi, na przykład trzy liczby całkowite oddzielone spacjami. Jednak umieszczenie każdego punktu na osobnej linii jest obowiązkowe. Dane wyjściowe powinny być przesyłane przez STDOUT, z dokładnością do co najmniej 2 miejsc po przecinku.

Dla tych z was, którzy nie wiedzą, czworościan jest trójwymiarową bryłą, utworzoną przez 4 trójkątne ściany.

Przykład

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

# output
2932496435.95

Zostaw notatkę, jeśli zauważysz, że moja matematyka jest błędna.

stokastic
źródło
@BetaDecay Nie, chodzi o to, że będą one wprowadzane przez STDIN w czterech oddzielnych wierszach. Przeredaguję pytanie, aby to wyjaśnić.
stokastic
Czy dane wejściowe mogą być [[list],[of],[lists]]?
fosgen
@ phosgene Lubię myśleć, że czytanie danych wejściowych jest częścią wyzwania, więc powiem nie. W przyszłych wyzwaniach postaram się być bardziej wyrozumiały dzięki specyfikacjom danych wejściowych.
stokastic
Czy to regularny czy nieregularny czworościan?
James Williams
@JamesWilliams opublikowany przykład jest nieregularny. Twój program powinien jednak obsłużyć wszelkie dane wejściowe, w tym zwykłe czworościany.
stokastic

Odpowiedzi:

5

Python, 198 178 161 znaków

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

Format wejściowy jest taki, jak podano w pytaniu.

Oblicza długość krawędzi przylegających do każdej ze ścian, a następnie używa wzoru Herona .

Keith Randall
źródło
4

Matlab / Octave 103

Zakładam, że wartości mają być przechowywane w zmiennej c. Wykorzystuje to fakt, że pole trójkąta jest połową długości iloczynu poprzecznego dwóch jego wektorów bocznych.

%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
wada
źródło
Każdy punkt musi być wprowadzony w osobnej linii jako standardowe wejście.
DavidC
Najpierw pomyślałem, że w Matlabie nie ma czegoś takiego jak standardowe wejście, ale odkryłem funkcję, której można użyć do symulacji tego za pomocą okna poleceń, więc teraz możesz przekazać dane wejściowe tak jak w innych językach.
flawr
Ciekawy. Tego samego polecenia używa Mathematica,Input[]
DavidC
Jak myślisz, dlaczego to jest interesujące? „input” wydaje mi się dość ogólną nazwą dla funkcji, która to robi.
flawr
Do wczoraj, ja naprawdę nie wiem co „standardowe wejście” oznaczało, i pomyślałem, że nie ma Mathematica „standard” wejście, chociaż miałam regularnie stosowany Input[], InputString[], Import[], i ImportString[].
DavidC
4

APL, 59

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

Działa poprzez obliczanie produktów krzyżowych

Objaśnienie
Pierwszy wiersz definiuje funkcję, która przyjmuje dwa argumenty (implikacja o nazwie i ), domyślnie oczekuje, że będą to tablice liczbowe o długości 3, traktuje je jako wektory 3d i oblicza kwadratową wielkość ich iloczynu krzyżowego.

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

Druga linia zajmuje się resztą.

                         ⎕⎕⎕-⊂⎕ # 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
źródło
Jeśli nie jesteś pewien, czy to hieroglify, czy uszkodzony plik dll, prawdopodobnie będzie to APL. Czy mógłbyś wyjaśnić nieco więcej, co robią niektóre z tych symboli? To nie tak, że chcę się tego nauczyć, ale nadal jestem raczej zaintrygowany tym, jak możesz programować za pomocą tych pozornie niejasnych symboli = P
flawr
@ flawr Zwykle to robi, ponieważ gra w golfa w APL sprowadza się głównie do projektowania algorytmów i najprawdopodobniej spowodowałaby nietypowe podejście do problemu. Ale czułem, że „obliczanie iloczynu krzyżowego” wystarczająco przekazuje tutaj algorytm. Jeśli chcesz uzyskać pełne wyjaśnienie, zrobię to dzisiaj.
TwiNight,
Pomysł obliczenia iloczynu krzyżowego był jasny, ale sam kod pozostawia mnie bez żadnych wskazówek, więc pomyślałem tylko kilka słów o tym, które części kodu robią to, co byłoby świetne, ale oczywiście nie chcę was zachęcać napisz szczegółowe wyjaśnienie!
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))

Wykorzystuje to:

  • Twierdzenie Pitagorasa (w 3D), aby obliczyć długość każdej linii
  • Formuła Herona, aby obliczyć powierzchnię każdego trójkąta
monopole
źródło
1
Użyłem tej samej metody do testowania mojego rozwiązania. Będę musiał spróbować zagrać w golfa i opublikować go później.
stokastic
1
Your for i in">"*4is smart
stokastic
Możesz na stałe zakodować długość 3, zamiast używać len (i) w funkcji zasięgu.
stokastic
1
Możesz zapisać kilka dodatkowych znaków wykonujących pierwiastek kwadratowy jako x**0.5zamiast math.sqrt(x).
Snorfalorpagus
1
Można zapisać dwa bajty poprzez umieszczenie def a(t,u,v)w jednej linii tak: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5.
Beta Decay
2

Mathematica 168 154

Znajduje długości krawędzi czworościanu i wykorzystuje wzór Herona do określenia obszarów twarzy.

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

Istnieje bardziej bezpośrednia trasa, która wymaga tylko 60 znaków , ale narusza reguły, ponieważ oblicza obszar każdej twarzy za pomocą wbudowanej funkcji Area:

p = Table[Input[], {4}];
N[Tr[Area /@ Polygon /@ Subsets[p, {3}]], 25]
DavidC
źródło
1

Szałwia - 103

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

Część do odczytu danych wejściowych jest adaptowana na podstawie odpowiedzi Keitha Randalla .

Wrzlprmft
źródło
0

Python - 260

Nie jestem pewien, jaka jest etykieta zamieszczania odpowiedzi na twoje pytania, ale ona jest moim rozwiązaniem, którego użyłem do zweryfikowania mojego przykładu, gra w golfa:

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

Wykorzystuje tę samą procedurę, co laurencevs.

stokastic
źródło
4
Zasadniczo najlepiej jest poczekać kilka dni, zanim odpowiesz na własne pytanie, zwłaszcza jeśli Twój wynik jest niski, aby nie ostudzić motywacji widzów.
Blackhole
Kilka wskazówek: Możesz zapisać niektóre postacie według r=range. lambdajest krótszy niż def. math.sqrtmożna zastąpić (…)**.5. p=copy.copy(P);p.pop(j);można skrócić do p=P[:j-1]+P[j:]. Ajest używany tylko raz.
Wrzlprmft
0

C 303

Z wyłączeniem niepotrzebnych białych znaków. Jednak wciąż jest wiele do grania w golfa (postaram się wrócić i zrobić to później). To pierwszy raz, kiedy zadeklarowałem forpętlę w#define . Zawsze wcześniej znajdowałem sposoby na zminimalizowanie liczby pętli.

Musiałem zmienić z floatna, doubleaby uzyskać tę samą odpowiedź co OP dla przypadku testowego. Wcześniej było to okrągłe 300.

scanf działa tak samo, niezależnie od tego, czy oddzielasz dane wejściowe spacjami lub znakami nowej linii, więc możesz sformatować je w dowolnej liczbie wierszy.

#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
źródło