Superficie del tetraedro


16

La sfida

Questa sfida è molto semplice. Dati quattro punti tridimensionali, calcola la superficie del tetraedro che formano. Questo è , quindi vince il codice più corto. Si applicano scappatoie standard, con l'aggiunta della clausola secondo cui è vietata qualsiasi funzione incorporata per svolgere questo compito dati quattro punti.

Puoi presumere che tutti e quattro i punti saranno distinti e ti verrà dato tramite STDIN, 1 punto per riga. Ciascun punto sarà composto da tre numeri interi senza segno a 16 bit. Il formato esatto di ciascun punto può essere modificato se semplifica le cose, come tre numeri interi separati da spazio. Avere ogni punto su una riga separata è obbligatorio comunque. L'output dovrebbe essere tramite STDOUT, con almeno 2 decimali.

Per quelli di voi che non lo sanno, un tetraedro è un solido 3-d, formato da 4 facce triangolari.

Esempio

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

# output
2932496435.95

Per favore, lascia una nota se noti che la mia matematica è sbagliata.


@BetaDecay No, l'idea è che verranno immessi tramite STDIN su quattro righe separate. Modificherò la domanda per chiarire questo.
stokastic

L'ingresso può essere un [[list],[of],[lists]]?
fosgene,

@phosgene Mi piace pensare che leggere l'input sia parte della sfida, quindi ho intenzione di dire di no. Cercherò di essere più indulgente con le specifiche di input nelle sfide future.
stokastic

È un tetraedro regolare o irregolare?
James Williams,

@JamesWilliams l'esempio pubblicato è irregolare. Il tuo programma dovrebbe gestire qualsiasi input, compresi i tetraedri regolari.
stokastic,

Risposte:


5

Python, 198 178 161 caratteri

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

Il formato di input è come indicato nella domanda.

Calcola la lunghezza dei bordi adiacenti a ciascuna delle facce e quindi utilizza la formula di Airone .


4

Matlab / Octave 103

Presumo che i valori siano memorizzati nella variabile c. Questo utilizza il fatto che l'area di un triangolo è la mezza lunghezza del prodotto trasversale di due dei suoi vettori laterali.

%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

Ogni punto deve essere inserito su una riga separata come input standard.
DavidC

In un primo momento ho pensato che non esistesse l'input standard in Matlab, ma ho scoperto una funzione che può essere utilizzata per simulare questo tramite la finestra di comando, quindi ora puoi passare l'input come puoi in altre lingue.
Flawr

Interessante. È lo stesso comando usato da Mathematica,Input[]
DavidC,

Perché pensi che sia interessante? "input" mi sembra un nome piuttosto generico per una funzione che lo fa.
Flawr

Fino a ieri, non ho davvero sapere cosa "standard input" significava, e ho pensato che Mathematica non ha avuto input "standard", anche se avevo regolarmente utilizzato Input[], InputString[], Import[], e ImportString[].
DavidC,

4

APL, 59

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

Funziona calcolando i prodotti incrociati

Spiegazione
La prima riga definisce una funzione che accetta due argomenti (implicitamente denominati e ), si aspetta implicitamente che siano array numerici di lunghezza 3, li trattano come vettori 3d e calcola la grandezza quadrata del loro prodotto incrociato.

                        ⊂⍺   # 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 seconda riga fa il resto.

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

Se non sei sicuro che si tratti di geroglifici o di un file dll danneggiato, probabilmente sarà APL. Potresti forse spiegare un po 'di più cosa fanno alcuni di quei simboli? Non è che io voglia impararlo, ma sono ancora piuttosto incuriosito da come puoi programmare con quei simboli apparentemente oscuri = P
flawr

@flawr Di solito lo faccio perché il golf in APL si basa principalmente sulla progettazione di algoritmi e molto probabilmente si tradurrebbe in un approccio non comune al problema. Ma mi sentivo come "calcolare il prodotto incrociato" trasmette abbastanza sull'algoritmo qui. Se vuoi una spiegazione completa, lo farò più tardi oggi.
TwiNight,

L'idea di calcolare il prodotto incrociato era chiara, ma il codice stesso mi lascia senza alcun indizio, quindi ho pensato solo alcune parole su quali parti del codice fanno ciò che sarebbe fantastico, ma ovviamente non voglio esortarti a scrivi una spiegazione dettagliata!
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))

Questo utilizza:

  • Il teorema di Pitagora (in 3D) per calcolare la lunghezza di ogni linea
  • Formula dell'airone per elaborare l'area di ogni triangolo

1
Ho usato lo stesso metodo per testare la mia soluzione. Dovrò provare il mio golf e pubblicarlo più tardi.
stokastic,

1
Il tuo for i in">"*4è intelligente
stokastic

È possibile codificare in modo rigido una lunghezza di 3, anziché utilizzare len (i) nella funzione di intervallo.
stokastic,

1
Potresti salvare qualche altro personaggio facendo la radice quadrata come x**0.5, invece di math.sqrt(x).
Snorfalorpagus,

1
È possibile salvare due byte mettendo def a(t,u,v)su una riga in questo modo: def a(t,u,v):w=(t+u+v)/2;return(w*(w-t)*(w-u)*(w-v))**0.5.
Decadimento beta

2

Mathematica 168 154

Questo trova le lunghezze dei bordi del tetraedro e usa la formula di Heron per determinare le aree delle facce.

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

Esiste un percorso più diretto che richiede solo 60 caratteri , ma viola le regole in quanto calcola l'area di ciascuna faccia con una funzione incorporata Area:

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

1

Salvia - 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 parte di input-reading è adattata dalla risposta di Keith Randall .


0

Python - 260

Non sono sicuro di quale sia l'etichetta nel pubblicare le risposte alle tue domande, ma la sua è la mia soluzione, che ho usato per verificare il mio esempio:

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

Utilizza la stessa procedura di laurencevs.


4
Come regola generale, è consigliabile attendere qualche giorno prima di rispondere alla propria domanda, soprattutto se il punteggio è basso, al fine di non raffreddare la motivazione degli spettatori.
Blackhole,

Alcuni consigli: puoi salvare alcuni personaggi di r=range. lambdaè più corto di def. math.sqrtpuò essere sostituito da (…)**.5. p=copy.copy(P);p.pop(j);può essere abbreviato in p=P[:j-1]+P[j:]. Aviene usato solo una volta.
Wrzlprmft,

0

C, 303

Escludendo gli spazi bianchi non necessari. Tuttavia, c'è ancora molto da giocare a golf qui (cercherò di tornare e farlo più tardi.) È la prima volta che dichiaro un forcircuito in a #define. Ho sempre trovato il modo di minimizzare il numero di loop prima.

Ho dovuto cambiare da floata doubleper ottenere la stessa risposta dell'OP per il caso di test. Prima di ciò, era un round 300.

scanf funziona allo stesso modo se si separa l'input con spazi o newline, quindi è possibile formattarlo in quante o quante righe desideri.

#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);       
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.