Obróć hipersześcian


27

Wprowadzenie

Hypercube / tesseract jest 4-wymiarowym odpowiednikiem normalnej kostki. Robi się to, biorąc siatkę sześcianu, rozciągając ją na trzeci wymiar, a następnie - używając czwartego wymiaru - składając ją w hipersześcian. Zasadniczo jest to sześcian, którego każda strona to sześcian.

Aby utworzyć hipersześcian, potrzebujesz 16 wektorów 4d (wektor z x, a y, a zi wskładnikiem). Te wektory są następujące:

A(0, 0, 0, 0); B(1, 0, 0, 0); C(1, 0, 1, 0); D(0, 0, 1, 0); E(0, 1, 0, 0); F(1, 1, 0, 0); G(1, 1, 1, 0); H(0, 1, 1, 0); 
I(0, 0, 0, 1); J(1, 0, 0, 1); K(1, 0, 1, 1); L(0, 0, 1, 1); M(0, 1, 0, 1); N(1, 1, 0, 1); O(1, 1, 1, 1); P(0, 1, 1, 1);

Hipersześcian ma 24 twarze. Poniższa lista zawiera je wszystkie (każda grupa oznacza quad):

ABFE, CDHG, BCGF, DAEH, DCBA, FEHG
IJNM, KLPO, JKON, LIMP, LKJI, PMNO
ABJI, DCKL, BCKJ, DAIL, FEMN, GHPO, FGON, EHPM, EAIM, BFNJ, CGOK, HDLP

Przy wszystkich tych informacjach technicznie masz hipersześcian w kodzie. Aby to obrócić, potrzebujesz 6 różnych matryc dla każdej płaszczyzny obrotu, po jednej dla płaszczyzn YZ, XZ, XY, XW, YW i ZW. Po utworzeniu każdej macierzy należy pomnożyć z nią wierzchołki sześcianu.

Poniższe obrazy przedstawiają strukturę każdej matrycy:

Dla obrotu na płaszczyźnie YZ:

Dla obrotu na płaszczyźnie XZ:

Dla obrotu na płaszczyźnie XY:

Dla obrotu na płaszczyźnie XW:

Dla obrotu na płaszczyźnie YW:

Dla obrotu na płaszczyźnie ZW:

Obroty są stosowane w tej kolejności.

Po tym wszystkim masz obróconą hipersześcian. Teraz musisz go narysować. Należy użyć rzut prostopadły połączoną z projekcją perspektywy wysłać (x, y, z, w)do (2x/(2+z), 2y/(2+z)).

Wkład

Twój wkład to 6 liczb całkowitych od 0 (włącznie) do 360 (wyłącznie). Reprezentują one obroty w stopniach na różnych płaszczyznach obrotu hipersześcianu.

Wydajność

Twój wynik powinien być pojedynczym obrazem zawierającym hipersześcian. Wyświetlany może być obraz rasteryzowany, obraz wektorowy lub grafika ASCII. Obraz wyjściowy powinien mieć co najmniej 100 * 100 pikseli, a kostka musi zajmować co najmniej 50% ekranu. Dowolny domyślny format wyjściowy obrazu jest dozwolony.

Przypadki testowe

0 0 0 0 0 0

0 0 0 0 0 30

30 0 0 0 0 30

0 0 0 30 30 30

45 45 45 0 0 0

45 45 45 45 45 45

Otwórz obrazy w nowej karcie, aby zobaczyć je w pełnym rozmiarze.

Zasady

  • Obowiązują zasady domyślne
  • Standardowe luki są zabronione
  • Najkrótszy kod w bajtach wygrywa

Dlaczego nuke drugi post?
Rɪᴋᴇʀ

@ EᴀsᴛᴇʀʟʏIʀᴋ Wysłałem to na czacie do ostatniej recenzji
Bálint

7
Jak wskazałem dwa razy w piaskownicy, opis projekcji do wyświetlania jest niekompletny, ponieważ zakłada, że ​​rzutowany obiekt jest trójwymiarowy, podczas gdy w rzeczywistości jest 4-wymiarowy.
Peter Taylor,

