Animuj obracającą się figurę Lissajous

15

Zgłoszenia do tego wyzwania będą zawierać animowaną obracającą się figurkę Lissajous . Pojawienie się obrotu 3d występuje, gdy parametr x jest kolejno przesuwany fazowo w każdej klatce.

Wejście:

aI bparametry (zgodnie z art wikipedia ) zostaną podane w wierszu poleceń, lub czytać ze standardowego wejścia.

Wynik:

Jest to , więc dane wyjściowe będą wyświetlane w oknie emulatora terminala lub równorzędnym. Rozmiar wyjściowy może być zakodowany na stałe, ale liczba Lissajous musi być co najmniej wystarczająco duża, aby wypełnić okno 80x24.

Szybkość klatek animacji wyniesie około 50 kl./s. Spanie przez 20 ms między każdą klatką jest w porządku, pod warunkiem, że czas obliczenia każdej ramki jest niewielki w porównaniu ze stałym czasem uśpienia. Jeśli Twój wybór języka nie jest w stanie obliczyć wystarczająco szybko na wybranej platformie, musisz obliczyć czas do spania dynamicznie.

Każda ramka nie będzie wyświetlana, dopóki wszystkie obliczenia dla tej ramki nie zostaną zakończone. Nie ma potrzeby czyszczenia ekranu między poszczególnymi ramkami.

Figurka wykona pełny 2*Piobrót co około 4 sekundy.

Dla każdej ramki należy wygenerować krzywą całkowicie zamkniętą. Należy obliczyć co najmniej 1000 punktów wzdłuż krzywej. Rysowanie linii między punktami nie jest konieczne.

Punkty krzywej zostaną wykreślone jako #znaki. Reszta obszaru wyświetlania będzie pusta / biała.

To jest , więc najkrótsza odpowiedź w bajtach (uważana przeze mnie za akceptowalną) zostanie przyjętym zwycięzcą tydzień po opublikowaniu.


Nieodniesiona odpowiedź referencyjna .

Cyfrowa trauma
źródło
1
Czy wolno nam rysować w języku graficznym?
TheDoctor
@Doctor Byłem rozdarty, ale postanowiłem ograniczyć się do sztuki ascii . Być może możemy wykonać graficzną kontynuację, jeśli okaże się to popularne.
Cyfrowa trauma
1
Podobnie jak w przypadku wielu obracających się figurek, liczby te obracają się na różne sposoby w zależności od tego, jak na nie patrzysz. Na przykład twoja odpowiedź wydaje mi się kołysać w tę iz powrotem. Ale kiedy się staram, widzę regularną rotację.
Justin

Odpowiedzi:

7

Perl - 177

while($d+=.1){print"\e[H\e[2J";$a=0;while(($a+=.01)<4*atan2 1,0){$x=$==40+40*cos$d+$a*$ARGV[0];$y=$==13+13*sin$d+$a*$ARGV[1];print"\e[$y;$x"."H#";}print$/;select($v,$v,$v,.03);}

Współczynniki są przekazywane za pomocą argumentów. Powyższy gif jest produkowany zperl % 2 3

mniip
źródło
1
@DigitalTrauma Mam własne narzędzie do nagrywania ekranu w X11
mniip
7

C (odpowiedź referencyjna - bez gry w golfa)

Wyjście z ./lissajous 2 3:

wprowadź opis zdjęcia tutaj

/*
 * lissajous.c
 *
 * Compile with:
 *   cc lissajous.c -lm -o lissajous
 *
 * Usage:
 *   ./lissajous a b
 *
 * a and b are the parameters as described in:
 * http://en.wikipedia.org/wiki/Lissajous_curve
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>

int main (int argc, char **argv) {
    char buffer[25][80];
    double t, p;
    int x, y;
    int a, b;

    if (argc != 3) return 1;

    a = atoi(argv[1]);
    b = atoi(argv[2]);

    for (;;) {
        for (p = 0; p < 2 * M_PI; p += M_PI / 100) {
            memset(buffer, ' ', sizeof(buffer));
            /* Set 1st char of final line to nul.  Then we can printf
             * the whole 2d array as if it were one long 1d buffer.
             * Line wraps at 80 chars are assumed */
            buffer[24][0] = 0;
            for (t = 0; t < 2 * M_PI; t += M_PI / 500) {
                x = 39.5 * (1 + sin(a * t + p));
                y = 11.5 * (1 + sin(b * t)); 
                buffer[y][x] = '#';
            }
            printf("%s\n", &buffer[0][0]);
            usleep(20000);
        }
    }
    return (0);
}

C, 257 bajtów

