Tetraeder-Oberfläche


16

Die Herausforderung

Diese Herausforderung ist sehr einfach. Berechnen Sie anhand von vier dreidimensionalen Punkten die Oberfläche des Tetraeders, den sie bilden. Das ist , also gewinnt der kürzeste Code. Es gelten Standard-Regelungslücken, mit der zusätzlichen Bedingung, dass jede eingebaute Funktion, die diese Aufgabe mit vier Punkten erfüllt, verboten ist.

Sie können davon ausgehen, dass alle vier Punkte unterschiedlich sind und über STDIN mit 1 Punkt pro Linie angegeben werden. Jeder Punkt besteht aus drei 16-Bit-Ganzzahlen ohne Vorzeichen. Das genaue Format jedes Punkts kann geändert werden, wenn es die Sache einfacher macht, z. B. drei durch Leerzeichen getrennte Ganzzahlen. Es ist jedoch obligatorisch, dass jeder Punkt auf einer eigenen Linie liegt. Die Ausgabe sollte über STDOUT mit mindestens 2 Dezimalstellen erfolgen.

Für diejenigen von euch, die es nicht wissen, ist ein Tetraeder ein 3D-Körper, der aus 4 dreieckigen Flächen besteht.

Beispiel

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

# output
2932496435.95

Bitte hinterlassen Sie eine Nachricht, wenn Sie bemerken, dass meine Mathematik falsch ist.


@BetaDecay Nein, die Idee ist, dass sie über STDIN in vier separaten Zeilen eingegeben werden. Ich werde die Frage bearbeiten, um dies zu klären.
Stokastic

Kann der Eingang ein sein [[list],[of],[lists]]?
Phosgen

@phosgene Ich denke gerne, dass das Lesen der Eingabe Teil der Herausforderung ist, also werde ich nein sagen. Ich werde versuchen, bei zukünftigen Herausforderungen mit den Eingabespezifikationen nachsichtiger umzugehen.
Stokastic

Ist das ein regelmäßiger oder unregelmäßiger Tetraeder?
James Williams

@ James Williams das Beispiel geschrieben ist unregelmäßig. Ihr Programm sollte jedoch alle Eingaben verarbeiten, einschließlich regulärer Tetraeder.
Stokastic

Antworten:


5

Python, 198 178 161 Zeichen

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

Das Eingabeformat ist wie in der Frage angegeben.

Es berechnet die Länge der Kanten, die an die einzelnen Flächen angrenzen, und verwendet dann die Heron-Formel .


4

Matlab / Octave 103

Ich gehe davon aus, dass die Werte in der Variablen gespeichert werden c. Dies nutzt die Tatsache, dass die Fläche eines Dreiecks die halbe Länge des Kreuzprodukts zweier seiner Seitenvektoren ist.

%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

Jeder Punkt muss als Standardeingabe in einer separaten Zeile eingegeben werden.
DavidC

Ich dachte zuerst, es gibt keine Standardeingabe in Matlab, aber ich entdeckte eine Funktion, mit der dies über das Befehlsfenster simuliert werden kann, sodass Sie die Eingabe jetzt wie in anderen Sprachen übergeben können.
Fehler

Interessant. Das ist derselbe Befehl, den Mathematica verwendetInput[]
DavidC

Warum findest du das interessant? 'input' scheint mir ein ziemlich generischer Name für eine Funktion zu sein, die dies tut.
Fehler

Bis gestern wusste ich nicht wirklich , was „Standardeingabe“ gemeint, und ich dachte , dass Mathematica nicht hat „Standard“ Eingang, obwohl ich regelmäßig benutzt hatte Input[], InputString[], Import[], und ImportString[].
DavidC

4

APL, 59

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

Arbeitet durch Berechnung von Kreuzprodukten

Erläuterung
In der ersten Zeile wird eine Funktion definiert, die zwei Argumente (implicity named und ) verwendet, implizit numerische Arrays der Länge 3 erwartet, sie als 3D-Vektoren behandelt und die quadratische Größe ihres Kreuzprodukts berechnet .

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

Die zweite Zeile erledigt den 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

