Randomize Punkte auf einer Disc

14

Ich habe irgendwo über Kreise gelesen und gerade etwas über Discs gelernt ( es ist eigentlich ein ziemlich verbreitetes Konzept ) und über Codegolf nachgedacht.

Ihre Aufgabe ist es, einen Punkt / mehrere Punkte auf einer Scheibe mit dem Radius 1 zufällig zu ordnen .

Regeln:

  • Alle Punkte müssen die gleiche Wahrscheinlichkeit haben, um generiert zu werden
  • Gleitkommakoordinaten müssen verwendet werden. die Mindestanforderung sind zwei Dezimalstellen (zB die Punkte (0.12, -0.45)oder (0.00, -1.00)sind gültig)
  • Sie erhalten -20 Bytes, wenn Ihr Programm tatsächlich den Begrenzungskreis und die darin erzeugten Punkte anzeigt. Koordinaten müssen noch gültig sein, aber nicht angezeigt werden, und das erzeugte Bild muss mindestens 201 x 201 Pixel groß sein
  • Sie erhalten -5 Bytes, wenn Ihr Programm die Anzahl der zu generierenden Punkte als Eingabe für stdin verwendet
  • Wenn Sie den Begrenzungskreis und die Punkte nicht zeichnen möchten, muss Ihr Programm die Punkte ausgeben, die im Format (x, y)oder (x,y)auf stdout generiert wurden
  • Wenn Sie die Anzahl der generierten Punkte als Eingabe verwenden, aber nicht zeichnen möchten, muss Ihr Programm alle zufälligen Punkte in dem oben angegebenen Format mit oder ohne ein Leerzeichen dazwischen ausgeben

Kürzeste Einsendung in Bytes gewinnt!

Süßkartoffel
quelle
1
@sweerpotato Ja, bitte geben Sie an, dass alle Punkte im und auf dem Kreis gültig sind. Mir war nicht klar, dass du beides meinst. Auch scheint diese Frage besser zu einer Code-Golf-Herausforderung zu passen als zu einem Beliebtheitswettbewerb, aber das ist nur meine Meinung.
Cole
5
" Mach XYZ auf kreative Art und Weise " ist die klassische Bad Popcon Question ™. Was eine Person für kreativ hält, ist das, was eine andere Person für den offensichtlichen Weg hält.
Peter Taylor
Warum aus Neugier eine 201x201-Pixel-Ausgabeanforderung für Diagramme?
JohnE
@ JohnE Ich schlug 201x201 Pixel vor, da es der erforderlichen Genauigkeit von 2 Dezimalstellen entspricht
Trichoplax
Dürfen wir die Koordinaten als komplexe Zahlen ausgeben? Zum Beispiel: 0.3503082505747327+0.13499221288682994j.
Orlp

Antworten:

5

Pyth, 26 - 5 = 21 Bytes

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

Nimmt die Anzahl der auf stdin zu generierenden Koordinaten und gibt sie wie folgt auf stdout aus:

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

Verwendet eine Strategie, die der von @ MartinBüttner ähnelt und Polarkoordinaten und Radien generiert, außer dass dabei komplexe Exponentiation verwendet wird.

orlp
quelle
Sie können die entfernen p, nicht wahr? Es ändert nur die Ausgabe in separate Zeilen.
PurkkaKoodari
@ Pietu1998 Das ist nicht erlaubt, siehe die Kommentare zur Hauptfrage.
Orlp
Oh, alles klar.
PurkkaKoodari
16

CJam, 28 27 Bytes

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

Diese Lösung basiert nicht auf Ablehnung. Ich generiere die Punkte in Polarkoordinaten, aber mit einer ungleichmäßigen Verteilung der Radien, um eine gleichmäßige Dichte der Punkte zu erreichen.

Teste es hier.

Erläuterung

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.

