Losuj punkty na dysku


14

Czytałem gdzieś o kręgach, a teraz dowiedziałem się o dyskach ( to właściwie dość powszechna koncepcja ) i pomyślałem o codegolfie.

Twoim zadaniem jest zrandomizowanie punktu / kilku punktów na dysku o promieniu 1.

Zasady:

  • Wszystkie punkty muszą mieć jednakowe prawdopodobieństwo wygenerowania
  • Należy użyć współrzędnych zmiennoprzecinkowych; minimalny wymóg to dwa miejsca po przecinku (np. punkty (0.12, -0.45)lub (0.00, -1.00)są ważne)
  • Otrzymasz -20 bajtów, jeśli twój program faktycznie wyświetla okrąg ograniczający i wygenerowane w nim punkty. Współrzędne nadal muszą być prawidłowe, ale nie wyświetlane, a wygenerowany obraz musi mieć rozmiar co najmniej 201 na 201 pikseli
  • Otrzymasz -5 bajtów, jeśli twój program pobierze liczbę punktów do wygenerowania jako wejście na standardowe wejście
  • Jeśli zdecydujesz się nie drukować okręgu ograniczającego i punktów, twój program musi wypisać punkty wygenerowane w formacie (x, y)lub (x,y)na standardowym wyjściu
  • Jeśli zdecydujesz się przyjąć liczbę wygenerowanych punktów jako dane wejściowe, ale nie wykreślić go - Twój program musi wypisać wszystkie losowe punkty w formacie określonym powyżej z jedną spacją między nimi lub bez

Najkrótsze przesłanie w bajtach wygrywa!


1
@sweerpotato Tak, proszę określić, że wszystkie punkty wi na okręgu są prawidłowe. Nie zdawałem sobie sprawy, że masz na myśli jedno i drugie. Wydaje się, że to pytanie lepiej pasowałoby do gry w golfa kodowego niż w konkurs popularności, ale to tylko moja opinia.
cole

5
Wykonaj XYZ w sposób kreatywny ” to klasyczne pytanie Bad Popcon ™. To, co jedna osoba uważa za kreatywne, to to, co druga uważa za oczywisty sposób.
Peter Taylor,

Z ciekawości, dlaczego wymóg wydruku 201x201 pikseli dla wykresów?
JohnE

@JohnE Zasugerowałem 201x201 pikseli, ponieważ odpowiada wymaganej dokładności 2 miejsc po przecinku
trichoplax

Czy możemy wyprowadzić współrzędne jako liczby zespolone? Na przykład: 0.3503082505747327+0.13499221288682994j.
orlp

Odpowiedzi:


5

Pyth, 26 - 5 = 21 bajtów

VQp(sJ*@OZ2^.n1*yOZ.l_1)eJ

Pobiera liczbę współrzędnych do wygenerowania na stdin i wysyła je na stdout w następujący sposób:

(-0.5260190768964058, -0.43631187015380823)(-0.12127959509302746, -0.08556306418467638)(-0.26813756369750996, -0.4564539715526493)

Stosuje strategię podobną do @ MartinBüttner, generując współrzędne biegunowe i promienie, z tym wyjątkiem, że używa złożonego potęgowania.


Możesz usunąć p, prawda? Po prostu zmienia wyjście na oddzielne linie.
PurkkaKoodari,

@ Pietu1998 To niedozwolone, zobacz komentarze do głównego pytania.
orlp

Oh, dobrze.
PurkkaKoodari,

16

CJam, 28 27 bajtów

PP+mr_mc\ms]1.mrmqf*"(,)".\

To rozwiązanie nie opiera się na odrzuceniu. Generuję punkty we współrzędnych biegunowych, ale z nierównomiernym rozkładem promieni, aby uzyskać jednolitą gęstość punktów.

Sprawdź to tutaj.

Wyjaśnienie

PP+     e# Push 2π.
mr_     e# Get a random float between 0 and 2π, make a copy.
mc\     e# Take the cosine of one copy and swap with the other.
ms]     e# Take the sine of the other copy and wrap them in an array.
        e# This gives us a uniform point on the unit circle.
