2016-07-27 7 views
1

Ich versuche, Monte-Carlo-Simulation in C# Windows Form Anwendung mit gewichteten Quick Union mit Pfadkomprimierung Methode zu implementieren. Zum einen nehme ich gridSize und erzeugen dann ein Gitter zu gridSize * gridSize gleich und besteht aus schwarzem Hintergrund Etiketten, die Websites darstellen, dann ich zufällig Vereinigung einige Websites und ihren Hintergrund in weiß machen. Das Problem ist, wenn ich das Projekt laufen lasse, bekomme ich die ganzen Seiten in schwarz -noch egal, wie oft ich versuche-, aber wenn ich Haltepunkte hinzugefügt habe und Schritt für Schritt vorgegangen bin, bekomme ich einige weiße Seiten wie beabsichtigt !!! HierSeltsames Verhalten bei der Implementierung von Monte Carlo Simulation in C#

ist der Code:

public partial class Form1 : Form 
{ 
    int gridSize = 0; 
    byte siteSize = 50; 
    FlowLayoutPanel flowLayoutPanel; 
    UnionFind uf; 
    int randomFirstNumber; 
    int randomSecondNumber; 
    string labelName = string.Empty; 
    Random rnd = new Random(); 
    int numberOfAttempts; 
    Label label; 
    HashSet<int> excludeHashSet = new HashSet<int>(); 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void setGridSizeButton_Click(object sender, EventArgs e) 
    { 
     if (!string.IsNullOrEmpty(gridSizeTextbox.Text) && int.TryParse(gridSizeTextbox.Text, out gridSize)) 
     { 
      if (gridSize > 0) 
      { 
       var flowLayoutPanel = createFlowLayoutPanelAndLabels(); 

       setGridSizeButton.Enabled = false; 
       gridSizeTextbox.Enabled = false; 

       randomlyUnionSitesAndWhiteThem(); 
      } 
     } 
    } 

    private void reset_Click(object sender, EventArgs e) 
    { 
     setGridSizeButton.Enabled = true; 
     gridSizeTextbox.Enabled = true; 
     gridSizeTextbox.Text = string.Empty; 
     flowLayoutPanel.Dispose(); 
     excludeHashSet = new HashSet<int>(); 
     gridSizeTextbox.Focus(); 
    } 

    private FlowLayoutPanel createFlowLayoutPanelAndLabels() 
    { 
     flowLayoutPanel = new FlowLayoutPanel(); 
     flowLayoutPanel.Name = "flowLayoutPanel"; 
     flowLayoutPanel.Location = new Point(30, 60); 
     flowLayoutPanel.Size = new Size(gridSize, gridSize); 
     flowLayoutPanel.BorderStyle = BorderStyle.Fixed3D; 
     flowLayoutPanel.Width = siteSize * gridSize + 10 * gridSize; 
     flowLayoutPanel.Height = siteSize * gridSize + 10 * gridSize; 

     for (int i = 0; i < gridSize * gridSize; i++) 
     { 
      var label = new Label(); 
      label.Text = ""; 
      label.Name = i.ToString(); 
      label.Width = siteSize; 
      label.Height = siteSize; 
      label.BackColor = Color.Black; 
      label.Margin = new Padding(3); 
      label.BorderStyle = BorderStyle.FixedSingle; 

      flowLayoutPanel.Controls.Add(label); 
     } 
     this.Controls.Add(flowLayoutPanel); 

     return flowLayoutPanel; 
    } 

    private void randomlyUnionSitesAndWhiteThem() 
    { 
     uf = new UnionFind(gridSize * gridSize); 

     numberOfAttempts = rnd.Next(0, gridSize * gridSize); 
     for (int i = 0; i < numberOfAttempts; i++) 
     { 
      randomFirstNumber = getRandomNumber(0, gridSize * gridSize, excludeHashSet); 
      randomSecondNumber = getRandomNumber(0, gridSize * gridSize, excludeHashSet); 

      labelName = uf.union(randomFirstNumber, randomSecondNumber).ToString(); 
      if (Convert.ToInt16(labelName) > -1) 
      { 
       label = (Label)flowLayoutPanel.Controls.Find(labelName, false).First(); 
       label.BackColor = Color.White; 
       excludeHashSet.Add(Convert.ToInt16(labelName)); 
      } 
     } 
    } 

    private int getRandomNumber(int min, int max, HashSet<int> excludes) 
    { 
     int randomNumber; 
     do 
     { 
      var range = Enumerable.Range(min, max).Where(i => !excludes.Contains(i)); 

      var rand = new Random(); 
      int index = rand.Next(0, max - excludes.Count); 

      randomNumber = range.ElementAt(index); 
     } 
     while (excludes.Any(x => x == randomNumber)); 

     return randomNumber; 
    } 
} 

