Shuffle Bags Random () zufühlen

Ein Pseudo-Zufallszahlengenerator (PRNG) wie der Zufällig Die Klasse in C # ist kein echter Zufallszahlengenerator: Ihr Ziel ist es, die Zufälligkeit mit der Geschwindigkeit zu approximieren. Dies bedeutet, dass häufig eine ungleichmäßige Verteilung der Werte zurückgegeben wird, was möglicherweise nicht Ihren Vorstellungen entspricht. In diesem Tutorial zeige ich Ihnen, wie Sie dieses Problem mit a lösen können shuffle bag.

Hinweis: Obwohl dieses Tutorial C # verwendet, sollten Sie in der Lage sein, in fast jeder Spielentwicklungsumgebung dieselben Techniken und Konzepte anzuwenden.


Einführung

Als ich anfing, Spiele zu entwickeln, habe ich den Standard verwendet Zufällig() Methoden, um Abwechslung im Spiel zu schaffen, groß ansonsten Bedingungen, bis ich meine gewünschten Ergebnisse erhalten habe. Wenn die Ergebnisse nicht so ausbalanciert waren, wie ich es mir gewünscht hätte, würde ich zusätzliche Bedingungen schaffen, bis mir das Gameplay Spaß machte. Erst vor kurzem wurde mir klar, dass es bessere Ansätze gibt, um ein wirklich unterhaltsames Spielerlebnis zu schaffen.

Es ist nichts falsch mit der Verwendung des eingebauten Zufällig Klasse: Das Problem, nicht die gewünschten Ergebnisse zu erzielen, ergibt sich aus der Implementierung der Methoden. In diesem Artikel verwenden wir die Methode "Shuffle Bag" Zufällig() Fühlen Sie sich willkürlicher (und machen Sie mehr Spaß). Verwenden Sie Boggle-Boards als praktisches Beispiel.


Das Problem

Haben Sie jemals bemerkt, dass ein Ausdruck wie:

 int value = Random.Next (lowerBounds, upperBounds);

… Gibt Ihnen eine ungleichmäßige Verteilung der Zahlen?

Ein Zufallszahlengenerator, der Werte zwischen 0 und 1 auswählt, kümmert sich nicht darum, ob er alle 1 zurückgibt, wenn Sie also eine erstellt haben ansonsten Wenn Sie den obigen Ausdruck verwenden, um einen Zweig auszuwählen, erhalten Sie wahrscheinlich nicht die erwarteten Ergebnisse.

 var rand = new Random (); für (int i = 0; i < 10; i++) Console.WriteLine(rand.Next(0, 2));

Es ist nichts technisch falsch mit Random.Next (), Eine gute gleichmäßige Verteilung der Zahlen ist jedoch nicht garantiert. Dies bedeutet in vielen Spielsituationen, Zufällig() macht keinen Spaß.


Was ist eine Shuffle-Tasche??

Ein Shuffle Bag ist eine Technik zur Steuerung der Zufälligkeit, um die gewünschte Verteilung zu erzeugen. Die Idee ist:

  • Wählen Sie einen Wertebereich mit der gewünschten Verteilung aus.
  • Alle diese Werte in eine Tüte legen.
  • Mische den Inhalt der Tasche.
  • Ziehen Sie die Werte nacheinander bis zum Ende heraus.
  • Wenn Sie das Ende erreicht haben, beginnen Sie von vorne und ziehen die Werte wieder einzeln heraus.

Shuffle Bag implementieren

Das Implementieren eines Shuffle-Beutels in C # ist einfach und die Technik kann leicht in jede Sprache konvertiert werden.

Da der Zweck dieses Artikels darin besteht, sich auf die Implementierung von Shuffle Bags und nicht auf Sprachfunktionen zu konzentrieren, werden wir uns nicht mit der Verwendung von Generika beschäftigen. Ich empfehle jedoch dringend die Verwendung von Generika, da wir damit typsichere Datenstrukturen erstellen können, ohne sich auf tatsächliche Datentypen festzulegen. Mit Generics können Sie mit demselben Code Shuffle Bags erstellen, die viele verschiedene Datentypen enthalten.

Hier ist der grundlegende Code:

 öffentliche Klasse ShuffleBag privat Zufall random = new Random (); private Liste Daten; privates Zeichen currentItem; private int currentPosition = -1; private int Capacity get return data.Capacity;  public int Size get return data.Count;  public ShuffleBag (int initCapacity) data = neue Liste (initCapacity); 

Am Anfang der Klasse werden die Instanzvariablen eingerichtet, und der Konstruktor initialisiert die Dateninstanzvariable auf die Anfangskapazität des Programmierers (d. H. Wie groß die Tasche ist, um damit zu beginnen)..

 public void Add (char item, int Betrag) für (int i = 0; i < amount; i++) data.Add(item); currentPosition = Size - 1; 

