ディスク上のポイントをランダム化する


14

私はどこかでサークルについて読んで、今やディスクについて学び(実際にはかなり一般的な概念です)、コードゴルフについて考えました。

あなたの仕事は、半径1のディスク上のポイント/いくつかのポイントをランダム化することです。

ルール:

  • すべてのポイントが生成される確率は等しくなければなりません
  • 浮動小数点座標を使用する必要があります。最小要件は小数点以下2桁です(例:ポイント(0.12, -0.45)または(0.00, -1.00)有効)
  • プログラムが実際に境界円とその中に生成されたポイントを表示する場合、-20バイトを取得します。座標は依然として有効であるが表示されていない必要があり、生成される画像は少なくとも201 x 201ピクセルのサイズである必要があります
  • プログラムがstdinの入力として生成されるポイントの数を取る場合、-5バイトを取得します
  • 境界円とポイントをプロットしないことにした場合、プログラムはフォーマット(x, y)または(x,y)stdoutで生成されたポイントを出力する必要があります
  • 生成されたポイントの数を入力として取得するが、プロットしない場合-プログラムは、上記の形式ですべてのランダム化されたポイントを出力しなければなりません。

バイト単位の最短提出が勝ちです!


1
@sweerpotatoはい、サークル内およびサークル上のすべてのポイントが有効であることを指定してください。私はあなたが両方を意味することに気づきませんでした。また、この質問は人気コンテストよりもコードゴルフの課題に適しているように思えますが、それは私の意見です。
コール

5
クリエイティブな方法でXYZを行う」は、古典的なBad Popcon Question™です。ある人が創造的だと考えるのは、他の人が明白な方法であると考えるものです。
ピーターテイラー

好奇心から、なぜプロットの201x201ピクセル出力要件が必要ですか?
JohnE

それは必要な2進の場所の精度と一致するよう@JohnE私は201x201ピクセルを提案
センモウヒラムシ

座標を複素数として出力できますか?例:0.3503082505747327+0.13499221288682994j
orlp

回答:


5

Pyth、26-5 = 21バイト

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

stdinで生成する座標の数を取得し、次のようにstdoutに出力します。

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

@MartinBüttnerと同様の戦略を使用し、極座標と半径を生成しますが、複素指数を使用します。


を削除pできますか?出力を個別の行に変更するだけです。
PurkkaKoodari

@ Pietu1998それは許可されていません。主な質問に関するコメントを参照してください。
orlp

いいよ。
PurkkaKoodari

16

CJam、28 27バイト

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

このソリューションは拒否ベースではありません。極座標でポイントを生成していますが、ポイントの密度が均一になるように、半径が不均一に分布しています。

ここでテストしてください。

説明

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.

なぜ機能するのですか?半径rと(小さな)幅の狭い環を考えてくださいdr。面積はおよそです2π*r*dr(環が狭い場合、内周と外周はほぼ同一であり、曲率は無視できます。そのため、面積は周囲の辺の長さと幅の長方形として扱うことができます環)。したがって、面積は半径とともに直線的に増加します。これは、一定の密度を達成するために、ランダムな半径の線形分布も必要であることを意味します(半径の2倍で、2倍の面積を埋めるため、そこに2倍のポイントが必要です)。

0から1までの線形ランダム分布を生成するにはどうすればよいですか?最初に離散的なケースを見てみましょう。たとえば、次のように4つの値の望ましい分布があるとします{0.1, 0.4, 0.2, 0.3}(つまり、の14倍の共通性0と2倍の共通性が2必要です3。3倍の共通性が必要です0)。

enter image description here

希望の分布を持つ4つの値のいずれかを選択するにはどうすればよいですか?それらを積み重ねて、y軸で0から1までの一様にランダムな値を選択し、そのポイントでセグメントを選択します。

enter image description here

ただし、このピッキングを視覚化する別の方法があります。代わりに、分布の各値をその時点までの値の累積で置き換えることができます。

