2 回答

TA貢獻1856條經驗 獲得超17個贊
jcalz 已經給出了很好的答案。這是我在評論中詢問的變體的替代版本:當您希望在周長的兩側均勻選擇您的點時,如果您的w : h比率為4 : 1,則第一個點位于水平邊的可能性是 的四倍作為一個垂直的。(這意味著擊中兩個相反的長邊的幾率是 24/45;兩個相反的短邊的幾率是 1/45;并且每個擊中一個的幾率是 20/45——通過一個簡單但略顯乏味的計算。)
const rand = {
next: () => Math. random (),
between: (lo, hi) => lo + (hi - lo) * Math .random (),
}
const vertices = (w, h) => [ {x: 0, y: h}, {x: w, y: h}, {x: w, y: 0}, {x: 0, y: 0} ]
const edges = ([v1, v2, v3, v4]) => [ [v1, v2], [v2, v3], [v3, v4], [v4, v1] ]
const randomPoint = ([v1, v2], rand) => ({
x: v1 .x + rand .next () * (v2 .x - v1 .x),
y: v1 .y + rand .next () * (v2 .y - v1 .y),
})
const getIndex = (w, h, x) => x < w ? 0 : x < w + h ? 1 : x < w + h + w ? 2 : 3
const twoPoints = (w, h, rand) => {
const es = edges (vertices (w, h) )
const perimeter = 2 * w + 2 * h
const r1 = rand .between (0, perimeter)
const idx1 = getIndex (w, h, r1)
const r2 = (
rand. between (0, perimeter - (idx1 % 2 == 0 ? w : h)) +
Math .ceil ((idx1 + 1) / 2) * w + Math .floor ((idx1 + 1) / 2) * h
) % perimeter
const idx2 = getIndex (w, h, r2)
return {p1: randomPoint (es [idx1], rand), p2: randomPoint (es [idx2], rand)}
}
console .log (
// Ten random pairs on rectangle with width 5 and height 2
Array (10) .fill () .map (() => twoPoints (5, 2, rand))
)
唯一復雜的位是 的計算r2。我們通過將所有四個邊加在一起并減去當前邊的長度(width如果idx是偶數,height如果是奇數)來計算 0 和其余三個邊的總長度之間的隨機數。然后我們把它加到邊的總長度上,直到并包括索引(其中ceil和floor調用簡單地計算水平和垂直邊的數量,這些值分別乘以寬度和高度,并加在一起),最后取結果與周長的浮點模數。這與 jcalz 的答案中的技術相同,但通過處理邊長而不是簡單的計數而變得更加復雜。
我沒有創建rand任何類或接口的實例,實際上這里也沒有做任何 Typescript,但是你可以很容易地自己添加它。

TA貢獻1863條經驗 獲得超2個贊
假設我們有以下接口和類型:
interface Rand {
next(): number;
between(x: number, y: number): number;
}
interface Point {
x: number;
y: number;
}
type PointPair = readonly [Point, Point];
并在評論中接受您的話,該程序是:首先隨機選擇兩個邊,然后在這些邊上隨機選擇點......首先讓我們看看隨機選擇兩個邊所涉及的內容:
const s1 = Math.floor(rand.between(0, arr.length));
const s2 = (Math.floor(rand.between(1, arr.length)) + s1) % arr.length;
s1并s2代表arr我們正在選擇的索引。第一個選擇介于0和 小于數組長度之間的整數。我們通過0在數組的 和之間選擇一個實數(好吧,浮點數,無論如何),然后取該實數的下限來做到這一點。由于長度是4,我們正在做的是在0和之間均勻地選擇一個實數4。這些數字有四分之一之間0和1之間,另外四分之一1和2之間,一個季度2和3最后一個季度,并且之間3和4。這意味著你有 25% 的機會選擇每一個0,1,2和3。(選擇的機會4基本上為 0,或者如果rand以排除上限的正常方式實現,則可能恰好為 0 )。
因為s2我們現在1在數組的長度和之間均勻地選擇一個數字。在這種情況下,我們正在采摘1,2或3用33%的幾率各。我們將這個數字加到s1然后除以的余數4。想想我們正在做的事情是從第一邊開始s1,然后順時針移動 1、2 或 3 邊(比如)以選擇下邊。這完全消除了兩次選擇同一面的可能性。
現在讓我們看看在給定一個實例的情況下PointPair,在一條線段(可以定義為 a ,對應于線段的兩端p1和p2)上隨機選取一個點涉及什么Rand:
function randomPointOnSide([p1, p2]: PointPair, rand: Rand): Point {
const frac = rand.next(); // between 0 and 1
return { x: (p2.x - p1.x) * frac + p1.x, y: (p2.y - p1.y) * frac + p1.y };
}
在這里,我們做的就是選擇一個隨機數frac,沿途有多遠從代表p1到p2我們想去的地方。如果frac是0,我們選擇p1。如果frac是1,我們選擇p2。如果frac是0.5,我們選擇介于p1和之間的中間位置p2。造成這種情況的通式是之間的線性插值p1和p2給出frac。
希望在這兩者之間,您可以實現您正在尋找的算法。祝你好運!
添加回答
舉報