Warum funktioniert es? Betrachten Sie einen engen Kreisring aus Radius rund (kleiner) Breite dr. Die Fläche ist ungefähr 2π*r*dr(wenn der Kreisring eng ist, sind der innere und der äußere Umfang nahezu identisch, und die Krümmung kann ignoriert werden, so dass die Fläche wie die eines Rechtecks ​​mit Seitenlängen des Umfangs und der Breite des Kreisrings behandelt werden kann) Annulus). Die Fläche wächst also linear mit dem Radius. Das heißt, wir wollen auch eine lineare Verteilung der Zufallsradien, um eine konstante Dichte zu erreichen (bei doppeltem Radius ist doppelt so viel Fläche zu füllen, also wollen wir dort doppelt so viele Punkte).

Wie erzeugen wir eine lineare Zufallsverteilung von 0 bis 1? Schauen wir uns zuerst den diskreten Fall an. Nehmen wir an, wir haben eine gewünschte Verteilung von 4 Werten wie {0.1, 0.4, 0.2, 0.3}(dh wir wollen 14-mal so häufig sein wie 0und doppelt so häufig wie 2; wir wollen 3dreimal so häufig sein wie 0):

Bildbeschreibung hier eingeben

Wie kann man einen der vier Werte mit der gewünschten Verteilung auswählen? Wir können sie stapeln, einen gleichmäßig zufälligen Wert zwischen 0 und 1 auf der y-Achse auswählen und das Segment an diesem Punkt auswählen:

Bildbeschreibung hier eingeben

Es gibt jedoch eine andere Möglichkeit, diese Auswahl zu visualisieren. Wir könnten stattdessen jeden Wert der Verteilung durch die Akkumulation der Werte bis zu diesem Punkt ersetzen:

Bildbeschreibung hier eingeben

Und jetzt behandeln wir die oberste Zeile dieses Diagramms als Funktion f(x) = yund invertieren sie, um eine Funktion zu erhalten , die wir auf einen einheitlich zufälligen Wert anwenden können in :g(y) = f-1(y) = xy ∈ [0,1]

Bildbeschreibung hier eingeben

Cool, wie kann man das nutzen, um eine lineare Radienverteilung zu erzeugen? Dies ist die Distribution, die wir wollen:

Bildbeschreibung hier eingeben

Der erste Schritt besteht darin, die Werte der Verteilung zu akkumulieren. Die Verteilung ist jedoch stetig. Anstatt also alle vorherigen Werte zu addieren, nehmen wir ein Integral von 0bis r. Wir können leicht die analytisch lösen: . Wir möchten jedoch, dass dies normalisiert wird, dh dass es mit einer Konstanten multipliziert wird, die den Maximalwert von ergibt. Wir möchten also :0r r dr = 1/2 r21rr2

Bildbeschreibung hier eingeben

Und schließlich invertieren wir dies, um eine Funktion zu erhalten [0,1], die wir auf einen einheitlichen Wert anwenden können. Dies können wir wiederum analytisch tun: Es ist nur r = √y, wo yist der Zufallswert:

Bildbeschreibung hier eingeben

Dies ist eine ziemlich nützliche Technik, die oft verwendet werden kann, um einfache Verteilungen genau zu generieren (sie funktioniert für jede Verteilung, aber für komplizierte müssen die letzten beiden Schritte möglicherweise numerisch gelöst werden). Ich würde es jedoch in diesem speziellen Fall nicht im Produktionscode verwenden, da die Quadratwurzel, der Sinus und der Cosinus unerschwinglich teuer sind: Die Verwendung eines auf Ablehnung basierenden Algorithmus ist im Durchschnitt viel schneller, da nur Addition und Multiplikation erforderlich sind.

Martin Ender
quelle
1
Sehr schöne Erklärung!
Sweerpotato
2
Mmm Bilder: D
Beta Decay
12

Mathematica, 68 44 - 20 = 24 Bytes

Vielen Dank an David Carraher, der mir mitteilte RandomPoint, dass 24 (!) Bytes eingespart wurden. In Mathematica ist für alles etwas eingebaut.

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

Dies stellt den Punkt und den Begrenzungskreis dar, um sich für den Bonus zu qualifizieren:

Bildbeschreibung hier eingeben

Das Ergebnis ist ein Vektorbild, daher ist die Größenangabe von 201 x 201 Pixel nicht wirklich sinnvoll, wird jedoch standardmäßig größer dargestellt.

