2011-10-31 51 views
4

我在c#中遇到了一個令人感興趣的問題,我不知道該怎麼做。隨機間隔發生器對於設定的時間段內的實例數量

我需要有兩個軌道頂部彼此玩。一定數量的嘟嘟聲需要在一段時間內播放。其中一個會有一個設定的時間間隔(想想節拍器),但另一個需要隨機播放。

我不確定如何解決第二個問題,在設定的時間內隨機播放一組嘟嘟聲。

回答

2

只需要設置一定的時間量T即可表示爲某種足夠細化的結構,也就是說毫秒。如果您需要發出N次嗶嗶聲,則需要將時間段拆分N次。因此,建立一個循環,運行N次,並且在每次迭代中,在時間間隔中選擇隨機位置以發出嘟嘟聲。根據您之後對數據所做的操作,您可能需要對嗶聲點進行排序。

+0

您可能還需要驗證您沒有選擇同一個點的兩倍。 – Fantius

+0

這裏的嗶嗶聲是劃分點,而不是塊,所以對於N次嗶嗶聲,您需要在時間間隔內有N個隨機位置。當然,這將導致N + 1個塊。 – phoog

+0

OP也可能希望確保嗶嗶聲的時間不超過某個最小跨度。例如,如果嗶嗶聲本身需要500毫秒才能發聲,則可能需要將嗶聲至少保持半秒鐘。 – phoog

0

使用隨機數生成在總時間範圍內生成日期時間。當你完成隨機發出的嘟嘟聲時,間隔當然是隨機的。像這樣:

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或類似的東西。不知道它是否會給你一個從雙倍到長整數的錯誤,因爲它正在四捨五入,這在這裏很好。

0

您可以將其作爲一系列單次定時器來實現。當每個定時器到期(或「滴答」)時,您會播放蜂鳴聲,然後隨機確定用於下一個單次定時器的持續時間。如果您選擇的持續時間是1到1000(毫秒)之間的某個隨機數,則您將每半秒平均一次「打勾」。

編輯:只是爲了好玩,我想我會提一下,這是行爲心理學家運行由B.F. Skinner啓發的各種實驗的老問題。他們有時使用稱爲「可變間隔」的加固時間表,其中加固之間的時間在某個預定平均間隔內隨機變化。請參閱http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1404199/pdf/jeabehav00190-0145.pdf以瞭解涉及的公式。

0

像這樣的東西應該做的伎倆(此代碼沒有測試...但它編譯乾淨的)

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