2017-04-20 4 views
0

Ich mache ein einfaches Spiel, um meine C# Fähigkeiten zu verbessern. Ich lese über die Random() -Klasse und wie sie einen Seed von Datetime generiert und einige Ergebnisse gefunden, wie man einen Pseudozufallsgenerator von einer Instanz bekommt.C# zufällige Seed-Generator von mehreren Instanzen

Spielerklasse:

Random dice = new Random(); 
    public int RollDice() 
    { 
     int dice1 = dice.Next(1, 7); 
     int dice2 = dice.Next(1, 7); 
     int sum = dice1 + dice2; 
     Console.WriteLine("D1: " + dice1 + " D2: " + dice2 + " SUM: " + sum); 
     return sum; 
    } 

Main:

//infiniteloop{ 
     player1.RollDice(); 
     Console.ReadKey(); 
     player2.RollDice(); 
    } 

Nach Ausgang, nicht mehr, wie lange ich warten, um die Taste zu drücken und wieder rufen die player2.DiceRoll() wird es noch rollen die gleichen Zahlen. Wenn ich nur einen Spieler habe, funktioniert es perfekt. Wie kann ich das verbessern?

+0

Sie möchten 'Würfel' statisch machen. Ich nehme an, du hast 'player1' und' player2' in schneller Folge erstellt und sie haben den gleichen Samen. – juharr

Antwort

3

Pseudo-Zufallszahlengeneratoren einmal ausgesät werden, wenn sie erstellt werden. Nachdem sie gesetzt wurden, folgen sie einem festen Zyklus durch die Zahlen (basierend auf ihrem Seed), um die nächste Zahl zu erzeugen.

Wenn Sie den Random-Konstruktor ohne ein Argument verwenden, wird die aktuelle Zeit als Startwert verwendet. Bei allen folgenden Anrufen, bei denen eine Nummer tatsächlich generiert wird, wird die aktuelle Zeit nicht mehr verwendet. Es spielt also keine Rolle, wie lange Sie zwischen diesen Anrufen warten.

Das Problem, das Sie sehen, ist, dass jeder Spieler ein Random eigenes Objekt hat und diese zur gleichen Zeit erstellt werden. Siehe das folgende Beispiel:

// these are created pretty much at the same time 
var r1 = new Random(); 
var r2 = new Random(); 


Console.WriteLine(r1.Next(1, 7)); 
Console.WriteLine(r2.Next(1, 7)); 

Console.WriteLine(r1.Next(1, 7)); 
Console.WriteLine(r2.Next(1, 7)); 

Console.WriteLine(r1.Next(1, 7)); 
Console.WriteLine(r2.Next(1, 7)); 

Console.WriteLine(r1.Next(1, 7)); 
Console.WriteLine(r2.Next(1, 7)); 

Wenn Sie diesen Code ausführen, werden Sie sehen, dass die Zahlen aus den beiden Zufallsgeneratoren sind immer gleich. Dies liegt daran, dass sie mit der gleichen Zeit ausgesät werden.

Um dies zu beheben, müssten Sie diese Generatoren anders seeden oder sicherstellen, dass eine tatsächlich erstellt wird nach die andere.

Eine viel bessere Lösung wäre jedoch, ein einzelnes Objekt einzuführen, das für das Erstellen zufälliger Würfelwürfe verantwortlich ist. Ihre Player Objekte würden dann den gleichen Dies-Generator verwenden, der nur einen einzigen Zufallszahlengenerator hat. Die Zufallszahlen würden also vom selben Generator kommen und verhindern, dass sie identisch sind. Etwas wie folgt aus:

public class DieGenerator 
{ 
    private Random rand = new Random(); 

    public int Roll() 
    { 
     return rand.Next(1, 7); 
    } 
} 

Sie würden dann eine Aufgabe dieser erstellen und übergeben sie an die Player so können sie es verwenden, um die Würfel anstatt sich auf ihre eigenen Zufallszahlengenerator zu rollen.

+1

Eine Sache, auf die man achten sollte, wenn eine Instanz von 'Random' über Klassen verteilt wird. 'Random' ist nicht threadsicher. Wenn Sie also Multi-Threading durchführen, müssen Sie eine' lock (rand) {...} 'um den' .Next'-Aufruf legen. –

0

Ihr Zufallsgenerator dice wird nicht an dem Punkt erstellt, an dem player2.RollDice() aufgerufen wird. Es wird erstellt, wenn Sie die player2 Instanz erstellen, die, wie ich annehme, zur gleichen Zeit erstellt wird player1 ist und das ist, warum Sie die gleichen Rollen sehen; Beide dice haben die gleichen Samen.

Um dies zu beheben, besteht eine Möglichkeit darin, einen eindeutigen Zufallsgenerator zu erstellen und ihn in Player Instanzen zu injizieren.

Zum Beispiel wie folgt aussehen würde über Konstruktor Injektion:

public class Player 
{ 
    private readonly Random dice; 

    public Player(Random dice) 
    { 
     Debug.Assert(dice != null); 
     this.dice = dice; 
    } 

    public int RollDice() => dice.Next(1, 7); 
} 

Und du würdest es wie folgt verwendet werden:

var dice = new Random(); 
var player1 = new Player(dice); 
var player2 = new Player(dice); 
0

Wie die anderen Antworten weisen darauf hin, Ihr Problem ist, dass Sie verwenden zwei (identisch gesetzte) Zufallszahlengeneratoren, die jeweils die gleiche Sequenz erzeugen. Es gibt ein paar Möglichkeiten, um diesen:

Option Eins: Seed jeden Zufall anders in dem Spieler-Konstruktor

Player(int seed) { 
    this.dice = new Random(seed); 
} 

dann in Ihrem main.cs

var player1 = new Player(1); 
var player2 = new Player(2); 

Option 2: Erstellen eine einzelne Random und übergeben Sie es in Ihrem Konstruktor (oder Ihre Anrufe an RollDice)

01 Dies bedeutet, dass jedoch viele Stellen die Random in Player statischen

Random dice = new Random();

Änderungen

static Random dice = new Random();

:

Diese Methode wurde von @sdgfsdh

Option 3 detailliert beschrieben worden Players Sie erstellen, th Sie werden alle das gleiche Random verwenden und Ihr ursprüngliches Problem vermeiden.

+0

Warum eine statische Variable überhaupt einführen? – sdgfsdh

+0

Damit beide '' '' 's'' Random' verwenden, anstatt dass beide eigene (identisch gesetzte) Instanzen haben. Probieren Sie es aus, es funktioniert gut. – paul

0

Wahrscheinlich wird dice gleichzeitig für beide Spieler erstellt, was ihnen beide den gleichen Samen gibt.Ich würde empfohlen Schaffung einer Würfel für beide Spieler:

// Removed "Random dice = new Random(); " 

public int RollDice(Random dice) 
{ 
    int dice1 = dice.Next(1, 7); 
    int dice2 = dice.Next(1, 7); 
    int sum = dice1 + dice2; 
    Console.WriteLine("D1: " + dice1 + " D2: " + dice2 + " SUM: " + sum); 
    return sum; 
} 


// Main 
var dice = new Random(); 
while (true) 
{ 
    player1.RollDice(dice); 
    Console.ReadKey(); 
    player2.RollDice(dice); 
} 
Verwandte Themen