合計が1になるn個の乱数を返す

オブジェクトを並べる時に、最初と最後の位置は確定しているけど、途中はランダムに揺らぎのある配置にしたいような目的に使う関数。

// 合計が1になるn個の乱数を返す
function float[] randomArray(int num; float seed;)
{
    float value[];
    
    // 最初は0,最後は1、中間はランダム数の配列をつくる
    value[0] = 0;
    for (int i = 1; i < num; i++)
    {
        value[i] = random((i+1)*seed);
    }
    value[num] = 1;
    
    // 昇順に並べる
    value = sort(value);
    
    // 差を求める
    float diff[];
    for (int i = 0; i < len(value)-1; i++)
    {
        diff[i] = value[i+1]-value[i];
    }
    
    return diff;
}

関数の使用例

float value[] = randomArray(8, 5.6423);
printf(sprintf('%g', value) + '\n');
//{0.207584, 0.00183773, 0.100961, 0.0747466, 0.0101892, 0.260371, 0.0237045, 0.320606}

// 合計が1になるか検算
float sum = 0;
for (int i = 0; i < len(value); i++)
    sum += value[i];
    
printf('sum:' + sprintf('%g', sum) + '\n');
//sum:1

実用例

100mに7本の木を植える。最初と最後の木の位置は固定で、中間の木はある程度ランダムな並びにしたい。そして間隔は最低10m欲しい。

// 最小間隔を個数を設定した場合
// 100mに7個を最小間隔10m並べる
float length = 100;
int num = 6; // 間隔なので7-1=6
float min = 10;

float rest = length - min * num;
float diff[] = randomArray(num, 5.6423);

for(int i = 0; i < len(diff); i++)
{
    diff[i] *= rest;
}

float pos[];
pos[0] = 0;
sum = 0;
for(int i = 0; i < len(diff); i++)
{
    sum = sum + min + diff[i];
    pos[i+1] = sum;
}
printf('pos:' + sprintf('%g', pos) + '\n');
//pos:{0, 18.3034, 28.3769, 42.4153, 55.8127, 76.2276, 100}

個数は固定せず、最低の間隔と、マージン幅を設定した場合

// 個数は固定せず、最小間隔と、マージン幅を設定した場合
// 100mに最小間隔8mとマージン幅1mでランダムに並べる
float min = 8;
float margin = 1;
float length = 100;
int num = int(length / (min + margin));
//printf('num:' + sprintf('%g', num) + '\n');
float rest = length - min * num;
float diff[] = randomArray(num, 5.6423);

for(int i = 0; i < len(diff); i++)
{
    diff[i] *= rest;
}

float pos[];
pos[0] = 0;
float sum = 0;
for(int i = 0; i < len(diff); i++)
{
    sum = sum + min + diff[i];
    pos[i+1] = sum;
}

// ポイントを生成して確認
for(int i = 0; i < len(pos); i++)
{
    int pt = addpoint(0, set(pos[i],0,0));
}
//printf('pos:' + sprintf('%g', pos) + '\n');
タイトルとURLをコピーしました