Wenn Sie nicht sicher sind, ob es sich um Hieroglyphen oder eine beschädigte DLL-Datei handelt, handelt es sich wahrscheinlich um APL. Könnten Sie vielleicht etwas näher erläutern, was einige dieser Symbole bewirken? Es ist nicht so, dass ich es lernen möchte, aber ich bin immer noch ziemlich fasziniert davon, wie man mit diesen scheinbar obskuren Symbolen programmieren kann = P
Fehler

@flawr Ich mache das normalerweise, weil das Golfen in APL hauptsächlich auf das Algorithmus-Design zurückzuführen ist und höchstwahrscheinlich zu einer ungewöhnlichen Herangehensweise an das Problem führen würde. Aber ich hatte das Gefühl, dass "Cross-Product-Berechnung" hier genug über den Algorithmus aussagt. Wenn Sie eine ausführliche Erklärung wünschen, werde ich das später tun.
TwiNight

Die Idee, das Kreuzprodukt zu berechnen, war klar, aber der Code selbst lässt mich ohne Anhaltspunkt, so dass ich mir nur ein paar Worte überlegte, welche Teile des Codes großartig wären, aber ich möchte Sie natürlich nicht dazu drängen schreibe eine ausführliche Erklärung!
Fehler

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

Dies verwendet:

  • Der Satz von Pythagoras (in 3D), um die Länge jeder Linie zu berechnen
  • Heron's Formula, um die Fläche jedes Dreiecks zu berechnen

1
Ich habe die gleiche Methode zum Testen meiner Lösung verwendet. Ich muss meins mal ausprobieren und später posten.
Stokastic

1
Sie for i in">"*4ist clever
stokastic

Sie können eine Länge von 3 fest codieren, anstatt len ​​(i) in Ihrer Bereichsfunktion zu verwenden.
Stokastic

1
Sie könnten ein paar weitere Zeichen speichern, indem Sie die Quadratwurzel als x**0.5anstelle von verwenden math.sqrt(x).
Snorfalorpagus

1
Sie können , indem sie zwei Bytes speichern def a(t,u,v)wie so auf einer Linie: 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

Dieser ermittelt die Kantenlängen des Tetraeders und bestimmt anhand der Heronschen Formel die Flächen der Flächen.

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

Es gibt einen direkteren Weg, der nur 60 Zeichen erfordert , der jedoch gegen die Regeln verstößt, da er die Fläche jedes Gesichts mit einer eingebauten Funktion berechnet Area:

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

1

Salbei - 103

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

Der Eingabe-Leseteil ist aus Keith Randalls Antwort adaptiert .


0

Python - 260

Ich bin nicht sicher, wie die Etikette beim Posten von Antworten auf Ihre eigenen Fragen lautet, aber sie ist meine Lösung, mit der ich mein Beispiel überprüft habe:

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

Es wird dasselbe Verfahren angewendet wie bei Laurencevs.


4
Als Faustregel empfiehlt es sich, ein paar Tage zu warten, bevor Sie Ihre eigene Frage beantworten, insbesondere wenn Ihre Punktzahl niedrig ist, um die Motivation der Zuschauer nicht abzukühlen.
Blackhole

Ein paar Tipps: Sie können einige Zeichen speichern, indem Sie r=range. lambdaist kürzer als def. math.sqrtkann durch ersetzt werden (…)**.5. p=copy.copy(P);p.pop(j);kann auf gekürzt werden p=P[:j-1]+P[j:]. Awird nur einmal verwendet.
Wrzlprmft

0

C 303

Ohne unnötige Leerzeichen. Es gibt hier jedoch noch viel zu golfen (ich werde versuchen, es später noch einmal zu versuchen.) Es ist das erste Mal, dass ich eine forSchleife in einer deklariere #define. Ich habe schon immer Wege gefunden, die Anzahl der Schleifen zu minimieren.

Ich hatte von zu ändern , floatum doubledie gleiche Antwort wie die OP für den Testfall zu erhalten. Vorher war es eine Runde 300.

scanf Funktioniert gleichermaßen, unabhängig davon, ob Sie Ihre Eingabe durch Leerzeichen oder Zeilenumbrüche trennen, sodass Sie sie in beliebig viele oder so wenige Zeilen formatieren können.

#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);       
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.