2
@luserdroog Myślę, że „U” musi być „N”.
zlewka

2
@ Bálint Dzięki za wyzwanie, podobało mi się. Mamy nadzieję, że otrzymamy więcej odpowiedzi i różne podejścia. : D
zlewka

Odpowiedzi:


9

Oktawa, 474 433 429 bajtów

function H(a,b,c,d,e,f) C=@cosd;S=@sind;R=[1,0,0,0;0,C(e),0,-S(e);0,-S(e)*S(f),C(f),-C(e)*S(f);0,S(e)*C(f),S(f),C(e)*C(f)]*[C(c)*C(d),-S(c)*C(d),0,S(d);S(c),C(c),0,0;0,0,1,0;-C(c)*S(d),S(c)*S(d),0,C(d)]*[C(b),S(a)*S(b),C(a)*S(b),0;0,C(a),-S(a),0;-S(b),S(a)*C(b),C(a)*C(b),0;0,0,0,1]*(dec2bin(0:15)'-48.5);Z=R(3,:)+2;R=2*R./Z;Q=[1,2,10,12,11,9,10,14,16,12,4,8,16,15,11,3,7,15,13,9,1,5,13,14,6,8,7,5,6,2,4,3,1];plot(R(1,Q),R(2,Q));

Obrócono:

function H(a,b,c,d,e,f) 
C=@cosd;S=@sind;
R=[1,0,0,0;0,C(e),0,-S(e);0,-S(e)*S(f),C(f),-C(e)*S(f);0,S(e)*C(f),S(f),C(e)*C(f)]*
  [C(c)*C(d),-S(c)*C(d),0,S(d);S(c),C(c),0,0;0,0,1,0;-C(c)*S(d),S(c)*S(d),0,C(d)]*
  [C(b),S(a)*S(b),C(a)*S(b),0;0,C(a),-S(a),0;-S(b),S(a)*C(b),C(a)*C(b),0;0,0,0,1]*
  (dec2bin(0:15)'-48.5);
Z=R(3,:)+2;
R=2*R./Z;
Q=[1,2,10,12,11,9,10,14,16,12,4,8,16,15,11,3,7,15,13,9,1,5,13,14,6,8,7,5,6,2,4,3,1];
plot(R(1,Q),R(2,Q));

Matryce rotacyjne nadal zajmują dużo bajtów, ale cykl Eulera działał całkiem dobrze, zmniejszając liczbę odwiedzonych wierzchołków z 96 120 do 33.

Wierzchołki są generowane przez przyjęcie 4-bitowej reprezentacji binarnej [0:15]i uznanie msb za współrzędną x, a lsb współrzędną w.

Edycja: Wstępne pomnożenie wszystkich macierzy obrotu było koszmarem, dlatego początkowo tego nie użyłem, ale wstępne pomnożenie ich parami pozwoliło zaoszczędzić 41 bajtów. Teraz szukaj optymalnej kombinacji. :) Mnożenie macierzy przez trójki było gorsze niż brak pomnożenia wstępnego, więc będę zadowolony z podejścia opartego na parach.


Wydajność:

H(0,0,0,0,0,0)

H (0,0,0,0,0,0)

H(0,0,0,0,0,30)

H (0,0,0,0,0,30)

H(30,0,0,0,0,30)

H (30,0,0,0,0,30)

H(0,0,0,30,30,30)

H (0,0,0,30,30,30)

H(45,45,45,0,0,0)

H (45,45,45,0,0,0)

H(45,45,45,45,45,45)

H (45,45,45,45,45,45)


Edycja: Jestem głupia. oszukany przez tę samą zmienną wszędzie ... [Czy jesteś pewien, że nie chcesz pełnej wstępnie pomnożonej macierzy? :) i.imgur.com/nkM6y6g.png]
algmyr

@algmyr Tak, w pełni pomnożona macierz wyszła około dwa razy dłużej, jeśli dobrze pamiętam.
zlewka