1.mr    e# Get a random float between 0 and 1.
mq      e# Take the square root. This is the random radius.
f*      e# Multiply x and y by this radius.
"(,)".\ e# Put the resulting numbers in the required format.

Dlaczego to działa? Rozważmy wąski pierścień o promieniu ri (małej) szerokości dr. Obszar jest w przybliżeniu 2π*r*dr(jeśli pierścień jest wąski, obwód wewnętrzny i zewnętrzny są prawie identyczne, a krzywiznę można zignorować, tak że obszar można traktować jak prostokąt o bokach o obwodzie i szerokości pierścień). Zatem obszar zwiększa się liniowo wraz z promieniem. Oznacza to, że chcemy również liniowego rozkładu promieni losowych, aby uzyskać stałą gęstość (przy podwójnym promieniu jest dwa razy więcej miejsca do wypełnienia, więc chcemy tam dwa razy więcej punktów).

Jak wygenerować liniowy rozkład losowy od 0 do 1? Najpierw spójrzmy na dyskretny przypadek. Powiedzmy, że mamy pożądany rozkład 4 wartości, takich jak {0.1, 0.4, 0.2, 0.3}(tzn. Chcemy 1być 4 razy tak powszechne jak 0i dwa razy tak powszechne jak 2; chcemy 3trzy razy częściej niż 0):

enter image description here

Jak wybrać jedną z czterech wartości o pożądanym rozkładzie? Możemy je ułożyć w stos, wybrać równomiernie losową wartość od 0 do 1 na osi y i wybrać segment w tym punkcie:

enter image description here

Istnieje jednak inny sposób wizualizacji tego wyboru. Zamiast tego możemy zastąpić każdą wartość rozkładu akumulacją wartości do tego momentu:

enter image description here

A teraz traktujemy górną linię tego wykresu jako funkcję f(x) = yi odwracamy ją, aby uzyskać funkcję , którą możemy zastosować do równomiernie losowej wartości w :g(y) = f-1(y) = xy ∈ [0,1]

enter image description here

Fajnie, więc jak wykorzystać to do generowania liniowego rozkładu promieni? Oto rozkład, który chcemy:

enter image description here

Pierwszym krokiem jest zebranie wartości rozkładu. Ale rozkład jest ciągły, więc zamiast sumowania wszystkich poprzednich wartości, bierzemy całkę od 0do r. Możemy łatwo rozwiązać ten analitycznie: . Chcemy jednak to znormalizować, tzn. Pomnożyć przez stałą, tak aby to dało maksymalną wartość , więc tak naprawdę chcemy :0r r dr = 1/2 r21rr2

enter image description here

I na koniec odwracamy to, aby uzyskać funkcję, którą możemy zastosować do jednolitej wartości [0,1], którą możemy ponownie wykonać analitycznie: po prostu r = √y, gdzie yjest wartość losowa:

enter image description here

Jest to dość użyteczna technika, która często może być używana do generowania prostych rozkładów dokładnie (działa dla każdego rozkładu, ale w przypadku skomplikowanych dwa ostatnie kroki mogą wymagać rozwiązania numerycznego). Nie użyłbym go jednak w tym konkretnym przypadku w kodzie produkcyjnym, ponieważ pierwiastek kwadratowy, sinus i cosinus są zbyt drogie: użycie algorytmu opartego na odrzucaniu jest średnio znacznie szybsze, ponieważ wymaga tylko dodawania i mnożenia.


1
Bardzo miłe wytłumaczenie!
sweerpotato,

2
Zdjęcia mm: D
rozpad beta

12

Mathematica, 68 44-20 = 24 bajtów

Bardzo dziękuję Davidowi Carraherowi za poinformowanie mnie o tym RandomPoint, co pozwoliło zaoszczędzić 24 (!) Bajtów. Mathematica ma mieć wbudowaną za wszystko.

Graphics@{Circle[],Point@RandomPoint@Disk[]}

To wykreśla punkt i okrąg ograniczający, aby zakwalifikować się do premii:

enter image description here

Rezultatem jest obraz wektorowy, więc specyfikacja wielkości 201 x 201 pikseli naprawdę nie ma sensu, ale domyślnie renderuje większy.


Jak o Graphics[{Circle[], Point@RandomPoint@Disk[]}]?
DavidC,

