En pseudo slumpmässig talgenerator (PRNG) som Slumpmässig
Klass i C # är inte en sann slumptalgenerator: dess mål är att approximera slumpmässighet med hastighet. Det betyder att det ofta kommer att återkomma en ojämn fördelning av värden, vilket kanske inte är vad du vill ha. I den här handledningen visar jag dig hur du löser detta problem med en shuffle väska.
Notera: Även om denna handledning använder C #, borde du kunna använda samma tekniker och begrepp i nästan vilken spelutvecklingsmiljö som helst.
När jag började skapa spel, använde jag standarden Slumpmässig()
metoder för att skapa variation i spel, skapa stora om annat
villkor tills jag fick mina önskade resultat. Om resultaten inte balanserade hur jag ville ha dem skulle jag skapa ytterligare villkor tills jag kände att spelet var kul. Det var inte förrän jag insåg att det finns bättre tillvägagångssätt för att skapa en riktigt underhållande spelupplevelse.
Det finns inget fel med användandet av det inbyggda Slumpmässig
klass: problemet med att inte få de önskade resultaten härrör från genomförandet av metoderna. I den här artikeln använder vi "Shuffle Bag" -metoden för att göra Slumpmässig()
känner sig mer slumpmässig (och roligare), med hjälp av Boggle boards som ett praktiskt exempel.
Har du någonsin märkt att ett uttryck som:
int värde = Random.Next (lowerBounds, upperBounds);
... ger dig en ojämn fördelning av siffror?
En slumptalsgenerator som väljer värden mellan 0 och 1 bryr sig inte om den returnerar alla 1s, så om du har skapat en om annat
blockera med ovanstående uttryck för att välja en filial får du förmodligen inte de resultat du förväntar dig.
var rand = ny slumpmässig (); för (int i = 0; i < 10; i++) Console.WriteLine(rand.Next(0, 2));
Det finns inget tekniskt fel med Random.Next ()
, men det garanterar inte en fin jämn fördelning av siffror. Det betyder att i många spel situationer, Slumpmässig()
Det är inte kul.
En Shuffle Bag är en teknik för att styra slumpmässigt för att skapa den distribution vi önskar. Tanken är:
Att implementera en Shuffle Bag i C # är enkel, och tekniken kan enkelt konverteras till något språk.
Eftersom syftet med denna artikel är att fokusera på genomförandet av Shuffle Bags och inte språkfunktioner, kommer vi inte att titta på användningen av generics. Jag rekommenderar dock starkt användningen av generika eftersom de tillåter oss att skapa säkra datastrukturer utan att förbinda sig till faktiska datatyper. Generics tillåter dig att använda samma kod för att skapa Shuffle Bags som innehåller många olika typer av data.Här är den grundläggande koden:
offentlig klass ShuffleBag privat slumpmässig slumpmässig = ny slumpmässig (); privat listadata; privat char currentItem; privat int currentPosition = -1; privat int Kapacitet get return data.Capacity; public int Storlek get return data.Count; offentlig ShuffleBag (int initCapacity) data = ny lista (initCapacity);
I början av klassen skapas instansvariablerna, och konstruktorn initierar datainnexervariabeln till programmerarens initialkapacitet (dvs hur stor väskan ska börja med).
public void Lägg till (char item, int mängd) for (int i = 0; i < amount; i++) data.Add(item); currentPosition = Size - 1;
De Lägg till
Metoden lägger helt enkelt till röding
till data
så många gånger som programmeraren specificerar.
Observera att nuvarande position
är satt till slutet av listan, som vi kommer att korsa från slutet senare. Varför från slutet av listan? Du kan göra Shuffle Bag från början, men börjar i slutet och arbetar bakåt gör renare kod.
public char Nästa () if (currentPosition < 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;
De Nästa
Metoden är köttet i denna teknik.
Om nuvarande position
är mindre än en, vi återställer den för att peka till slutet av listan och returnera det första objektet från väskan. (Detta täcker situationen där vi har kryssat igenom alla objekt och vill nu börja om igen.)
Annars använder vi random.Next ()
att välja ett slumpmässigt objekt från väskan, från någonstans mellan första objektet och föremålet vid vår nuvarande position. Vi byter ut det här slumpmässigt utvalda objektet med objektet i vår nuvarande position och minskar sedan nuvarande position
med 1.
Slutligen returnerar vi det slumpmässigt valda objektet. Resultatet är att vi fortsätter att plocka föremål som vi inte har valt före, medan du shufflar påsen när vi går. Det innebär att innehållet är i en annan ordning när vi vill korsa den igen.
Nu är det dags att prova vår nyskapade klass.
För flera år sedan skapade jag en Boggle-klon för iPhone.
Ett problem som jag mötte var att skapa täta brädor som bara använde 16 bokstäver, men fick användaren att skapa hundratals ord med de 16 bokstäverna. Jag lärde mig om brevfrekvenser, och hur jag kunde använda den för att skapa en positiv användarupplevelse.
Genom att använda frekvensen som bokstäver visas i engelsk text kan vi konstruera en vägd ordlista.
privata statiska bokstavsfrekvenser= ny ordbok '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,987, '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; // totalt: 99.965
Notera: Q hanteras lite annorlunda än de andra bokstäverna. Den behåller värdet från brevfrekvensbordet, men det verkar som Qu i många ordspel.
Nu kan vi skapa en förekomst av vår Shuffle Bag-klass, fylla vår Shuffle Bag med data och skapa täta Boggle Boards.
static void Main (sträng [] args) var shuffleBag = ny ShuffleBag (88000); int mängd = 0; foreach (var brev i brevFrekvenser) amount = (int) letter.Value * 1000; shuffleBag.Add (letter.Key, mängd); för (int i = 0; i < 16; i++) Console.Write(shuffleBag.Next()); Console.WriteLine();
Notera: Det viktigaste att ta bort från den här koden är belopp
. En multiplikator på 1000 returnerar bättre resultat än en multiplikator på 10.
Kör resultaten genom en online-lösare. Hur många ord hittar du?
I denna artikel erkände vi problemet med att använda slumpmässiga värden med om annat
villkor, introducerade vi en lösning med hjälp av Shuffle Bags, och visade en användning genom att skapa täta Boggle Boards. Med användning av Shuffle Bags tar vi kontroll över Slumpmässig()
metoder och skapa en jämn fördelning av värden som hjälper till i en positiv spelupplevelse.