Ok, cóż, sam nie mogłem się oprzeć golfowi. Myślę jednak, że jest o wiele więcej do gry w golfa:

#include<math.h>
main(int a,char**v){char x,y,b,d[25][80];double t,p,q=2*M_PI;a=atoi(v[1]);b=atoi(v[2]);for(p=0;memset(d,32,2000);p+=q/100){p=p<q?p:0;d[24][0]=0;for(t=0;t<q;y=11.5*sin(b*t)+12,d[y][x]=35,t+=q/1e3)x=39.5*sin(a*t+p)+40;puts(d);usleep(20000);}}
Cyfrowa trauma
źródło
2
zabawne, jak odpowiedź referencyjna zyskuje na popularności ...
TheDoctor
@Doctor Wiem, prawda. Właśnie dlatego dodałem wersję w golfa, ponieważ nie przychodziło mi przychylne głosowanie za nie golfową odpowiedzią.
Cyfrowa trauma
Jeśli jesteś usleepna 20000 ms, dlaczego nie tylko sleepna 20s?
user12205
usleep @ace (20000) 20000 == mikro sekund, a nie 20000 Milli sekund
cyfrowy Trauma
Ups, przepraszam, mój zły. Co usleep(2e4);?
user12205
2

Python 3 - 280

Przepraszam, nie mam dla ciebie żadnego z tych fantazyjnych animowanych gifów. Konsola Windows wolno drukuje: P

Nie jestem pewien, czy spełnia to wymagania 50 klatek na sekundę, ale nie jestem pewien, czy to naprawdę możliwe w przypadku Pythona. Możesz wyregulować 1000 w drugim wierszu dla liczby punktów do obliczenia (lista to szerokość wyjściowa, wysokość wyjściowa, punkty do znalezienia, postęp na klatkę (pi * 2 / n) i punkt początkowy). Lub możesz je usunąć i określić również w danych wejściowych.

import math as m
a,b,w,h,p,r,t=list(map(int,input().split()))+[79,24,1000,100,0]
while 1:v,z=w/2,h/2;d=[[int(m.sin(a*k+t)*v+v),int(m.sin(b*k)*z+z)]for k in[m.pi*2/p*l for l in range(p)]];print('\n'.join(''.join([' ','#'][[i,j]in d]for i in range(w))for j in range(h)));t+=m.pi*2/r

WIĘCEJ WAŻNEJ EDYCJI: Wejście przez stdin, rozdzielone spacjami, zakończone znakiem nowej linii. Będzie czekać na twoje dane wejściowe.

EDYCJA: zrzut ekranu. W tym przypadku zmieniono wysokość na 40.

Renderowanie Lissajous

cjfaure
źródło
Hmm, po prostu zawiesza się dla mnie z Pythonem 3.2.3 (i 2.7.3) na Ubuntu. Chyba muszę skądś wykopać maszynę wirtualną z systemem Windows. Lub naucz się pytona.
Cyfrowa trauma
@DigitalTrauma Hm. Używam 3.3.2. Dziwne, że to nie działa, ale nie widzę żadnych procedur specyficznych dla platformy w moim kodzie.
cjfaure
Zapisz jako lissajous.py, a następnie bieg python3 lissajous.py 2 3powinien wystarczyć, prawda?
Cyfrowa trauma
@DigitalTrauma Och, och, przepraszam. Wymaga danych wejściowych stdin, a nie argumentów (nie udało się określić, że ... oops). Rozdzielone spacjami.
cjfaure
Aha - Chyba powinienem to zobaczyć input()i zgadłem. Działa dobrze dla mnie teraz z 3.2.3. +1
Cyfrowa trauma
1

C # - 360 352 (dla wielu platform - 332 tylko dla systemu Windows)

Edytowane po naprawie błędu mikro golfa i zaokrąglania + sugestia Ypnypn

Nie do końca kandydat na taką długość - i jest to dosłownie kopia referencji - ale no cóż. :)

namespace System{class P{static int Main(string[]m){double p=Math.PI*2,a=int.Parse(m[0]),b=int.Parse(m[1]),q,t;for(;;)for(q=0;q<p;q+=p/200){var s=new string(' ',1920).ToCharArray();for(t=0;t<p;t+=p/1000)s[(int)(39.5*Math.Sin(a*t+q)+40)+(int)(11.5*Math.Sin(b*t)+12)*80]='#';Console.SetCursorPosition(0,0);Console.Write(s);Threading.Thread.Sleep(20);}}}}

Wieprz pamięci, tworząc nową tablicę dla każdego odświeżania - pierwotnie (ponownie) używał StringBuilder, ale poświęcił go dla skrócenia. Ale przynajmniej odświeżenie zajmuje mniej niż 1 ms na moim starym Core2.