Das Hinzufügen Methode fügt einfach das hinzu verkohlen zu Daten so oft wie vom Programmierer angegeben.

Notiere dass der aktuelle Position wird an das Ende der Liste gesetzt, da wir später vom Ende aus navigieren werden. Warum am Ende der Liste? Sie könnten den Shuffle Bag von Anfang an durchqueren lassen, aber wenn Sie am Ende beginnen und rückwärts arbeiten, wird der Code sauberer.

 public char Next () if (aktuellePosition < 1)  currentPosition = Size - 1; currentItem = data[0]; return currentItem;  var pos = random.Next(currentPosition); currentItem = data[pos]; data[pos] = data[currentPosition]; data[currentPosition] = currentItem; currentPosition--; return currentItem; 

Das Nächster Methode ist das Fleisch dieser Technik.

Ob aktuelle Position kleiner als Eins ist, setzen wir sie zurück, um auf das Ende der Liste zu zeigen, und geben den ersten Artikel aus der Tasche zurück. (Dies deckt die Situation ab, in der wir alle Elemente durchlaufen haben und jetzt erneut beginnen möchten.)

Ansonsten verwenden wir random.Next () einen zufälligen Artikel aus der Tasche zu holen, irgendwo zwischen dem ersten Artikel und dem Artikel an unserer aktuellen Position. Wir tauschen diesen zufällig ausgewählten Artikel mit dem Artikel an unserer aktuellen Position aus und nehmen dann ab aktuelle Position um 1.

Zum Schluss geben wir den zufällig ausgewählten Artikel zurück. Das Ergebnis ist, dass wir ständig Artikel auswählen, die wir noch nicht ausgewählt haben, während wir die Tasche mischen, während wir gehen. Das bedeutet, dass sich der Inhalt in einer anderen Reihenfolge befindet, wenn wir ihn erneut durchlaufen möchten.

Nun ist es an der Zeit, unsere neu erstellte Klasse auszuprobieren.


Verwenden der Shuffle-Bag-Klasse

Vor einigen Jahren habe ich einen Boggle-Klon für das iPhone erstellt.


Bildnachweis: Rich Brooks

Ein Problem, mit dem ich konfrontiert war, war das Erstellen von dichten Boards, die nur 16 Buchstaben verwendeten, aber es dem Benutzer erlaubten, Hunderte von Wörtern mit diesen 16 Buchstaben zu formen. Ich habe etwas über Buchstabenfrequenzen gelernt und wie ich damit eine positive Benutzererfahrung schaffen kann.

Durch die Häufigkeit, mit der Buchstaben in englischem Text erscheinen, können wir ein gewichtetes Wörterbuch erstellen.

 privates statisches Wörterbuch letterFrequencies = neues Wörterbuch 'E', 12.702, 'T', 9.056, 'A', 8.167, 'O', 7.507, 'I', 6.966, 'N', 6.769 , 'S', 6,327, 'H', 6,094, 'R', 5,998, 'D', 4,253, 'L', 4,025, 'C', 2,782, 'U', 2,758, 'M', 2,406, 'W', 2,306, 'F', 2,228, 'G', 2,015, 'Y', 1,974, ' P ', 1,929, ' B ', 1,492, ' V ', 0,978, ' K ', 0,772, ' J ', 0,153, ' X ', 0,150, ' Q ' 0,095, 'Z', 0,074; // gesamt: 99.965

Hinweis: Q wird etwas anders behandelt als die anderen Buchstaben. Es behält den Wert aus der Buchstabenhäufigkeitstabelle bei, erscheint jedoch als Qu in vielen Wortspielen.

Jetzt können wir eine Instanz unserer Shuffle-Bag-Klasse erstellen, unsere Shuffle-Bag mit Daten füllen und dichte Boggle-Boards erstellen.

 static void Main (string [] args) var shuffleBag = new ShuffleBag (88000); int Betrag = 0; foreach (var Buchstabe in letterFrequencies) Betrag = (int) letter.Value * 1000; shuffleBag.Add (letter.Key, Betrag);  für (int i = 0; i < 16; i++) Console.Write(shuffleBag.Next()); Console.WriteLine(); 

Hinweis: Das wichtigste, was man von diesem Code wegnehmen kann, ist das Menge. Ein Multiplikator von 1000 liefert bessere Ergebnisse als ein Multiplikator von 10.

Führen Sie die Ergebnisse über einen Online-Löser aus. Wie viele Wörter findest du??


Fazit

In diesem Artikel haben wir das Problem bei der Verwendung von Zufallswerten mit bestätigt ansonsten In diesem Fall haben wir eine Lösung mit Shuffle Bags eingeführt und die Verwendung durch die Erstellung von dichten Boggle Boards demonstriert. Mit der Verwendung von Shuffle Bags übernehmen wir die Kontrolle Zufällig() Methoden und schaffen eine gleichmäßige Verteilung von Werten, die zu einem positiven Spielerlebnis beitragen.