Een pseudo random number generator (PRNG) zoals de Willekeurig
Klasse in C # is geen echte generator voor willekeurige getallen: het doel is om willekeurigheid met snelheid te benaderen. Dit betekent dat het vaak een ongelijke verdeling van waarden oplevert, wat niet is wat u wilt. In deze zelfstudie laat ik u zien hoe u dit probleem kunt oplossen met een shuffle tas.
Notitie: Hoewel deze tutorial C # gebruikt, zou je in bijna elke game-ontwikkelomgeving dezelfde technieken en concepten moeten kunnen gebruiken.
Toen ik games begon te maken, gebruikte ik de standaard Willekeurig()
methoden om variëteit in gameplay te creëren, groot te maken if / else
voorwaarden totdat ik de gewenste resultaten heb ontvangen. Als de resultaten niet in balans waren zoals ik ze wilde, creëerde ik extra voorwaarden totdat ik vond dat het spelen leuk was. Het was tot voor kort dat ik me realiseerde dat er betere benaderingen zijn bij het creëren van een echt vermakelijke spelervaring.
Er is niets mis met het gebruik van de ingebouwde Willekeurig
klasse: het probleem van het niet behalen van de gewenste resultaten komt voort uit de implementatie van de methoden. In dit artikel gebruiken we de "Shuffle Bag" -methode om te maken Willekeurig()
voel meer willekeurig (en leuker), met behulp van Boggle-platen als een praktisch voorbeeld.
Heb je ooit gemerkt dat een uitdrukking als:
int value = Random.Next (lowerBounds, upperBounds);
... geeft u een ongelijke verdeling van getallen?
Een generator voor willekeurige getallen die waarden tussen 0 en 1 kiest, maakt het niet uit als alle 1-en worden geretourneerd, dus als u een hebt gemaakt if / else
blokkeren met behulp van de bovenstaande uitdrukking om een filiaal te kiezen, krijgt u waarschijnlijk niet de resultaten die u verwacht.
var rand = nieuw Willekeurig (); voor (int i = 0; i < 10; i++) Console.WriteLine(rand.Next(0, 2));
Er is niets technisch mis mee Random.Next ()
, maar het garandeert niet een mooie gelijkmatige verdeling van nummers. Dit betekent dat in veel gameplay-situaties, Willekeurig()
is niet leuk.
Een Shuffle Bag is een techniek om willekeur te beheersen om de door ons gewenste verdeling te creëren. Het idee is:
Het implementeren van een Shuffle Bag in C # is eenvoudig en de techniek kan eenvoudig in elke taal worden omgezet.
Aangezien het doel van dit artikel is om ons te concentreren op de implementatie van Shuffle Bags en niet op taalfuncties, zullen we niet kijken naar het gebruik van generieke geneesmiddelen. Ik raad echter ten sterkste het gebruik van generieke geneesmiddelen aan, omdat ze ons in staat stellen veilige datastructuren van het type te maken zonder zich te verbinden aan de werkelijke gegevenstypen. Met Generics kunt u dezelfde code gebruiken om Shuffle Bags te maken met veel verschillende soorten gegevens.Hier is de basiscode:
public class ShuffleBag private Random random = new Random (); privélijstgegevens; privé char currentItem; private int currentPosition = -1; private int Capacity krijg return data.Capacity; public int Size krijg return data.Count; openbare ShuffleBag (int initCapacity) data = new List (initCapacity);
Het begin van de klasse stelt de instantievariabelen in, en de constructor initialiseert de gegevensinstantie-variabele in de initiële capaciteit van de programmeur (d.w.z. hoe groot de tas is om mee te beginnen).
public void Toevoegen (char item, int amount) for (int i = 0; i < amount; i++) data.Add(item); currentPosition = Size - 1;
De Toevoegen
methode voegt gewoon de verkolen
naar gegevens
zo vaak als de programmeur aangeeft.
Merk op dat de huidige positie
is ingesteld op het einde van de lijst, omdat we later van het einde zullen oversteken. Waarom vanaf het einde van de lijst? U kunt de Shuffle-tas vanaf het begin doorlopen, maar begin aan het einde en achteruit werken zorgt voor schonere code.
public char Next () 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 volgende
methode is het vlees van deze techniek.
Als huidige positie
is minder dan één, we resetten het om naar het einde van de lijst te wijzen en het eerste item uit de zak te retourneren. (Dit geeft de situatie weer waarin we alle items hebben doorlopen en nu opnieuw willen beginnen.)
Anders gebruiken we random.Next ()
om een willekeurig item uit de tas te halen, ergens tussen het eerste item en het item op onze huidige positie. We wisselen dit willekeurig geselecteerde item uit met het item op onze huidige positie en verlagen vervolgens huidige positie
door 1.
Ten slotte retourneren we het willekeurig geselecteerde item. Het resultaat is dat we items blijven plukken die we nog niet eerder hadden gepickt, terwijl we de tas schuifelen terwijl we verder gaan. Dit betekent dat de inhoud ervan in een andere volgorde staat wanneer we hem opnieuw willen doorkruisen.
Nu is het tijd om onze nieuw gecreëerde klas uit te proberen.
Enkele jaren geleden heb ik een Boggle-kloon voor de iPhone gemaakt.
Een probleem waar ik mee te maken kreeg, was het maken van dichte borden die slechts 16 letters gebruikten, maar de gebruiker toestonden honderden woorden te vormen met die 16 letters. Ik leerde over letterfrequenties en hoe ik het kon gebruiken om een positieve gebruikerservaring te creëren.
Door de frequentie te gebruiken dat letters in Engelse tekst voorkomen, kunnen we een gewogen woordenboek construeren.
privé statische WoordenboekletterFrequenties= nieuw Woordenboek '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; // totaal: 99.965
Notitie: Q is een beetje anders behandeld dan de andere letters. Het behoudt de waarde van de letterfrequentietabel, maar het wordt weergegeven als Qu in veel woordspelletjes.
Nu kunnen we een exemplaar van onze Shuffle Bag-klasse maken, onze Shuffle Bag vullen met gegevens en dichte Boggle Boards maken.
static void Main (string [] args) var shuffleBag = new ShuffleBag (88000); int amount = 0; foreach (var letter in letterFrequencies) amount = (int) letter.Value * 1000; shuffleBag.Add (letter.Key, aantal); voor (int i = 0; i < 16; i++) Console.Write(shuffleBag.Next()); Console.WriteLine();
Notitie: Het belangrijkste om dit stukje code af te halen, is het bedrag
. Een vermenigvuldiger van 1000 levert betere resultaten op dan een vermenigvuldiger van 10.
Voer de resultaten uit via een online oplosser. Hoeveel woorden vind je?
In dit artikel hebben we het probleem erkend met het gebruik van willekeurige waarden bij if / else
voorwaarden, hebben we een oplossing geïntroduceerd met Shuffle Bags en een gebruik aangetoond door dichte Boggle Boards te maken. Met het gebruik van Shuffle Bags nemen wij de controle over Willekeurig()
methoden en creëer een gelijkmatige verdeling van waarden die bijdragen aan een positieve spelervaring.