我在c#中遇到了一個令人感興趣的問題,我不知道該怎麼做。隨機間隔發生器對於設定的時間段內的實例數量
我需要有兩個軌道頂部彼此玩。一定數量的嘟嘟聲需要在一段時間內播放。其中一個會有一個設定的時間間隔(想想節拍器),但另一個需要隨機播放。
我不確定如何解決第二個問題,在設定的時間內隨機播放一組嘟嘟聲。
我在c#中遇到了一個令人感興趣的問題,我不知道該怎麼做。隨機間隔發生器對於設定的時間段內的實例數量
我需要有兩個軌道頂部彼此玩。一定數量的嘟嘟聲需要在一段時間內播放。其中一個會有一個設定的時間間隔(想想節拍器),但另一個需要隨機播放。
我不確定如何解決第二個問題,在設定的時間內隨機播放一組嘟嘟聲。
只需要設置一定的時間量T即可表示爲某種足夠細化的結構,也就是說毫秒。如果您需要發出N次嗶嗶聲,則需要將時間段拆分N次。因此,建立一個循環,運行N次,並且在每次迭代中,在時間間隔中選擇隨機位置以發出嘟嘟聲。根據您之後對數據所做的操作,您可能需要對嗶聲點進行排序。
使用隨機數生成在總時間範圍內生成日期時間。當你完成隨機發出的嘟嘟聲時,間隔當然是隨機的。像這樣:
List<DateTime> randomBeeps = new List<DateTime>();
Random rand = new Random();
for(int j = 0; j < numberBeepsNeeded; j++)
{
int randInt = rand.Next();
double percent = ((double)randInt)/Int32.MaxValue;
double randTicksOfTotal = ((double)setAmountOfTime.Ticks) * percent;
DateTime randomBeep = new DateTime((long)randTicksOfTotal);
randomBeeps.Add(randomBeep);
}
您可能需要使用Convert.ToLong或類似的東西。不知道它是否會給你一個從雙倍到長整數的錯誤,因爲它正在四捨五入,這在這裏很好。
您可以將其作爲一系列單次定時器來實現。當每個定時器到期(或「滴答」)時,您會播放蜂鳴聲,然後隨機確定用於下一個單次定時器的持續時間。如果您選擇的持續時間是1到1000(毫秒)之間的某個隨機數,則您將每半秒平均一次「打勾」。
編輯:只是爲了好玩,我想我會提一下,這是行爲心理學家運行由B.F. Skinner啓發的各種實驗的老問題。他們有時使用稱爲「可變間隔」的加固時間表,其中加固之間的時間在某個預定平均間隔內隨機變化。請參閱http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1404199/pdf/jeabehav00190-0145.pdf以瞭解涉及的公式。
像這樣的東西應該做的伎倆(此代碼沒有測試...但它編譯乾淨的)
using System;
using System.Security.Cryptography;
using System.Threading;
class BeatBox : IDisposable
{
private RandomNumberGenerator RNG;
private DateTime dtStarted;
private TimeSpan TimeElapsed { get { return DateTime.Now - dtStarted; } }
private TimeSpan Duration;
private TimeSpan BeatInterval;
private uint MinRandomInterval;
private uint MaxRandomInterval;
private uint RandomIntervalDomain;
private Timer RegularIntervalTimer;
private Timer RandomIntervalTimer;
public delegate void TickHandler(object sender , bool isRandom);
public event TickHandler TickEvent;
private EventWaitHandle CompletionEventWaitHandle;
public BeatBox(TimeSpan duration , TimeSpan beatInterval , uint minRandomInterval , uint maxRandomInterval)
{
this.RNG = RandomNumberGenerator.Create();
this.Duration = duration ;
this.BeatInterval = beatInterval ;
this.MinRandomInterval = minRandomInterval ;
this.MaxRandomInterval = maxRandomInterval ;
this.RandomIntervalDomain = (maxRandomInterval - minRandomInterval) + 1 ;
this.dtStarted = DateTime.MinValue ;
this.RegularIntervalTimer = null ;
this.RandomIntervalTimer = null ;
return;
}
private long NextRandomInterval()
{
byte[] entropy = new byte[sizeof(long)] ;
RNG.GetBytes(entropy);
long randomValue = BitConverter.ToInt64(entropy , 0) & long.MaxValue; // ensure that its positive
long randomoffset = (randomValue % this.RandomIntervalDomain);
long randomInterval = this.MinRandomInterval + randomoffset;
return randomInterval;
}
public EventWaitHandle Start()
{
long randomInterval = NextRandomInterval();
this.CompletionEventWaitHandle = new ManualResetEvent(false);
this.RegularIntervalTimer = new Timer(RegularBeat , null , BeatInterval , BeatInterval);
this.RandomIntervalTimer = new Timer(RandomBeat , null , randomInterval , Timeout.Infinite);
return this.CompletionEventWaitHandle;
}
private void RegularBeat(object timer)
{
if (this.TimeElapsed >= this.Duration)
{
MarkComplete();
}
else
{
this.TickEvent.Invoke(this , false);
}
return;
}
private void RandomBeat(object timer)
{
if (this.TimeElapsed >= this.Duration)
{
MarkComplete();
}
else
{
this.TickEvent.Invoke(this , true);
long nextInterval = NextRandomInterval();
this.RandomIntervalTimer.Change(nextInterval , Timeout.Infinite);
}
return;
}
private void MarkComplete()
{
lock (this.CompletionEventWaitHandle)
{
bool signaled = this.CompletionEventWaitHandle.WaitOne(0);
if (!signaled)
{
this.RegularIntervalTimer.Change(Timeout.Infinite , Timeout.Infinite);
this.RandomIntervalTimer.Change(Timeout.Infinite , Timeout.Infinite);
this.CompletionEventWaitHandle.Set();
}
}
return;
}
public void Dispose()
{
if (RegularIntervalTimer != null)
{
WaitHandle handle = new ManualResetEvent(false);
RegularIntervalTimer.Dispose(handle);
handle.WaitOne();
}
if (RandomIntervalTimer != null)
{
WaitHandle handle = new ManualResetEvent(false);
RegularIntervalTimer.Dispose(handle);
handle.WaitOne();
}
return;
}
}
class Program
{
static void Main(string[] args)
{
TimeSpan duration = new TimeSpan(0 , 5 , 0); // run for 5 minutes total
TimeSpan beatInterval = new TimeSpan(0 , 0 , 1); // regular beats every 1 second
uint minRandomInterval = 5; // minimum random interval is 5ms
uint maxRandomInterval = 30; // maximum random interval is 30ms
using (BeatBox beatBox = new BeatBox(duration , beatInterval , minRandomInterval , maxRandomInterval))
{
beatBox.TickEvent += TickHandler;
EventWaitHandle completionHandle = beatBox.Start();
completionHandle.WaitOne();
}
return;
}
static void TickHandler(object sender , bool isRandom)
{
Console.WriteLine(isRandom ? "Random Beep!" : "Beep!");
return;
}
}
您可能還需要驗證您沒有選擇同一個點的兩倍。 – Fantius
這裏的嗶嗶聲是劃分點,而不是塊,所以對於N次嗶嗶聲,您需要在時間間隔內有N個隨機位置。當然,這將導致N + 1個塊。 – phoog
OP也可能希望確保嗶嗶聲的時間不超過某個最小跨度。例如,如果嗶嗶聲本身需要500毫秒才能發聲,則可能需要將嗶聲至少保持半秒鐘。 – phoog