enter image description here

そして今、このチャートの一番上の行を関数として扱い、f(x) = yそれを反転して関数を取得します。これは、次のような一様にランダムな値に適用できます。g(y) = f-1(y) = xy ∈ [0,1]

enter image description here

それでは、これを利用して半径の線形分布を生成するにはどうすればよいでしょうか?これは私たちが望む分布です:

enter image description here

最初のステップは、分布の値を蓄積することです。しかし、分布はそれほど代わりに以前のすべての値を合計すると、我々はから積分を取る、連続している0r。これを分析的に簡単に解決できます。ただし、これを正規化する、つまり、最大値が得られるように定数を乗算するため、実際に必要なのは次のとおりです。0r r dr = 1/2 r21rr2

enter image description here

そして最後に、我々この反転は、我々が均一な値に適用することができます機能を取得するには[0,1]それだけだ。我々は再び解析的に行うことができ、r = √yyランダムな値です。

enter image description here

これは、単純な分布を正確に生成するために頻繁に使用できるかなり有用な手法です(どの分布でも機能しますが、複雑な分布では最後の2つのステップを数値的に解決する必要があります)。ただし、この特定のケースでは、平方根、サイン、コサインは法外に高価なので、この特定のケースでは使用しません。拒否ベースのアルゴリズムを使用すると、加算と乗算のみが必要になるため、平均してはるかに高速です。


1
とてもいい説明です!
-sweerpotato

2
Mmm写真:D
ベータ崩壊

12

Mathematica、68 44-20 = 24バイト

RandomPoint24(!)バイトを節約してくれたDavid Carraherに感謝します。Mathematicaにすべての機能が組み込まれています。

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

これは、ボーナスの対象となるポイントと境界円をプロットします。

enter image description here

結果はベクトル画像なので、201x201ピクセルのサイズ指定は実際には意味がありませんが、デフォルトではそれより大きくレンダリングされます。


どうGraphics[{Circle[], Point@RandomPoint@Disk[]}]
DavidC

私のゲストになります。また、1バイト...保存するGraphics@{Circle[], Point@RandomPoint@Disk[]}
DavidC

@DavidCarraherどうもありがとう!:)
マーティンエンダー

Mathematicaの構文はわかりませんが、,?の後のスペースを削除することで別のバイトを節約できます。
ふわふわ

私はすでにポストさバージョンでやった@fluffy
マーティン・エンダー

9

CJam、31 26バイト

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

これは、辺の長さ2の正方形にランダムポイントを繰り返し生成し、最初のユニットをユニットディスク内に保持することで機能します。

3バイトのゴルフをしてくれた@MartinBüttnerに感謝します!

CJamインタプリタでオンラインで試してください。

使い方

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

iKe53 51バイト

特に特別なことは何もありませんが、少なくとも1つのグラフィカルソリューションが必要です。

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

プロット

ブラウザで試してみてください

編集:極座標の分布を変更する@MartinBüttnerのアプローチを適用することで、2バイトを削減できます。また、かなり直接的だと思います。

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

3
境界円も描画する場合は、-20の資格があります。
orlp

1
iKeにはラスターベースの描画モデルがあり、その要件はかなり不公平です。境界円の近似値をレンダリングするのにも20文字以上かかると思います。
JohnE

7

Perl、59バイト

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

これは単純な解決策であり、正方形に点を生成し、遠く離れた点を拒否します。私の唯一のゴルフトリックは、条件内に割り当てを含めることです。

編集:ゴルフの過程で、ランダムポイントをに印刷する興味深い方法を見つけました。

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

7

オクターブ、24 53-20 = 33バイト

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

501の等間隔シータ値と1つの乱数を生成し、それらをすべて[0..2π]にスケーリングします。次に、円の半径に対して501の1を生成し、さらに点に対してランダムな半径を生成し、平方根を取得してディスク上の均一な分布を確保します。次に、すべてのポイントを極座標としてプロットします。