Po usunięciu niektórych - teraz bolesnych dla długości - starych golfów, zmniejszając w ten sposób o 8 znaków, próbowałem przywrócić go do „poetyckiego” 360, powracając do podwójnej zamiast int parsowania i powracając do 80 * 24 zamiast 1920. To wciąż tylko 359 - i żaden inny pojedynczy znak, który mogę wymyślić, nie wnosi żadnej wartości do kodu. Pozostaniemy więc przy 352. :-)

Unrolled (zgubiłem kod przed golfa):

namespace System
{
    class P
    {
        static int Main(string[] m)
        {
            double p = Math.PI * 2,
                   a = int.Parse(m[0]),
                   b = int.Parse(m[1]),
                   q, t;

            for (;;)
            {
                for (q = 0; q < p; q += p/200)
                {
                    var s = new string(' ', 1920).ToCharArray();
                    // Alternative - Windows console only:
                    // var s = new char[1920];

                    for (t = 0; t < p; t += p/1000)
                    {
                        s[
                            (int) (39.5*Math.Sin(a * t + q) + 40)
                          + (int) (11.5*Math.Sin(b * t) + 12) * 80
                        ] = '#';
                    }
                    Console.SetCursorPosition(0, 0);
                    Console.Write(s);
                    Threading.Thread.Sleep(20);
                }
            }
        }
    }
}

Konsola systemu Windows akceptuje generowanie dużej liczby znaków zerowych, co daje wynik (graficznie) identyczny z użyciem rzeczywistego znaku spacji - co pozwala na zainicjowanie tablicy znaków o kilka znaków mniej.

Brak wymyślnej animacji, przepraszam :-)

JimmiTh
źródło
Konsola systemu Windows akceptuje generowanie wielu zerowych znaków . Ach, może to wyjaśnia, dlaczego nie jest tak dobrze z mono na Ubuntu. Nie mam teraz pod ręką Windows / .net, więc uwierzę ci na słowo, że działa.
Cyfrowa trauma
Właśnie dodałem zrzut ekranu - powinien sprawić, że stanie się wieloplatformowy, ale biorąc pod uwagę status, który już nie ma pretendenta - i raczej „poetycką” liczbę znaków, być może powinno się go po prostu pozostawić takim, jakim jest. :-)
JimmiTh
Nie ma potrzeby, aby wszystkie odpowiedzi były wieloplatformowe IMO. Jeśli odpowiedzi są specyficzne dla platformy, warto wspomnieć o platformie, chociaż C # jest tak dobrze znany, że jest już oczywisty.
Cyfrowa trauma
Czy using C = Consolenaprawdę zapisuje jakieś postacie?
Ypnypn
@Ypnypn - nie po inwazji na przestrzeń nazw Systemu, nie. Nie zmieniłem go ani nie poszukałem, ponieważ samozwańczym celem było dotarcie do tych samych 360 znaków przy jednoczesnym zastosowaniu „właściwej” inicjalizacji tablicy znaków. Dzięki. :-)
JimmiTh
1

Python 2.7 - 214

Myślę, że jeszcze raz na to spojrzę. Mam wrażenie, że można to jeszcze bardziej obniżyć, ale trudno będzie trafić liczbę bajtów Perla. Matematyka wydaje się tutaj moim największym ograniczeniem.

Ostrzeżenie: może wystąpić awaria dowolnego używanego terminala. Przetestowałem to w wierszu polecenia systemu Windows za pomocą lissajous.py 2 3. Ze względu na szybkie pisanie w wierszu polecenia, spodziewaj się, że ramki nieco podskoczą. Można to w większości rozwiązać (kosztem prędkości), używając większej sw range(s)i t=2*pi*i.

Nie używam \rani \btutaj celowo, ponieważ uruchamiam go w systemie Windows i kosztuje to dodatkowe znaki.

from math import*;import sys;a,b=sys.argv[1:];p=s=1920
while p:
 c = [" "]*s
 for i in range(s):
    t=2*pi*i/s;c[int(round((39.5*(1+sin(eval(a)*t+p))))+round(11.5*(1+sin(eval(b)*t)))*80)]="#"
 print ''.join(c)
 p+=.1
gajeNL
źródło
+1 Działa na Ubuntu, choć wyjście jest nieco przesadzone
Digital Trauma
@DigitalTrauma Tak, ta przepychanka jest spowodowana tym, że jest to rozwiązanie wieloplatformowe (tj. Działa w wierszu polecenia systemu Windows).
gajeNL