Diskteki noktaları rastgele seçme


14

Bir yerdeki daireleri okudum ve şimdi diskleri öğrendim ( aslında oldukça yaygın bir kavram ) ve codegolf'u düşündüm.

Göreviniz , yarıçapı 1 olan bir diskteki bir noktayı / birkaç noktayı rastgele ayarlamaktır .

Kurallar:

  • Tüm noktaların üretilme olasılığı eşit olmalıdır
  • Kayan nokta koordinatları kullanılmalıdır; minimum gereksinim iki ondalık basamaktır (örneğin, noktalar (0.12, -0.45)veya (0.00, -1.00)geçerlidir)
  • Programınız gerçekten sınırlayıcı daireyi ve içinde oluşturulan noktaları görüntülerse -20 bayt alırsınız. Koordinatlar hala geçerli olmalı, ancak gösterilmemeli ve oluşturulan görüntü en az 201 x 201 piksel boyutunda olmalıdır
  • Programınız stdin'de giriş olarak oluşturulacak puan sayısını alırsa -5 bayt alırsınız
  • Sınırlayıcı daireyi ve noktaları çizmemeye karar verirseniz, programınızın formatta (x, y)veya (x,y)stdout'ta oluşturulan noktaları çıkarması gerekir.
  • Oluşturulan noktaların sayısını girdi olarak almaya karar verirseniz, onu çizmemeye karar verirseniz - programınız, yukarıda belirtilen formattaki tüm rastgele noktaları aralarında bir boşluk olsun ya da olmasın çıkarmalıdır.

Bayt cinsinden en kısa gönderim kazanır!


1
@sweerpotato Evet, lütfen daire içindeki ve üzerindeki tüm noktaların geçerli olduğunu belirtin. İkinizin de kastettiğinizin farkında değildim. Ayrıca, bu soru bir popülerlik yarışmasından daha iyi bir kod golf mücadelesine uyacak gibi görünüyor, ama bu sadece benim görüşüm.
cole

5
" XYZ'yi yaratıcı bir şekilde yapın " klasik Bad Popcon Question ™ 'dır. Bir kişinin yaratıcı olduğunu düşündüğü şey, başka bir kişinin bariz yolu olarak gördüğü şeydir.
Peter Taylor

Meraktan, neden araziler için 201x201 piksel çıkış gereksinimi?
JohnE

@JohnE Gerekli 2 ondalık basamak doğruluğuyla eşleştiği için 201x201 piksel önerdim
trichoplax

Koordinatları karmaşık sayılar olarak verebilir miyiz? Örneğin: 0.3503082505747327+0.13499221288682994j.
orlp

Yanıtlar:


5

Pyth, 26-5 = 21 bayt

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

Stdin'de oluşturulacak koordinatların sayısını alır ve bunları stdout'ta şöyle verir:

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

Kutupsal koordinatlar ve yarıçaplar oluşturan @ MartinBüttner'e benzer bir strateji kullanır, ancak karmaşık üstellemeyi kullanarak bunu yapar.


Sen kaldırabilirsin, pdeğil mi? Sadece çıktıyı ayrı satırlara değiştirir.
PurkkaKoodari

@ Pietu1998 Buna izin verilmiyor, ana soru hakkındaki yorumlara bakın.
orlp

Pekala.
PurkkaKoodari

16

CJam, 28 27 bayt

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

Bu çözüm ret temelli değildir. Noktaları kutupsal koordinatlarda üretiyorum, ancak noktaların düzgün yoğunluğunu elde etmek için yarıçapların düzgün olmayan bir dağılımı ile.

Burada test edin.

açıklama

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.

Neden çalışıyor? Dar bir yarıçap rve (küçük) genişlik halkasını düşünün dr. Alan yaklaşık olarak 2π*r*dr(halka çok darsa, iç ve dış çevre neredeyse aynıdır ve eğrilik göz ardı edilebilir, böylece alan, çevrenin yan uzunluklarına ve genişliğine sahip bir dikdörtgeninki gibi işlenebilir. halka). Böylece alan yarıçapla doğrusal olarak artar. Bu, sabit bir yoğunluk elde etmek için rastgele yarıçapların doğrusal bir dağılımını istediğimiz anlamına gelir (yarıçapın iki katında, doldurulacak iki kat daha fazla alan vardır, bu yüzden orada iki kat daha fazla nokta isteriz).

0'dan 1'e doğrusal bir rastgele dağılım nasıl oluştururuz? Önce ayrık duruma bakalım. Diyelim ki, 4 değerin istenen bir dağılımına sahibiz, örneğin {0.1, 0.4, 0.2, 0.3}( 14 kat daha yaygın olmak istiyoruz)0 ve iki kat daha yaygın olmak 2istiyoruz; 3üç kat daha yaygın olmak istiyoruz 0):

resim açıklamasını buraya girin

İstenilen dağılım ile dört değerden birini nasıl seçebilirim? Bunları biriktirebilir, y ekseninde 0 ile 1 arasında rastgele rastgele bir değer seçebilir ve o noktada segmenti seçebiliriz:

resim açıklamasını buraya girin

Yine de bu toplama görselleştirmek için farklı bir yolu var. Bunun yerine, dağıtımın her bir değerini, o noktaya kadar olan değerlerin birikimi ile değiştirebiliriz:

resim açıklamasını buraya girin

Ve şimdi bu grafiğin üst satırını bir işlev olarak ele alıyoruz f(x) = yve bir işlev elde etmek için tersine çeviriyoruz .g(y) = f-1(y) = xy ∈ [0,1] :

resim açıklamasını buraya girin

Harika, öyleyse bunu yarıçapların doğrusal bir dağılımını oluşturmak için nasıl kullanabiliriz? İstediğimiz dağıtım bu:

resim açıklamasını buraya girin

İlk adım dağılımın değerlerini biriktirmektir. Ama dağıtımı bunun yerine önceki tüm değerlerin üzerinde toplayarak nedeniyle, bir integralini almak, süreklidir 0için r. Biz kolayca Analitik Olarak çözebilir: . Bununla birlikte, bunun normalleştirilmesini istiyoruz, yani, bunun maksimum değeri verecek şekilde bir sabitle çarpmasını istiyoruz, bu yüzden gerçekten istediğimiz şey :0r r dr = 1/2 r21rr2

resim açıklamasını buraya girin

Ve son olarak, [0,1]tekrar analitik olarak yapabileceğimiz tek tip bir değere uygulayabileceğimiz bir fonksiyon elde etmek için bunu tersine çeviriyoruz : sadece r = √y, neredey rastgele değer :

resim açıklamasını buraya girin

Bu genellikle basit dağılımları tam olarak oluşturmak için kullanılabilecek oldukça yararlı bir tekniktir (herhangi bir dağıtım için çalışır, ancak karmaşık olanlar için son iki adımın sayısal olarak çözülmesi gerekebilir). Bununla birlikte, bu özel durumda üretim kodunda kullanmam, çünkü kare kök, sinüs ve kosinüs aşırı derecede pahalıdır: ret tabanlı bir algoritma kullanmak ortalama olarak çok daha hızlıdır, çünkü sadece toplama ve çarpmaya ihtiyaç duyar.


1
Çok güzel bir açıklama!
sweerpotato

2
AAAA resimler: D
Beta Çürüme

12

Mathematica, 68 44-20 = 24 bayt

David Carraher'a RandomPoint24 (!) Byte tasarruf sağlayan bilgi verdiğiniz için çok teşekkürler . Mathematica'nın her şey için yerleşik bir özelliği vardır.

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

Bu, bonusa hak kazanmak için noktayı ve sınırlayıcı daireyi çizer:

resim açıklamasını buraya girin

Sonuç bir vektör görüntüsüdür, bu nedenle 201x201 pikselin boyut spesifikasyonu gerçekten anlamlı değildir, ancak varsayılan olarak bundan daha büyük hale gelir.


Nasıl Graphics[{Circle[], Point@RandomPoint@Disk[]}]?
DavidC

Misafirim ol. Ayrıca, 1 bayt tasarruf ...Graphics@{Circle[], Point@RandomPoint@Disk[]}
DavidC

@DavidCarraher Çok teşekkürler! :)
Martin Ender

Mathematica sözdizimini bilmiyorum ama kesinlikle sonra boşluk kaldırarak başka bir bayt kaydedebilirsiniz ,?
kabarık

@fluffy Yayınlanan versiyonda zaten yaptım
Martin Ender

9

CJam, 31 26 bayt

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

Bu, yan uzunluk 2'nin karesinde tekrar tekrar rastgele noktalar oluşturarak ve birim diskin içine düşen ilki tutarak çalışır.

@ MartinBüttner'a 3 baytlık golf için teşekkürler!

CJam yorumlayıcısında çevrimiçi deneyin .

Nasıl çalışır

{                  }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 bayt

Özellikle özel bir şey yok, ama sanırım en az bir grafik çözümümüz olmalı:

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

arsa

Tarayıcınızda deneyin .

Düzenleme: @ MartinBüttner'in kutupsal koordinatların dağılımını değiştirmek için yaklaşımını uygulayarak iki bayt tıraş edebilirim. Bence biraz daha doğrudan:

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

3
Sınırlayıcı daireyi de çizerseniz, -20 için hak kazanırsınız.
orlp

1
iKe'nin raster tabanlı bir çizim modeli vardır ve bu gereksinimi oldukça haksız hale getirir. Ben de sınırlayıcı bir çemberin yaklaşık bir hale getirmek için 20 karakterden biraz daha pahalıya mal olacağını düşünüyorum.
JohnE

7

Perl, 59 Bayt

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

Bu sadece basit bir çözümdür, bir kare içinde noktalar oluşturur ve bunları çok uzakta reddeder. Tekil golf hilem, durumun içindeki ödevleri dahil etmektir.

Düzenleme: Golf sürecinde, bir daire üzerinde rastgele noktalar yazdırmak için ilginç bir yol buldum .

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

7

Oktav, 24 53-20 = 33 bayt

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