Martin Ender
quelle
Wie wäre es Graphics[{Circle[], Point@RandomPoint@Disk[]}]?
DavidC
Sei mein Gast. Außerdem, um 1 Byte zu speichern ...Graphics@{Circle[], Point@RandomPoint@Disk[]}
DavidC
@ DavidCarraher Vielen Dank! :)
Martin Ender
Ich kenne die Mathematica-Syntax nicht, aber Sie können mit Sicherheit ein weiteres Byte speichern, indem Sie das Leerzeichen nach dem entfernen ,.
flauschiger
@fluffy habe ich schon in der geposteten Version gemacht
Martin Ender
9

CJam, 31 26 Bytes

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

Dies funktioniert, indem wiederholt zufällige Punkte in einem Quadrat der Seitenlänge 2 erzeugt werden und der erste Punkt, der in die Einheitsscheibe fällt, beibehalten wird.

Danke an @ MartinBüttner für das Golfen mit 3 Bytes!

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

{                  }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.
Dennis
quelle
8

iKe , 53 51 Bytes

Nichts besonderes, aber ich nehme an, wir sollten mindestens eine grafische Lösung haben:

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

Handlung

Versuchen Sie es in Ihrem Browser .

Bearbeiten: Ich kann zwei Bytes abschneiden, indem ich den @ MartinBüttner-Ansatz zum Ändern der Verteilung von Polarkoordinaten anwende. Ich denke, es ist auch etwas direkter:

,(80*1+(%?c){x*(cos y;sin y)}'6.282*?c:9999;cga;3)
JohnE
quelle
3
Wenn Sie auch den Begrenzungskreis zeichnen, qualifizieren Sie sich für -20.
Orlp
1
iKe verfügt über ein rasterbasiertes Zeichnungsmodell, was diese Anforderung ziemlich unfair macht. Ich denke, es würde ziemlich viel mehr als 20 Zeichen kosten, um auch eine Annäherung an einen Begrenzungskreis zu erstellen.
JohnE
7

Perl, 59 Bytes

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

Dies ist nur eine einfache Lösung, bei der Punkte in einem Quadrat generiert und zu weit entfernte Punkte verworfen werden. Mein einzigartiger Golf-Trick ist es, die Aufgaben in die Bedingung einzubeziehen.

Bearbeiten: Während des Golfspiels habe ich eine interessante Möglichkeit gefunden, zufällige Punkte auf einen Kreis zu drucken .

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

Oktave, 24 53 - 20 = 33 Bytes

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

Erzeugt 501 Theta-Werte mit gleichem Abstand plus eine Zufallszahl und skaliert sie alle auf [0..2π]. Dann werden 501 Einsen für den Radius des Kreises sowie ein zufälliger Radius für den Punkt generiert und die Quadratwurzel verwendet, um eine gleichmäßige Verteilung über die Scheibe sicherzustellen. Zeichnet dann alle Punkte als Polarkoordinaten.

Bildbeschreibung hier eingeben


Hier ist eine kurze Demonstration der Verteilung (ohne den Einheitenkreis):

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

9801 Punkte

Becherglas
quelle
5

Oktave / Matlab, 74 64 Bytes

Ablehnungsmethode , 64 Bytes:

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

Direkte Methode , 74 Bytes (danke an Martin Büttner für die Hilfe bei der Korrektur von zwei Fehlern):

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

R, 99 95 81-20 = 79 75 61 Bytes

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

Verwenden Sie die komplexe Zahlenkonstruktion, um die x / ys aus Polarkoordinaten zu erstellen. Die Eingabe war etwas teuer und es gibt wahrscheinlich einen besseren Weg, dies zu tun. Mit ylim undxlim soll sichergestellt werden, dass der gesamte Kreis gezeichnet wird, und mit wird aspsichergestellt, dass die Punkte unter dem Kreissymbol angezeigt werden.

Vielen Dank an @jbaums und @flodel für die Einsparungen

Probieren Sie es hier aus

MickyT
quelle
runif(9,0,1)kann vereinfacht werdenrunif(9)
jbaums
@ Jbaums, danke ... eines der Dinge, die ich immer zu vergessen scheinen :)
MickyT
Kann 14 rasieren:symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
Flodel
@flodel sehr nett danke.
MickyT
Noch eine Teeny-Ersparnis: Arbeitet ylianstelle von ylim.
Jbaums
4