Und das ist mein Union Methode:

class UnionFind 
{ 
    ..... 
    public int union(int firstNumber, int secondNumber) 
    { 
     firstNumber = getRoot(firstNumber); 
     secondNumber = getRoot(secondNumber); 

     if (firstNumber == secondNumber) 
     { 
      return -1; 
     } 

     if (sizes[firstNumber] < sizes[secondNumber]) 
     { 
      array[firstNumber] = secondNumber; 
      sizes[secondNumber] += sizes[firstNumber]; 

      return array[firstNumber]; 
     } 
     else 
     { 
      array[secondNumber] = firstNumber; 
      sizes[firstNumber] += sizes[secondNumber]; 

      return array[secondNumber]; 
     } 
    } 
    ..... 
} 

Antwort

0

dachte ich, den Grund für das seltsame Verhalten aus. Dies passiert, wenn Sie die Klasse Random so oft in einer Schleife verwenden. Dies kann mit mehreren Methoden gelöst werden.

Zum Beispiel System.Threading.Thread.Sleep(10);. Hier machen Sie Schleife schlafen für n Millisekunden. Diese

private int getRandomNumber(int min, int max, HashSet<int> excludes) 
{ 
    int randomNumber; 
    do 
    { 
     System.Threading.Thread.Sleep(10); 
     ... 

kann auch erreicht werden, indem System.Timers.Timer die das gleiche Ergebnis ergibt. Auch diese Methode ist für ein solches Problem besser geeignet.

System.Timers.Timer myTimer = new System.Timers.Timer(); 

private void percolateEverySecond() 
{ 
    myTimer.Elapsed += new ElapsedEventHandler(percolateForTimer); //this is the function that will be executed every myTimer.Interval 
    myTimer.Interval = 1000; 
    myTimer.Enabled = true; 
} 

private void percolateForTimer(object source, ElapsedEventArgs e) 
{ 
    //randomly white site, then union it with surrounding sites 
    ... 
} 

private void Start_Click(object sender, EventArgs e) 
{ 
    ... 
    percolateEverySecond(); 
} 

Siehe this für weitere Informationen über System.Threading.Thread.Sleep() vs System.Timers.Timer.

Beachten Sie auch, dass der obige Code in der Frage einen großen Raum für Verbesserungen hat, aber als allgemeine Regel sollten Sie jede Funktion nur für eine bestimmte Aufgabe "Single Responsibility Principle" verantwortlich machen.

+1

Also, im Grunde war Alex richtig, auch wenn die Erklärung einige Details verpasste.Und wenn man eine einzelne "Random" -Instanz anstelle einer neuen basierend auf der aktuellen Zeit verwendet, dann erscheint eine weitere neue, die ebenfalls auf der (unveränderten) aktuellen Zeit basiert, als eine viel bessere Lösung als willkürlich gewählte Verzögerungen, um zu verhindern, dass die gleiche Zeit gesehen wird zweimal. – hvd

0

Sie müssen nur This.Refresh nennen() -Methode am Ende Ihres randomlyUnionSitesAndWhiteThem() Methode;)

+0

Leider hat dies das Problem nicht gelöst. – Ahmed

1

Sie haben in Ihrer getRandomNumber-Methode ein neues Random-Objekt deklariert, das Ihnen immer den gleichen Wert gibt; Wenn Sie stattdessen Ihr Attribut rnd verwenden, funktioniert es.

Here is the explanation

+0

Ich habe es versucht, und es hat das Problem nicht gelöst. Ich bekomme die Zufallszahlen nicht in den gleichen Werten, ich bekomme jedes Mal andere Werte. Mein Problem ist, dass ich das gewünschte Verhalten erhalte, wenn ich Breakpoints hinzufüge und den Code Zeile für Zeile ausfühle, aber wenn ich das Programm nur zeilenweise ausführen lasse, bekomme ich die ganzen Seiten in schwarz, was bedeutet, dass sie nicht erhalten sind Gewerkschaft Das bedeutet, dass ich 2 Verhaltensweisen/Ergebnisse für den gleichen Code bekomme. Ich möchte wissen, warum und wie Sie das beheben können. – Ahmed

+0

Alex hat Recht. New Random() erstellt einen neuen Random basierend auf der aktuellen Zeit. Laufen mit Breakpoints verlangsamt alles so sehr, dass man ein anderes zufälliges bekommt. –

Verwandte Themen