ここに画像の説明を入力してください


以下に、ディストリビューションの簡単なデモを示します(単位円なし):

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

9801ポイント


5

オクターブ/ Matlab、74 64バイト

拒否方法、64バイト:

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

ダイレクトメソッド、74バイト(2つのエラーの修正を手伝ってくれたMartinBüttnerに感謝):

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バイト

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

複素数構成を使用して、極座標からx / yを構築します。入力を取得するには少し費用がかかり、おそらくこれを行うためのより良い方法があります。のylim そしてxlim全体の円を確保することであるがプロットされasp性を保証は点は、円記号の下に示されています。

@jbaumsと@flodelに感謝します

ここで試してみてください


runif(9,0,1)に簡略化することができますrunif(9)
jbaums

@jbaums、ありがとう...私がいつも忘れそうなことの1つ:)
MickyT

14を剃ることができます:symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
flodel

@flodelありがとうございます。
MickyT

別の小さな節約:のyli代わりに動作しylimます。
jbaums

4

/ Java 141バイト-20 = 121の処理

setupProcessing.orgのデフォルトは200x200であるため、201 * 201が最小サイズであるという要件により、メソッドを入力する必要があります。

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

処理/ javaが許可されていることを知りませんでした!
Jアトキン

4

QBasic、138バイト-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

ユーザーの入力を受け取り、ディスクとポイントを描画します。QB64でテスト済み。

これは非常に基本的な「ダーツボードに投げて何を刺しておく」戦略です。キャッチは、「スティック」が数学的にではなくグラフィカルに決定されることです。白いディスクが黒い背景にプロットされ、その後、ランダムに生成されたポイントが黒くなくなるまで拒否されます。ポイント自体は青色で描画されます(ただし、それらが1つのピクセルであるかどうかを判断するのは難しいですが、画像をクリックして拡大します)。


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の部分についてはよくわからなかったので、このスクリプトを使用して、これでいくつかの配布テストを行いました。

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
}

入力を1e7にすると、コーヒーを1、2回飲んだ後、この結果が得られます。

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

私は大丈夫だと思います。


簡単な説明:しばらく走り回った後、ディスクを等しい面積の4つのリングに分割したい場合、カットしなければならない半径はsqrt(1/4)、sqrt(1/2 )およびsqrt(3/4)。テストする点の実際の半径はsqrt(x ^ 2 + y ^ 2)になるため、平方根をすべてスキップできます。1 / 4、2 / 4、3 / 4の「一致」は、M。Buettnerが以前に指摘したものに関連している可能性があります。


3

HPPPL、146(171-20-5)バイト

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ポイントの例(実デバイスの秒単位のタイミングを含む):

ディスク上のポイントのランダム化、タイミング

関数自体は r(n)ます。上の画像の残りの部分は、タイミングの目的のみです。

結果(ディスク直径は236ピクセル):

ここに画像の説明を入力してください

上記のバージョンはポイント座標を保存しないため、2つのパラメーターを取るバージョンを作成しましたr(n,p)nは、ポイントの数でありp=0、端末にポイントを返し、p=1ポイントとディスクをプロットします)、座標の保存が必須の場合。このバージョンは283(308-20-5)バイト長です:

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;

改変されていないバージョン:

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;

の端末出力r(10,0)

ディスクターミナル出力のポイントをランダム化する

r(10,1) 上記のようなポイントでディスクを表示します。


2

JavaScript、75バイト

拒否ベース:

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

直接法(80バイト):

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

2

Python、135 130バイト

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の提案**0.5への感謝を削除しました(単位円であるため、(x、y)と(0、0)の平方距離が1 2に等しいかどうかを確認しています。これは同じことです)。

これにより、括弧も削除できました。


私はあなたが必要ないと思う**0.5
jimmy23013

@ jimmy23013ありがとうございます!削除されました。
JF
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.