Processing / Java 141 bytes-20 = 121

Die Anforderung für 201 * 201 als Mindestgröße erfordert, dass ich die setupMethode eingebe, da Processing.org standardmäßig 200x200 ist :(

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)}
Timothy Groote
quelle
Ich wusste nicht, dass die Verarbeitung / Java erlaubt war, ordentlich!
J Atkin
4

QBasic, 138 Bytes - 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

Nimmt Benutzereingaben auf und zeichnet die Disc und Punkte. Getestet auf QB64 .

Dies ist eine ziemlich einfache Strategie, mit der man auf die Dartscheibe wirft und behält, was man hält. Der Haken dabei ist, dass "was klebt" nicht mathematisch, sondern grafisch bestimmt wird: Eine weiße Scheibe wird auf einem schwarzen Hintergrund dargestellt, und dann werden zufällig erzeugte Punkte verworfen, bis sie nicht mehr schwarz sind. Die Punkte selbst sind blau gezeichnet (obwohl es schwer zu erkennen ist, wann es sich um einzelne Pixel handelt - klicken Sie auf das Bild, um es zu vergrößern).

DLosc
quelle
3

awk - 95 - 5 = 90

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

Da ich mir bezüglich des Teils rand () <. 5 nicht ganz sicher war, habe ich mit diesem Skript einige Verteilungstests durchgeführt:

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
}

was bei einer Eingabe von 1e7 zu diesem Ergebnis führt, nachdem ich ein- oder zweimal an meinem Kaffee getrunken habe:

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

das finde ich ganz in ordnung.

Eine kleine Erklärung:
Nach einigem Kritzeln stellte sich heraus, dass die Radien, in die Sie schneiden müssten, sqrt (1/4), sqrt (1/2) sind, wenn Sie die Scheibe in vier Ringe mit gleicher Fläche teilen möchten ) und sqrt (3/4). Da der tatsächliche Radius des Punktes, den ich teste, sqrt (x ^ 2 + y ^ 2) wäre, kann ich die Quadratwurzel alle zusammen überspringen. Das 1/4, 2/4, 3/4 "Zusammentreffen" könnte mit dem zusammenhängen, worauf M. Buettner früher hingewiesen hat.

Cabbie407
quelle
3

HPPPL , 146 (171-20-5) Bytes

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;

Beispiel für 10000 Punkte (einschließlich der Zeitangabe in Sekunden für das reale Gerät):

Randomize Punkte auf einer Disc, Timing

Die Funktion selbst wird von aufgerufen r(n). Der Rest auf dem Bild oben dient nur zu Timing-Zwecken.

Ergebnis (Scheibendurchmesser beträgt 236 Pixel):

Bildbeschreibung hier eingeben

In der obigen Version werden die Punktkoordinaten nicht gespeichert, daher habe ich eine Version geschrieben, die zwei Parameter akzeptiert r(n,p). nist die Anzahl der Punkte und p=0gibt die Punkte an das Terminal zurück, p=1zeichnet die Punkte und die Disc), falls das Speichern von Koordinaten obligatorisch ist. Diese Version ist 283 (308-20-5) Bytes lang:

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;

Die ungolfed Version:

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;

Terminalausgang für r(10,0):

Randomize Punkte auf einer Disc-Terminal-Ausgabe

r(10,1) zeigt die Scheibe mit den Punkten, wie oben gezeigt.

ML
quelle
2

JavaScript, 75 Byte

Ablehnungsbasiert:

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

Direkte Methode (80 Bytes):

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

Python, 135-130 Bytes

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

Der **0.5Dank an den Vorschlag von @ jimmy23013 wurde entfernt (da es sich um einen Einheitskreis handelt, überprüfe ich jetzt, ob der quadratische Abstand zwischen (x, y) und (0, 0) gleich 1 2 ist . Dies ist dasselbe).

Dadurch konnte ich auch die Klammern entfernen.

JF
quelle
Ich denke du brauchst das nicht **0.5.
Jimmy23013
@ Jimmy23013 Vielen Dank! entfernt.
JF