501 eşit aralıklı teta değeri artı bir rasgele sayı üretir ve tümünü [0..2π] olarak ölçeklendirir. Daha sonra dairenin yarıçapı için 501 1, artı nokta için rastgele bir yarıçap üretir ve disk üzerinde eşit dağılım sağlamak için kare kökü alır. Ardından tüm noktaları kutupsal koordinatlar olarak çizer.

resim açıklamasını buraya girin


İşte dağıtımın hızlı bir gösterimi (birim çemberi olmadan):

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

9801 Puan


5

Oktav / Matlab, 74 64 bayt

Reddetme yöntemi , 64 bayt:

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

Doğrudan yöntem , 74 bayt (iki hatayı düzeltmeme yardımcı olduğu için Martin Büttner'e teşekkürler):

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 Bayt

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

Kutupsal koordinatlardan x / y oluşturmak için karmaşık sayı yapısını kullanın. Girdi almak biraz pahalı ve muhtemelen bunu yapmanın daha iyi bir yolu var. ylim Vexlim tüm daire çizilir ve sağlamaktır aspolmasını sağlar noktası daire sembolünün altında gösterilmiştir.

Tasarruf için @jbaums ve @flodel'e teşekkürler

Burada deneyin


runif(9,0,1)basitleştirilebilirrunif(9)
jbaums

@jbaums, teşekkürler ... her zaman unuttuğum şeylerden biri :)
MickyT

14 tıraş olabilir:symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
flodel

@ flodel çok güzel teşekkür ederim.
MickyT

Başka bir ufacık tasarruf: yerine yliçalışır ylim.
jbaums

4

İşleme / Java 141 bayt-20 = 121

201 * 201 için minimum boyut gereksinimi, setupProcessing.org varsayılanı 200x200 :( olduğundan , yöntemi koymamı gerektirir.

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

İşleme / java izin temiz bilmiyordum!
J Atkin

4

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

Kullanıcı girişini alır ve diski ve noktaları çizer. QB64 üzerinde test edildi .

Bu oldukça basit bir "dart tahtası atmak ve ne sopa tutmak" stratejisidir. Yakalama, "hangi çubukların" matematiksel olarak değil, grafiksel olarak belirlendiğidir: siyah bir arka plan üzerine beyaz bir disk çizilir ve daha sonra rastgele oluşturulan noktalar siyah oluncaya kadar reddedilir. Noktaların kendileri mavi çizilir (tek piksel olduklarını söylemek zor olsa da - büyütmek için resme tıklayın).


3

awk - 95-5 = 90

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

Rand () <. 5 bölümü hakkında tam olarak emin olmadığım için, bu komut dosyasını kullanarak bu ile bazı dağıtım testleri yaptım:

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
}

kahvemde bir veya iki kez yudumladıktan sonra 1e7 girişi için bu sonucu verir:

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

ki bence oldukça iyi.

Biraz açıklama:
Bir süre karalama yaptıktan sonra, diski eşit alana sahip dört halkaya bölmek istiyorsanız, kesmeniz gereken yarıçap sqrt (1/4), sqrt (1/2) ) ve sqrt (3/4). Test ettiğim noktanın gerçek yarıçapı sqrt (x ^ 2 + y ^ 2) olacağından, karekökü hep birlikte atlayabilirim. 1/4, 2/4, 3/4 "tesadüf", M. Buettner'in daha önce işaret ettiği şeyle ilgili olabilir.


3

HPPPL , 146 (171-20-5) bayt

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;

10000 nokta örneği (gerçek cihaz için saniye cinsinden zamanlama dahil):

Bir diskteki noktaları rastgele zamanlama

Fonksiyonun kendisi tarafından çağrılır r(n) . Yukarıdaki resimde kalan kısım sadece zamanlama amaçlıdır.

Sonuç (disk çapı 236 pikseldir):

resim açıklamasını buraya girin

Yukarıdaki sürüm nokta koordinatlarını saklamıyor, bu yüzden iki parametre alan bir sürüm yazdım r(n,p). nnokta sayısıdır ve noktaları p=0terminale döndürür, p=1noktaları ve diski çizer), koordinatların saklanması zorunludur. Bu sürüm 283 (308-20-5) bayt uzunluğundadır:

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;

Çözülmemiş versiyon:

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;

Terminal çıkışı r(10,0):

Disk terminali çıkışındaki noktaları rastgele

r(10,1) diski yukarıda gösterildiği gibi noktaları gösterir.


2

JavaScript, 75 bayt

Reddetme tabanlı:

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

Doğrudan yöntem (80 bayt):

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

2

Python, 135130 bayt

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

@ Jimmy23013’ün önerisi **0.5sayesinde kaldırıldı (birim daire olduğu için, şimdi (x, y) ve (0, 0) arasındaki mesafenin 1 2'ye eşit olup olmadığını kontrol ediyorum . Bu aynı şeydir).

Bu da beni parantezleri kaldırmam için serbest bıraktı.


Sanırım ihtiyacın yok **0.5.
jimmy23013

@ jimmy23013 Teşekkür ederiz! çıkarıldı.
JF
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.