Bądź moim gościem. Ponadto, aby zaoszczędzić 1 bajt ...Graphics@{Circle[], Point@RandomPoint@Disk[]}
DavidC

@DavidCarraher Wielkie dzięki! :)
Martin Ender

Nie znam składni Mathematica, ale na pewno możesz zapisać kolejny bajt, usuwając spację po znaku ,?
puszysty

@fluffy Zrobiłem już w opublikowanej wersji
Martin Ender

9

CJam, 31 26 bajtów

{];'({2dmr(_}2*@mhi}g',\')

Działa to poprzez wielokrotne generowanie losowych punktów w kwadracie o długości boku 2 i zatrzymywanie pierwszego, który wpada w dysk jednostki.

Dzięki @ MartinBüttner za grę w golfa z 3 bajtów!

Wypróbuj online w interpretatorze CJam .

Jak to działa

{                  }g       Do:
 ];'(                         Clear the stack and push a left parenthesis.
     {      }2*               Do twice:
      2dmr                      Randomly select a Double between 0 and 2.
          (_                    Subtract 1 and push a copy.
               @              Rotate the copy of the first on top of the stack.
                mh            Compute the Euclidean norm of the vector consisting
                              of the two topmost Doubles on the stack.
                  i           Cast to integer.
                            If the result is non-zero, repeat the loop.
                     ',\    Insert a comma between the Doubles.
                        ')  Push a right parenthesis.

8

iKe , 53 51 bajtów

Nic szczególnego, ale przypuszczam, że powinniśmy mieć co najmniej jedno rozwiązanie graficzne:

,(80+160*t@&{.5>%(x*x)+y*y}.+t:0N 2#-.5+?9999;cga;3)

wątek

Wypróbuj w swojej przeglądarce .

Edycja: Mogę zgolić dwa bajty, stosując podejście @ MartinBüttnera do modyfikacji rozkładu współrzędnych biegunowych. Myślę, że jest to również bardziej bezpośrednie:

,(80*1+(%?c){x*(cos y;sin y)}'6.282*?c:9999;cga;3)

3
Jeśli narysujesz również okrąg ograniczający, kwalifikujesz się do -20.
orlp

1
iKe ma oparty na rastrze model rysowania, co czyni ten wymóg raczej niesprawiedliwym. Myślę, że zrobienie przybliżenia okręgu ograniczającego kosztowałoby nieco ponad 20 znaków.
JohnE

7

Perl, 59 bajtów

while(($x=1-rand 2)**2+($y=1-rand 2)**2>1){};print"($x,$y)"

To tylko proste rozwiązanie, generujące punkty w kwadracie i odrzucające je zbyt daleko. Moją szczególną sztuczką w golfa jest uwzględnienie zadań wewnątrz warunku.

Edycja: W trakcie gry w golfa znalazłem interesujący sposób drukowania losowych punktów na kole .

use Math::Trig;$_=rand 2*pi;print"(",sin,",",cos,")"

7

Oktawa, 24 53-20 = 33 bajtów

polar([0:2e-3:1,rand]*2*pi,[ones(1,501),rand^.5],'.')

Generuje 501 równomiernie rozmieszczonych wartości theta plus jedną liczbę losową i skaluje je wszystkie do [0..2π]. Następnie generuje 501 1 dla promienia okręgu, plus losowy promień punktu i bierze pierwiastek kwadratowy, aby zapewnić równomierny rozkład na dysku. Następnie rysuje wszystkie punkty jako współrzędne biegunowe.

wprowadź opis zdjęcia tutaj


Oto krótka demonstracja rozkładu (bez koła jednostki):

polar(2*pi*rand(99),rand(99).^.5,'.')

9801 punktów


5

Octave / Matlab, 74 64 bajtów

Metoda odrzucenia , 64 bajty:

u=1;v=1;while u^2+v^2>1
u=rand;v=rand;end
sprintf('(%f,%f)',u,v)

Metoda bezpośrednia , 74 bajty (podziękowania dla Martina Büttnera za pomoc w poprawieniu dwóch błędów):

t=rand*2*pi;r=1-abs(1-sum(rand(2,1)));sprintf('(%f,%f)',r*cos(t),r*sin(t))

5

R, 99 95 81-20 = 79 75 61 bajtów

symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))

Użyj konstrukcji liczb zespolonych, aby zbudować x / y ze współrzędnych biegunowych. Biorąc wkład był nieco drogi i prawdopodobnie jest na to lepszy sposób. ylim Ixlim ma na celu zapewnienie cały krąg wykreślono iasp zapewnia punkty pokazane są pod symbolem okręgu.

Dzięki @jbaums i @flodel za oszczędności

Wypróbuj tutaj


runif(9,0,1)można uprościćrunif(9)
jbaums

@jbaums, dzięki ... jedna z rzeczy, o których zawsze zdaje się zapominać :)
MickyT