To powinno być bardziej podobne, ciesz się głupimi „uproszczeniami” Maximy
algmyr

Aby nadrobić zaległości z matematyki, oto kod w wersji bardziej golfowej
algmyr

14

Postscriptum 1075 732 683 640 631 601 590 545 542 526 514 478 470

Używa mat.ps i G .

Edycja: -343 Zastosowano generowanie wektorów i obwód Eulera metodą kodowania binarnegoskradzionyzapożyczone z innych odpowiedzi. I zastosował ciągi binarne-tokena z biblioteki G.
Edycja: -49 Przedefiniowano sin cosi negskrócono nazwy.
Edycja: -43 Zdefiniowane krótkie nazwy sekwencji 0 0 0 1 1 0.
Edycja: -9 al (tj. aload) Jest krótsza niż (")@. Zrealizowano 3 wezwania do idi(tj. idiv) Kosztem bezczynności 1 idiv.
Edycja: -30 Zastosowany domyślny blok definicji od G.
Edycja: -10 Kilka więcej potrójnie używanych sekwencji.
Edycja: -45 Usuń zmienne i j k l m ndla kątów i zawsze definiuj aktualny kąt, ponieważ tfunkcje kątów używają wartości (globalnej)tzmienna. Odrocz wykonanie opisu kodu macierzy obrotu, aż jej twartość będzie gotowa.
Edycja: -3 Usuń <16>$tj. closepath. I przestrzeń.
Edycja: -16 Wyliczenie nawiasów tablicowych z wektorów jednostkowych w macierzach obrotu ( J K Li M). Ponownie złóż wniosek porzucony mona modi suna sub.
Edycja: -12 W linii funkcja projektu i rysowania i usuń (teraz pusty) załączony słownik.
Edycja: -36 Zakodowano obwód (tj. Twarze ) w ciągu.
Edycja: -8 Usuń definicję tablicy wierzchołków V. Zamiast tego pozostaw na stosie idupkopie robocze w razie potrzeby (raz, na początku i ponownie na końcu pętli). Przetłumaczyłem także kilka operatorów z ciągów znaków binarnych z powrotem na skrócone nazwy, w których BTS nie dał żadnych oszczędności, więc (I)$teraz fora(tj. forall). if dumoże być (T8)$, ale if dujest zdecydowanie lepszym wyborem (to golf , a nie zaciemnianie per se). Wykonaj również scale wcześniej translate , aby przetłumaczone współrzędne mogły być 3i 4zamiast 300i 400.

(mat.ps)run 3(G)run $
t sin
A neg
t cos
0 0
0 1
1 0
2 mu Z 2(!V)@
idi 2 mo .5 su
(>8)$
[F D]
[D E]
[E D]
[D F]

3 4 100(&>88)$(,)# div(<N)#[E 15{[I 1 H I 2 H I 4 H ex 8 H]}fo]E
5{ARGUMENTS 1(XK/)$/t ex d{{J[0 C B 0][0 A C 0]K}{[C 0 A 0]L[B 0
C 0]K}{[C B D][A C D]M K}{[C D A]L M[B D C]}{J[0 C 0 B]M[0 A 0
C]}{J L[D C B][D A C]}}(>K)$[(>?)$]transpose matmul}fo
du(019;:89=?;37?>:26><804<=576451320){48 su get al po{W
Z Y X}{(>3)$}fora X G Y G{li}(D)#{mov}if du}fora(HB)#

3 4I 100w pierwszej linii drugiego bloku są parametry reprezentujące środkowy x, y i środkowy skali odpowiednio na rysunku na stronie (współrzędne środkowe są skalowane scale). (300,400) to mniej więcej środek amerykańskiego papieru w formacie Letter (612 792) w jednostkach PS.

Jeśli potrafisz z grubsza podążać za PostScriptem, ważnymi dziwacznymi rzeczami są niejawny blok procedur i zakodowane ciągi operatora. Jak pokazują komentarze w pliku roboczym poniżej, każda linia pierwszego bloku jest domyślnie nazwana przez A, B, C itd. Tak więc np. F E Dprodukuje 1 0 0 1 0 0. W przypadku zakodowanych ciągów operatora wszystko, co jest argumentem $ #lub @jest sekwencją wywołań operatora, przy użyciu bajtów do wybierania operatorów z systemowej tabeli nazw, PLRM 3ed Dodatek F. Te funkcje i więcej są dostępne dla PostScript z biblioteką G ( teraz obejmuje również funkcje mat.ps).

Plik roboczy:

(mat.ps)run 3(G)run $
t sin %/A
A neg %/B
t cos %/C
0 0 %/D
0 1 %/E
1 0 %/F
2 mu Z 2(!V)@ %/G  %ad div %add div %108 1 54
idi 2 mo .5 su %idiv mod sub %/H %106 169 51
(>8)$ %/I %exch dup
[F D] %/J
[D E] %/K
[E D] %/L
[D F] %/M


3 4
100(&>88)$ %currentlinewidth exch dup dup %38
(,)#  %scale %139-95=44
div(<N)# %div setlinewidth %54 155-95=60 %translate %173-95=78
%/V
[E 15{[ I
    1 H I
    2 H I
    4 H ex
    8 H]}fo]

E 5{ARGUMENTS 1(XK/)$ %index get cvr %88 75 47
    /t ex d %exch def %62 51
    {{J[0 C B 0][0 A C 0]K} 
     {[C 0 A 0]L[B 0 C 0]K} 
     {[C B D][A C D]M K} 
     {[C D A]L M[B D C]}
     {J[0 C 0 B]M[0 A 0 C]}
     {J L[D C B][D A C]}}
    (>K)$ %exch get %62 75
    [
        (>?)$ %exch exec %62 63
    ]
    transpose matmul
}fo %for
du %dup
%d %def
%{transpose matmul}fora d

%[E 9 11 10 8 9 13 15 11 3 7 15 14 10 2 6 14 12 8 0 4 12 13 5 7 6 4 5 1 3 2 0]
%<0001090b0a08090d0f0b03070f0e0a02060e0c0800040c0d050706040501030200>
%          abcdef
%0123456789:;<=>?
(019;:89=?;37?>:26><804<=576451320)
{48 su get % 169 75 %V (>K)$ %sub %exch get

    al po %aload pop %2 117
    {W Z Y X}{(>3)$ %exch def
    }fora %forall %2 117  62 51 73
    X G
    Y G
    {li}(D)# %stopped
    {mov}
    if du%(T8)$ %if %84 du %dup 56
}
%<49a7a1>$ %forall stroke showpage %73 167-95=72 161-95=66
fora(HB)#

Niegolfowany i lekko komentowany:

300 400 translate   %roughly center of letter paper
currentlinewidth
100 dup dup scale
div setlinewidth    %scale x100, reduce line-width/100
(mat.ps)run         %load matrix library
ARGUMENTS aload pop{f e d c b a}{exch cvr def}forall  %define args as 
                                 % a,b,etc and convert to real numbers
/m{2 mod .5 sub}def
/P{aload pop{w z y x}{exch def}forall   %P: [x y z w]  project-and-draw  -
    x 2 mul z 2 add div 
    y 2 mul z 2 add div 
    {lineto}stopped{moveto}if %catch(&handle!) nocurrentpoint error in lineto
}bind def
/V[0 1 15{    % generate vectors with a for-loop
    [ exch
        dup m
        1 index 2 idiv m
        2 index 4 idiv m
        4 3 roll 8 idiv m
    ]
}for]
[[[1 0 0 0][0 a cos a sin neg 0][0 a sin a cos 0][0 0 0 1]] 
     [[b cos 0 b sin 0][0 1 0 0][b sin neg 0 b cos 0][0 0 0 1]] 
     [[c cos c sin neg 0 0][c sin c cos 0 0][0 0 1 0][0 0 0 1]] 
     [[d cos 0 0 d sin][0 1 0 0][0 0 1 0][d sin neg 0 0 d cos]]
     [[1 0 0 0][0 e cos 0 e sin neg][0 0 1 0][0 e sin 0 e cos]]
     [[1 0 0 0][0 1 0 0][0 0 f cos f sin neg][0 0 f sin f cos]]]
{transpose matmul} forall def   % apply array of rotations and define

%Eulerian circuit (borrowed and adjusted for 0-based indexing)
[0 1 9 11 10 8 9 13 15 11 3 7 15 14 10 2 6 14 12 8 0 4 12 13 5 7 6 4 5 1 3 2 0]

% the main program!
% on the stack is the Eulerian circuit array
{
    V exch get  %lookup index in (sextuply-transformed) vertex array
    P           %call project-and-draw
} forall
closepath stroke %draw it, don't just think about it

showpage % gs's cmd-line-args option automatically sets -dBATCH,
    % so without a showpage, gs will immediately exit before you
    % can look at the picture :(

Niektóre z moich wyników są lustrzanymi odbiciami przykładów pytania.

Dla gs -- hc.ps 0 0 0 0 0 0otrzymuję:
wprowadź opis zdjęcia tutaj

gs -- hc.ps 0 0 0 0 0 30
wprowadź opis zdjęcia tutaj

gs -- hc.ps 30 0 0 0 0 30
wprowadź opis zdjęcia tutaj

gs -- hc.ps 0 0 0 30 30 30
wprowadź opis zdjęcia tutaj

gs -- hc.ps 45 45 45 0 0 0
wprowadź opis zdjęcia tutaj

gs -- hc.ps 45 45 45 45 45 45
wprowadź opis zdjęcia tutaj

Animacja bonusowa, którą właśnie wykonałem za pomocą tego programu. Ten obraz odpowiada sekwencji obrotu 0 30 60 0 i i , gdzie i wynosi od 0 do 360 o 2.
wprowadź opis zdjęcia tutaj


2
Łał. Odpowiedź PostScript na problem matematyczny.
TuxCrafting,

@ TùxCräftîñg W tym pytaniu nie ma tak dużo matematyki, o ile można łatwo pomnożyć macierz. I chciałem napisać ten program, odkąd przeczytałem AK Armewskiego Wszechświata AK Dewdneya .
luser droog

Dodano nowe funkcje do biblioteki G. Nie można go tutaj użyć, ale umożliwia wersję 307 bajtów .
luser droog

8

C # + Unity, 1060 845 835 bajtów

C # ≈ Java

Zakłada, że ​​ta funkcja jest umieszczona w skrypcie MainCamera.

Edycja:
Podziękowania dla @TuukkaX za sugestie dotyczące zaoszczędzenia 19 bajtów Zapisano ~ 200 bajtów przy użyciu cyklu Eulera.

Gra w golfa:

void d(float[]r){transform.position=Vector3.back*2;GetComponent<Camera>().backgroundColor=Color.black;Vector4[]p=new Vector4[16];Matrix4x4[]m=new Matrix4x4[6];int i=0;for(;i<16;i++)p[i]=new Vector4(i%2,i/2%2,i/4%2,i/8%2)-new Vector4(.5f,.5f,.5f,.5f);int[,]X={{6,8,1,12,7,11},{5,0,0,0,5,10},{10,10,5,15,15,15}};for(i=0;i<6;i++){m[i]=Matrix4x4.identity;r[i]=Mathf.Deg2Rad*r[i];float c=Mathf.Cos(r[i]),s=Mathf.Sin(r[i]);m[i][X[1,i]]=c;m[i][X[2,i]]=c;m[i][X[0,i]]=s;m[i][X[0,i]%4*4+X[0,i]/4]=-s;}for(i=0;i<16;i++)foreach(Matrix4x4 x in m)p[i]=x*p[i];int[]F={0,1,9,11,10,8,9,13,15,11,3,7,15,14,10,2,6,14,12,8,0,4,12,13,5,7,6,4,5,1,3,2,0};LineRenderer l=new GameObject().AddComponent<LineRenderer>();l.SetVertexCount(33);l.material=new Material(Shader.Find("Sprites/Default"));l.SetWidth(.03f,.03f);for(i=0;i<33;i++)l.SetPosition(i,p[F[i]]);

Nowe linie + wcięcie + Pełna powłoka:

using UnityEngine;
using System.Collections;

public class h : MonoBehaviour {

    void d(float[]r)
    {
        transform.position=Vector3.back*2.5f;
        GetComponent<Camera>().backgroundColor=Color.black;
        Vector4[]p=new Vector4[16];
        Matrix4x4[]m=new Matrix4x4[6];
        int i=0;
        for(;i<16;i++)p[i]=new Vector4(i%2,i/2%2,i/4%2,i/8%2)-new Vector4(.5f,.5f,.5f,.5f);
        int[,]X={{6,8,1,12,7,11},{5,0,0,0,5,10},{10,10,5,15,15,15}};
        for (i=0;i<6;i++){
            m[i]=Matrix4x4.identity;
            r[i]=Mathf.Deg2Rad*r[i];
            float c=Mathf.Cos(r[i]);
            float s=Mathf.Sin(r[i]);
            m[i][X[1,i]]=c;
            m[i][X[2,i]]=c;
            m[i][X[0,i]]=s;
            m[i][X[0,i]%4*4+X[0,i]/4]=-s;
        }
        for (i=0;i<16;i++)foreach(Matrix4x4 x in m)p[i]=x*p[i];
        int[]F={0,1,9,11,10,8,9,13,15,11,3,7,15,14,10,2,6,14,12,8,0,4,12,13,5,7,6,4,5,1,3,2,0};
        LineRenderer l=new GameObject().AddComponent<LineRenderer>();
        l.SetVertexCount(33);
        l.material=new Material(Shader.Find("Sprites/Default"));
        l.SetWidth(.03f,.03f);
        for (i=0;i<33;i++)
            l.SetPosition(i,p[F[i]]);
        l.gameObject.tag = "Player";
    }
    public float[] input;
    void Start()
    {
        d(input);
    }
}

Nie mogłem wymyślić prostej formuły do ​​konstruowania macierzy rotacji ani „ścian”, które należy narysować, tak że kodowanie kosztowało dużo bajtów. Pożyczałem cykl Eulera od @beaker. Ponadto wbudowane w Unity są bardzo gadatliwe.

Możesz zweryfikować wszystkie przypadki testowe online .


Po raz pierwszy widzę tutaj odpowiedź C # + Unity. +1
DanTheMan

Myślę, że wszystko 0.5fmożna zredukować do .5fi 0.01fdo .01f. Myślę też, że tablice liczb całkowitych można oddzielić przecinkiem zamiast powtarzać int[]wiele razy.
Yytsi

@Blue Och, masz rację! Nie używałem C # przez jakiś czas, więc nie byłem pewien ostatniej wskazówki.
Yytsi

@TuukkaX Zignoruj ​​mój poprzedni komentarz, mogę użyć int[,]. Wciąż dziękuję.
Blue

Nadal masz coś, Vector4(0.5f,0.5f,0.5f,0.5f)co można zmniejszyć Vector4(.5f,.5f,.5f,.5f).
Yytsi

6

JavaScript ES6, 584 bajty

f=(...R)=>(P=s=>[...s].map(i=>parseInt(i,16)),C=document.createElement`canvas`,X=C.getContext`2d`,X.translate((C.width=300)/2,(C.height=300)/2),X.lineWidth=0.01,X.scale(100,100),X.beginPath(),P("0267fd9804c8ab915dcefb37546ea2310").map((e,i)=>{[x,y,z]=P("084c2a6e195d3b7f").map(i=>[...(1e3+i.toString(2)).slice(-4)].map(i=>i-0.5)).map(e=>(R.map((R,i,_,M=Math,C=M.cos(r=R*M.PI/180),S=M.sin(r))=>((a,b,s=1)=>[e[a],e[b]]=[C*e[a]-s*S*e[b],s*S*e[a]+C*e[b]])(...[[1,2],[0,2,-1],[0,1],[0,3,-1],[1,3],[2,3]][i])),e))[e];[x,y]=[2*x/(2+z),2*y/(2+z)];i?X.lineTo(x,y):X.moveTo(x,y)}),X.stroke(),C)

„Nie golf”:

f=(...R)=>(                                                              // function that accepts rotations in the following form: f(a,b,c,d,e,f)
    P=s=>[...s].map(i=>parseInt(i,16)),                                  // function to convert strings to hex-arrays
    V=P("084c2a6e195d3b7f")                                              // vertices encoded as hex values ( [0,1,1,0] -> 6 )
        .map(i=>[...(1e3+i.toString(2)).slice(-4)].map(i=>i-0.5))        // convert hex values to vertices, center the hypercube
        .map(e=>(R.map((R,i,_,M=Math,C=M.cos(r=R*M.PI/180),S=M.sin(r))=> // convert angles to degrees, precalculate sin and cos values
        ((a,b,s=1)=>[e[a],e[b]]=[C*e[a]-s*S*e[b],s*S*e[a]+C*e[b]])       // apply matrix transforms to all vertices
        (...[[1,2],[0,2,-1],[0,1],[0,3,-1],[1,3],[2,3]][i])),e)),        // list of encoded matrix transforms
    C=document.createElement`canvas`,X=C.getContext`2d`,                 // create image to draw on
    X.translate((C.width=300)/2,(C.height=300)/2),                       // setup image dimensions, center transform
    X.lineWidth=0.01,X.scale(100,100),X.beginPath(),                     // setup line, scale the transform and begin drawing
    P("0267fd9804c8ab915dcefb37546ea2310").map((e,i)=>{                  // hypercube edge path indices encoded as hex values
        [x,y,z]=V[e];[x,y]=[2*x/(2+z),2*y/(2+z)];                        // project vertex
        i?X.lineTo(x,y):X.moveTo(x,y)}),X.stroke(),                      // draw vertex
    C)                                                                   // return image

Zobacz to w akcji (zmodyfikowane w celu ciągłego obracania):

with(document)with(Math)with(document.getElementById`canvas`)with(getContext`2d`){render=()=>{requestAnimationFrame(render);clearRect(0,0,width,height);save();K=performance.now();R=[K*0.01,K*0.02,K*0.03,K*0.04,K*0.05,K*0.06];X=s=>[...s].map(i=>parseInt(i,16));V=X("084c2a6e195d3b7f").map(i=>[...(1e3+i.toString(2)).slice(-4)].map(i=>i-0.5)).map(e=>(R.map((R,i,_,C=cos(r=R*PI/180),S=sin(r))=>((a,b,s=1)=>[e[a],e[b]]=[C*e[a]-s*S*e[b],s*S*e[a]+C*e[b]])(...[[1,2],[0,2,-1],[0,1],[0,3,-1],[1,3],[2,3]][i])),e));translate((width=300)/2,(height=300)/2);lineWidth=0.01;scale(100,100);beginPath();X("0267fd9804c8ab915dcefb37546ea2310").map((e,i)=>{[x,y,z]=V[e];[x,y]=[2*x/(2+z),2*y/(2+z)];i?lineTo(x,y):moveTo(x,y)});stroke();restore();};render();}
<html><body><canvas id="canvas"></canvas></body></html>

Funkcja zwraca obiekt canvas HTML5, musisz na przykład dodać go do strony document.body.appendChild(f(0,0,0,0,0,0)).

Obecnie rotacje są stosowane w kolejności, pracuję nad zmianą kolejności, ale jak to jest, to poprawnie obraca hipersześcian.


Sprytnie zajęło mi trochę czasu, aby dowiedzieć się, co robisz z transformacjami macierzowymi. : D Poza tym nie mogę uruchomić fragmentu kodu ... daje mi to nieprzydatny „błąd skryptu”. w linii 0.
zlewka

@beaker Z jakiej przeglądarki korzystasz? Przetestowałem to na najnowszym Firefoksie.
Dendrobium

Jestem na Safari 9.1.1. Pozwól mi spróbować innego.
zlewka

1
Tak, Chrome działa dobrze.
zlewka

1
Safari to bzdury. Nie używaj go do sprawdzania, czy coś działa.
Patrick Roberts,

1

Mathematica, 453 415 bajtów *

Skrócono przez użycie trasy Eulerian i oczyszczenie jej w jedną instrukcję bez definiowania funkcji w zmiennych. Z jakiegoś powodu powoduje to spowolnienie kodu. Zgaduję, że Mathematica wielokrotnie ocenia te funkcje teraz, gdy nie są one przechowywane w zmiennej.

Graphics[Line[Table[{2#/(2+#3),2#2/(2+#3)}&@@Map[Dot@@Table[Table[If[n==m==#2||n==m==#,Cos[#3],If[n==#2&&m==#,If[#2==1&&(#==3||#==4),1,-1]Sin[#3],If[n==#&&m==#2,If[#2==1&&(#==3||#==4),-1,1]Sin[#3],If[n==m,1,0]]]],{n,4},{m,4}]&[k[[1]],k[[2]],a[[k[[3]]]]°],{k,{{4,3,6},{4,2,5},{4,1,4},{2,1,3},{3,1,2},{3,2,1}}}].#&,Tuples[{0,1},4]-.5,{1}][[i]],{i,{1,2,10,12,11,9,10,14,16,12,4,8,16,15,11,3,7,15,13,9,1,5,13,14,6,8,7,5,6,2,4,3,1}}]]]

* Liczę °i ==jako pojedyncze bajty, ponieważ są one reprezentowane jako pojedynczy znak w Mathematica. Myślę, że to uczciwe, ponieważ wiele języków używa dziwnych kodowań znaków.

Nie golfił z komentarzami. Wejście jest na stałe zakodowane na górze jako a={30,0,0,0,0,30};. Nie wliczałem tego do mojego wyniku.


a = {45, 45, 45, 45, 45, 45};



(* #2,#-th rotation matrix as a funciton of #3 *)
(* Using the \
#-notation saved 6 bytes over the more common function definition \
notation*)
r = 
  Table[If[n == m == #2 || n == m == #, Cos[#3], 
     If[n == #2 && m == #, 
      If[#2 == 1 && (# == 3 || # == 4), 1, -1] Sin[#3], 
      If[n == # && m == #2, 
       If[#2 == 1 && (# == 3 || # == 4), -1, 1] Sin[#3], 
       If[n == m, 1, 0]]]], {n, 4}, {m, 4}] &;

(* Total rotation matrix. Need six of them. Function of the six \
angles to rotate.*)

u = Dot @@ 
     Table[r[k[[1]], 
       k[[2]], \[Degree]*
        a[[k[[3]]]]], {k, {{4, 3, 6}, {4, 2, 5}, {4, 1, 4}, {2, 1, 
         3}, {3, 1, 2}, {3, 2, 1}}}].# &;



(* List of all vertices of the hypercube *)
t = Tuples[{0, 1}, 4];
t -= .5;
v = Map[u, t, {1}];

(*projection*)
p = {2 #/(2 + #3), 2 #2/(2 + #3)} &;

(*Eulerian tour*)

l = Table[
   p @@ v[[i]], {i, {1, 2, 10, 12, 11, 9, 10, 14, 16, 12, 4, 8, 16, 
     15, 11, 3, 7, 15, 13, 9, 1, 5, 13, 14, 6, 8, 7, 5, 6, 2, 4, 3, 
     1}}];
Graphics[Line[l]]

0 0 0 0 0 30

0 0 0 30 30 30

wprowadź opis zdjęcia tutaj

405 10 -14 -8 -9 205

wprowadź opis zdjęcia tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.