Można ogolić 14:symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
flodel

@flodel bardzo miło dziękuję.
MickyT,

Kolejne małe oszczędności: ylidziała zamiast ylim.
jbaums

4

Przetwarzanie / Java 141 bajtów-20 = 121

wymóg, aby 201 * 201 był minimalnym rozmiarem, wymaga ode mnie wprowadzenia setupmetody, ponieważ Processing.org ma domyślną wartość 200 x 200 :(

void setup(){noFill();size(201,201);}void draw(){float f=10,a=PI*2*random(),r=random();point(f+f*sin(a)*r,f+f*cos(a)*r);ellipse(f,f,f*2,f*2)}

Nie wiedziałem, że przetwarzanie / Java jest dozwolone, fajnie!
J Atkin,

4

QBasic, 138 bajtów - 20-5 = 113

INPUT n
r=200
SCREEN 12
RANDOMIZE TIMER
CIRCLE(r,r),r
PAINT(r,r)
FOR i=1TO n
DO
x=RND*r*2
y=RND*r*2
LOOP UNTIL POINT(x,y)
PSET(x,y),1
NEXT

Bierze dane wejściowe użytkownika i rysuje dysk i punkty. Testowane na QB64 .

Jest to dość prosta strategia „rzut na tarczę i trzymaj to, co się trzyma”. Haczyk polega na tym, że „tego, co się trzyma”, nie określa się matematycznie, lecz graficznie: na czarnym tle wykreślany jest biały dysk, a następnie losowo generowane punkty są odrzucane, aż nie będą czarne. Same punkty są narysowane na niebiesko (choć trudno powiedzieć, kiedy są pojedynczymi pikselami - kliknij obraz, aby powiększyć).


3

awk - 95 - 5 = 90

{
    for(;$1--;printf"("(rand()<.5?x:-x)","(rand()<.5?y:-y)")")
        while(1<(x=rand())^2+(y=rand())^2);
}

Ponieważ nie byłem całkiem pewien co do części rand () <.5, przeprowadziłem z tym testem dystrybucji, używając tego skryptu:

BEGIN{ srand() }
{ 
    split("0 0 0 0", s)
    split("0 0 0 0", a)

    for(i=$1; i--; )
    {
        while( 1 < r2 = ( x=rand() )^2 + ( y=rand() )^2 );

        x = rand()<.5 ? x : -x
        y = rand()<.5 ? y : -y

        ++s[ x>=0 ? y>=0 ? 1 : 4 : y>=0 ? 2 : 3 ]

        ++a[ r2>.75 ? 1 : r2>.5 ? 2 : r2>.25 ? 3 : 4]
    }

    print "sector distribution:"
        for(i in s) print "sector " i ": " s[i]/$1

    print "quarter area distribution:"
        for(i in a) print "ring " i ":   " a[i]/$1
}

co dla wejścia 1e7 daje mi ten wynik, po tym, jak wypiłem raz lub dwa razy przy mojej kawie:

1e7
sector distribution:
sector 1: 0.250167
sector 2: 0.249921
sector 3: 0.249964
sector 4: 0.249948
quarter area distribution:
ring 1:   0.24996
ring 2:   0.25002
ring 3:   0.250071
ring 4:   0.249949

co moim zdaniem jest całkiem w porządku.

Krótkie wyjaśnienie:
Po napisaniu przez chwilę okazało się, że jeśli chcesz podzielić dysk na cztery pierścienie o równej powierzchni, promienie, w których musisz wyciąć, to sqrt (1/4), sqrt (1/2 ) i sqrt (3/4). Ponieważ rzeczywisty promień punktu I testu będzie sqrt (x ^ 2 + y ^ 2), mogę pominąć kwadratowanie rootowania razem. „Zbieg okoliczności” 1/4, 2/4, 3/4 może być związany z tym, co zauważył wcześniej M. Buettner.


3

HPPPL , 146 (171–20–5) bajtów

EXPORT r(n)BEGIN LOCAL R,A,i,Q;RECT();Q:=118.;ARC_P(Q,Q,Q);FOR i FROM 1 TO n DO R:=√RANDOM(1.);A:=RANDOM(2*π);PIXON_P(G0,IP(Q+Q*R*COS(A)),IP(Q+Q*R*SIN(A)));END;FREEZE;END;

Przykład dla 10000 punktów (w tym czas w sekundach dla rzeczywistego urządzenia):

Losuj punkty na dysku, czas

Sama funkcja jest wywoływana przez r(n) . Reszta na powyższym obrazku służy wyłącznie celom czasowym.

Wynik (średnica dysku wynosi 236 pikseli):

wprowadź opis zdjęcia tutaj

Powyższa wersja nie przechowuje współrzędnych punktu, więc napisałem wersję, która przyjmuje dwa parametry r(n,p). njest liczbą punktów i p=0zwraca punkty do terminala, p=1drukuje punkty i dysk), w przypadku gdy zapisywanie współrzędnych jest obowiązkowe. Ta wersja ma długość 283 (308-20-5) bajtów:

EXPORT r(n,p)BEGIN LOCAL R,A,j,Q,x,y;Q:=118.0;CASE IF p==0 THEN print() END IF p==1 THEN RECT();ARC_P(Q,Q,Q) END END;FOR j FROM 1 TO n DO R:=√RANDOM(1.0);A:=RANDOM(2*π);x:=R*COS(A);y:=R*SIN(A);CASE IF p==0 THEN print("("+x+", "+y+")") END IF p==1 THEN PIXON_P(G0,IP(Q+Q*x),IP(Q+Q*y)) END END;END;FREEZE;END;

Wersja bez golfa:

EXPORT r(n,p)
BEGIN
LOCAL R,A,j,Q,x,y;
  Q:=118.0;
  CASE
    IF p==0 THEN print() END
    IF p==1 THEN RECT();ARC_P(Q,Q,Q) END
  END;
  FOR j FROM 1 TO n DO
    R:=√RANDOM(1.0);
    A:=RANDOM(2*π);
    x:=R*COS(A);
    y:=R*SIN(A);
    CASE
      IF p==0 THEN print("("+x+", "+y+")") END
      IF p==1 THEN PIXON_P(G0,IP(Q+Q*x),IP(Q+Q*y)) END
    END;
  END;
  FREEZE;
END;

Wyjście końcowe dla r(10,0):

Losuj punkty na wyjściu terminala dysku

r(10,1) pokazuje dysk z punktami, jak pokazano powyżej.


2

JavaScript, 75 bajtów

Oparte na odrzuceniu:

do x=(r=()=>4*Math.random()-2)(),y=r()
while(x*x+y*y>1)
alert(`(${[x,y]})`)

Metoda bezpośrednia (80 bajtów):

alert(`(${[(z=(m=Math).sqrt((r=m.random)()))*m.sin(p=m.PI*2*r()),z*m.cos(p)]})`)

2

Python, 135 130 bajtów

from random import*
def r():return uniform(-1,1)
p=[]
while not p:
    x,y=r(),r()
    if x**2+y**2<=1:p=x,y
print'(%.2f, %2f)'%p

Usunięto **0.5dzięki @ jimmy23013 „s sugestia (bo jest koło jednostka, jestem teraz sprawdzenie, czy odległość do kwadratu między (x, y) i (0, 0) jest równa 1 2 . Jest to to samo).

Pozwoliło mi to również usunąć nawiasy.


Myślę, że nie potrzebujesz **0.5.
jimmy23013

@ jimmy23013 Dziękujemy! oddalony.
JF
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.