So i am creating a dice using a public class called die. this class has 2 constructors and 3 other methods. When i call class within the main program, it will not print the desired (random) result.
Firstly i am trying to print out a random number between 1-6 based on the default values. Once i figure this out, i would eventually like to specify a number of sides for and print out a number between 1 and this specific number.
/// Represents one die (singular of dice) with faces showing values between
/// 1 and the number of faces on the die.
public class Die
{
private int numFaces, faceValue;
public Die() => (numFaces, faceValue) = (6, 1);
public Die(int faces)
{
numFaces = faces;
if (numFaces < 3)
numFaces = 6;
faceValue = 1;
}
public void RollDie()
{
//for (int ctr = 0; ctr <= numFaces; ctr++)
var rnd = new Random();
for (int ctr = 1; ctr <= 20; ctr++)
faceValue = rnd.Next(1, numFaces + 1);
}
public int GetFaceValue() => faceValue;
public int GetNumFaces() => numFaces;
}
public class Program
{
public static void Main()
{
var myDie = new Die(1);
for (int i =0; i < 20; i++)
{
myDie.RollDie();
Console.WriteLine(myDie.GetFaceValue());
}
}
}
Since Random is time seeded when the parameterless constructor is used, this can have the very negative consequence of duplicating results.
Excerpt from the API documentation:
However, because the clock has finite resolution, using the
parameterless constructor to create different Random objects in close
succession creates random number generators that produce identical
sequences of random numbers.
...
On most Windows systems, Random objects created within 15 milliseconds of one another are likely to have identical seed values.
This is a safer approach in regards to getting random numbers when creating and rolling multiple dice:
public class Die
{
static int seed = Environment.TickCount;
static readonly ThreadLocal<Random> DieRandom = new ThreadLocal<Random>(()
=> new Random(Interlocked.Increment(ref seed)));
public int FaceCount { get; }
public int Value { get; private set; }
public Die() : this(6) // default to 6 faces
{
}
public Die(int faceCount)
{
if (faceCount < 3) // validate input
throw new ArgumentOutOfRangeException(nameof(faceCount));
this.FaceCount = faceCount;
}
public int Roll()
{
Value = DieRandom.Next(1, FaceCount + 1);
return Value;
}
}
Edit: updated the Random with thread safety as suggested here.
Related
I'm writing an application for testing an algorithm with random generated inputs. This involves several instances of Random class spread around the code. I need all these instances to generate same inputs in different runs to debug the algorithm when I find an unexpected result. This is the behavior of the apps created with Delphi, unless you manually call Randomize.
I know I can:
Provide constant seeds for all created instances.
Pass a unique instance, which is created with a constant seed, to all methods that need a random generator.
The reason I prefer not to use any of the above methods is that most of the functions that generate random data are kind of black box functions that are collected here and there on the Internet. Some of them even use several random generators for unknown reasons. I prefer not to mess with these functions unless I really have to.
So, are there any other ways to control all these instances together?
Here's a quick example of a class with two static members, one a "fixed RNG", while the other just a normal "RNG", that you can use from anywhere in your code:
int x = MyRandom.RNG.Next(1, 7);
int y = MyRandom.FixedRNG.Next(1, 7);
Code:
public class MyRandom
{
private static Random _fixedRandom = new Random(1234);
private static Random _random = new Random();
public static Random FixedRNG
{
get
{
return _fixedRandom;
}
}
public static Random RNG
{
get
{
return _random;
}
}
}
An alternative might be to include an IsRandom property that determines which one gets returned:
public class MyRandom
{
private static bool _isRandom = false;
private static Random _fixedRandom = new Random(1234);
private static Random _random = new Random();
public static bool IsRandom
{
get
{
return _isRandom;
}
set
{
_isRandom = value;
}
}
public static Random RNG
{
get
{
if (IsRandom)
return _random;
else
return _fixedRandom;
}
}
}
Thanks to #Idle_Mind for their suggestion. Here is a more Delphi-like version:
public static class GlobalRandom
{
private static int _randSeed = 0;
public static Random RNG { get; private set; } = new Random(_randSeed); // Made accessible for Random extensions
public static void Randomize() { RNG = new Random(); }
public static int RandSeed { get => _randSeed;
set { _randSeed = value; RNG = new Random(_randSeed); } }
public static int Next() => RNG.Next();
public static int Next(int minValue, int maxValue) => RNG.Next(minValue, maxValue);
public static int Next(int maxValue) => RNG.Next(maxValue);
public static void NextBytes(byte[] buffer) => RNG.NextBytes(buffer);
public static double NextDouble() => RNG.NextDouble();
}
Use it like:
Console.WriteLine($"Default seed (0): {GlobalRandom.Next()}");
GlobalRandom.Randomize();
Console.WriteLine($"Unknown seed: {GlobalRandom.Next()}");
GlobalRandom.RandSeed = 100;
Console.WriteLine($"Constant seed (100): {GlobalRandom.Next()}");
GlobalRandom.RandSeed = 0;
Console.WriteLine($"Back to default seed: {GlobalRandom.Next()}");
First Run:
Default seed (0): 1559595546
Unknown seed: 1837960504
Constant seed (100): 2080427802
Back to default seed: 1559595546
Second Run:
Default seed (0): 1559595546
Unknown seed: 54655523
Constant seed (100): 2080427802
Back to default seed: 1559595546
How do I create an abstract property that can be a random number?
Parent.cs:
public abstract float ageInYears{get;}
Child.cs:
public override float ageInYears{
get{
return Random.Range(0, 10);
}
}
How do I ensure that Child.cs sets ageInYears to a random number, and that random number stays the same whenever accessed in the future?
private float? age;
public override float ageInYears{
get{
if(!age.HasValue) {
age = 10.0f * ((float) x.Next()) / ((float) int.MaxValue);
}
return age;
}
I use a method I call a Managed Entropy Source. Just a static class that creates a Random, then I call methods on MES, which being static, makes all random numbers come from the same 'stream', preventing the problem where 1000+ rng pulls can sometimes have just 2 values.
Also you can make nice wrappers, like CoinFlip() or Pick(list)
Helps when debugging random events, since you can swap out your MES implementation for a fake one that just reads from a file, or maybe inputbox's the number from the user ;)
An cryptographically seeded instance of Random is created per thread (inspired by this answer: https://stackoverflow.com/a/12952155/315689).
The backing property _ageInYears is initialized during the creation of each Child. Subsequent calls to the public ageInYears property will return the same value for a given instance of Child.
public class Child : Parent
{
[ThreadStatic]
private static Random _random;
private float _ageInYears;
public override float ageInYears { get { return _ageInYears; } }
public Child()
{
if (_random == null)
{
var cryptoResult = new byte[4];
new RNGCryptoServiceProvider().GetBytes(cryptoResult);
int seed = BitConverter.ToInt32(cryptoResult, 0);
_random = new Random(seed);
}
_ageInYears = (float)_random.NextDouble() * 10f;
}
}
https://dotnetfiddle.net/pmM5EC
I was working on a simple turn based RPG game. I was working on a battle system. I had it working with 1 enemy, and wanted to update it to work on multiple enemies. I have it spawning multiple enemies, but I am having issues targeting them.
Basically, the enemies are stored in a list called actualEnemies. The enemies are generated at run time, and there can be between 1-3. A label is generated to display the enemy name, and the enemy is selected by double clicking on it.
The issue seems to be in the naming of the enemy's. They have a property called characterName to identify an enemy. The problem is, there can be 2 or more of the same type of character (for example, 3x Goblin). So in the code where the enemies are generated, I was wanting to add a 1 to the characterName if there already is one in the list. The idea is to give each enemy a unique name.
The problem is, when I try this, it changes the values of all of the enemies of the same name, and this is screwing with everything. Here is the relevant section of code:
if (EnemyExists(e)) {
e.characterName += c.ToString();
}
c is simply a counter that is being used, to let me know if it is enemy 1, 2 or 3.
The EnemyExists function is as follows:
public bool EnemyExists(Enemy e) {
bool exists = false;
int eCount = 0;
foreach (Enemy en in actualEnemies) {
if (en.characterName == e.characterName) {
eCount++;
}
}
if (eCount > 1) {
exists = true;
}
return exists;
}
Just to note, the enemies all start off with a default name. For this example I am working on, there are only 2 kinds of enemy. The game picks a random number between 1-3, to decide how many enemies there are. Each enemy will be one of the 2 pre defined enemies, picked at random again. This is why I just want to add a number to the end of a name that is already present.
I suspect it has something to do with how I am creating the list of enemies:
public void CreateActualEnemies() {
int r;
int potEnemyNum = potentialEnemies.Count;
int numEnemies;
Random rand = new Random();
numEnemies = rand.Next(1, 4 );
for (int i = 0; i < numEnemies; i++) {
r = rand.Next(0,potEnemyNum);
Enemy ene = new Enemy();
ene = potentialEnemies.ElementAt(r);
actualEnemies.Add(ene);
}
DisplayEnemyDetails();
}
When I add to actualEnemies, am I just pointing to an address in potentialEnemies, so even though I am instantiating a new Enemy, each one, if it has the same name, points to the same place? Do I need to properly copy the object?
It is late, I am tired, but I feel like I am getting closer, any help would be great, thanks.
EDIT:
Enemy Class:
public class Enemy:Character {
public int xpGiven { get; set; }
public LootTable lootTable { get; set; }
public int goldDropped { get; set; }
public bool alive { get; set; }
public NamedTimer timer { get; set; }
public Enemy() {
alive = true;
xpGiven = 10;
lootTable = new LootTable();
goldDropped = 10;
timer = new NamedTimer();
}
}
Breaking down your question:
When I add to actualEnemies, am I just pointing to an address in potentialEnemies, so even though I am instantiating a new Enemy, each one, if it has the same name, points to the same place?
By doing
Enemy ene = new Enemy();
You are essentialy creating a new pointer in memory with a "blank" valued-reference.
However, since you did
ene = potentialEnemies.ElementAt(r);
You overwrote it with the reference to the element in the list. So whatever changes you do the ene object will reflect the item in the list.
If you want to segregate said changes, try using a MemberwiseClone.
From the example given at MSDN:
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person) this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(IdInfo.IdNumber);
other.Name = String.Copy(Name);
return other;
}
}
1: Property names should start with a capital letter in C#. I.e. public int xpGiven { get; set; } should be public int XpGiven { get; set; }. If it's a class variable (no get or set defined), you start with a lower case letter. To more easily identify class variables from local variables, programmers typically start them with a _, although this is not mandatory.
2: When doing ==, please be aware enemyA == enemya will return false. Use enemyA.Equals(enemya, StringComparison.OrdinalIgnoreCase) to ignore capital differences.
3:
public void CreateActualEnemies()
{
int r;
int potEnemyNum = potentialEnemies.Count;
int numEnemies;
Random rand = new Random();
numEnemies = rand.Next(1, 4 );
for (int i = 0; i < numEnemies; i++)
{
r = rand.Next(0,potEnemyNum);
Enemy ene = new Enemy();
ene = potentialEnemies.ElementAt(r);
actualEnemies.Add(ene);
}
DisplayEnemyDetails();
}
should be:
public void CreateActualEnemies()
{
Random rand = new Random();
int numEnemies = rand.Next(1, 4 );
for (int i = 0; i < numEnemies; i++)
{
Enemy ene = new Enemy();
ene.characterName = "" + ene.GetType().Name + " " + i; // or something similar to give the ene a unique name.
actualEnemies.Add(ene);
}
DisplayEnemyDetails();
}
If I call the default constructor "Creature" in main and then try to call the method "Generate Creator" the loop never runs. If I did a normal for loop it throws out of bounds errors even knowing the default constructor sets the length of the array. It is probably a dumb error I am not seeing. (this isnt all of the code)
class Creature
{
static int geneLength;
byte[] Chromosome = new byte[geneLength];
int fitness;
string geneString;
Random rn = new Random();
public Creature()
{
geneLength = 36;
fitness = 0;
}
public void GenerateCreature()
{
foreach(byte g in Chromosome)
{
Chromosome[g] = (byte)rn.Next(0, 2);
geneString += Chromosome[g].ToString();
}
}
}
Main:
namespace Creature_Generator
{
class Program
{
static void Main(string[] args)
{
Creature c = new Creature();
c.GenerateCreature();
Console.WriteLine(c.getGeneString);
}
}
}
foreach(byte g in Chromosome)
{
Chromosome[g] = (byte)rn.Next(0, 2); // 'g' is not an index
geneString += Chromosome[g].ToString(); // 'g' is not an index
}
while you are using foreach (byte g in Chromosome), I believe it is not a proper way to use code like Chromosome[g] which g is suppose a value not an index
try
StringBuilder geneString = new StringBuilder();
public Creature()
{
geneLength = 36;
this.Chromosome = new byte[geneLength];
fitness = 0;
}
for (int i = 0; i < this.Chromosome.Length; i++)
{
byte g = this.Chromosome[i]; // this line is useless
this.Chromosome[i] = (byte)rn.Next(0, 2);
geneString.Append(this.Chromosome[i].ToString());
}
Plus, if you are hard-coding geneLength = 36 in the constructor, consider use public int geneString { get; private set;} instead of static int geneLength; or
static int _geneLength = 36;
public int geneLength { get; private set; }
public Creature() { this.geneLength = _geneLength; }
public Creature(int geneLength) { this.geneLength = geneLength; }
Edit 1 -
According to #moreON advice, string geneString is modified from class string to StringBuilder, read more on https://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx
Other than your issue attempting to use the results of foreach to index an array, as others have mentioned, you're also ignoring the order in which initialisers and constructors are executed.
If we ignore inheritance (because you have none that is interesting here). Initializers are run before constructors.
This means that you are creating the array Chromosome before assigning 36 to geneLength. This means that geneLength was still default(int), which is 0, so you created an array with length 0.
For more on c# constructors see Jon Skeet's excellent page: http://jonskeet.uk/csharp/constructors.html
geneLength should probably also not be static, but that's a different discussion.
If you want geneLength to be a static field then you need to initialize it with a static constructor. Otherwise the value of geneLength is still 0 at the moment you instantiate the class.
Write your code like this instead:
class Creature
{
static int geneLength;
byte[] Chromosome = new byte[geneLength];
int fitness;
string geneString;
Random rn = new Random();
static Creature()
{
geneLength = 36;
}
public Creature()
{
fitness = 0;
}
public void GenerateCreature()
{
foreach (byte g in Chromosome)
{
Chromosome[g] = (byte)rn.Next(0, 2);
geneString += Chromosome[g].ToString();
}
}
}
I'm stuck one an exercise which is very important to understand for my soon come final exam, in a basic C# course.
I have an issue that I can't describe in words. So I'll show you with code and perhaps then you might help me.
I've been stuck on this, not being able to solve it, for a long time. Cuz of that, I don't want any copy paste code. I want to understand it. So please enlighten me where I've failed.
Explanation what I want to do.
I want to create a dart game 501. So first I add players, they throw their darts, you get the score after each turn announced, then when one player reach 501 points, the game announce the winner and all of his throws.
My idea of approaching the problem is to have an add player loop, which terminates (I got this fixed already).
Once you done creating the players(list elements), then you'll execute the methods with a foreach loop running all the players in the player list, executing the objects one at a time and finally Here is my real problem: storing all their scores in another list.
Here we go with the code
The list.
private List<Player> players = new List<Player>(); //This list is fine
Here is the loop.
foreach (Player dartThrows in players) //My loop
{
dartThrows.DoThrow();
dartThrows.GetScore();
}
SubClass1(named Player)
public List<Darts> dartList = new List<Darts>(); //<--HERE IS THE PROBLEM
Just some random constructors and methods.
The throw method. It's not an issue but I typed it down to give you an idea
public void DoThrow()
{
var tries = 3;
for (int i = 0; i < tries; i++)
{
//No problems here just int read-user input data
}
AddDarts(int a, int b, intc)
}
Here lies all my problems, it would make my life so much easier if this could get solved.
public void AddDarts(Darts toDartList)
{
dartList.Add(toDartList);
}
SubClass2 (Darts)
Here are my constructors
private int dartOne;
private int dartOne;
private int dartOne;
Here is my method
public Darts(int DartOne, int DartTwo, int DartThree)
{
dartOne = DartOne;
dartTwo = DartTwo;
dartThree = DartThree;
}
Best regards Marcus Johansson
Here is my full program
class Program
{
static void Main(string[] args)
{
Game game = new Game();
game.PlayGame();
}
}
class Game
{
private List<Player> players = new List<Player>();
private List<Player> computers = new List<Player>();
public void AddPlayer(string newPlayers)
{
players.Add(new Player(newPlayers));
}
public void AddComputer(string newComputer)
{
computers.Add(new Player(newComputer));
}
static string UpperCaseFirst(string s)
{
if (string.IsNullOrEmpty(s))
{
return string.Empty;
}
return char.ToUpper(s[0]) + s.Substring(1);
}
public void PlayGame()
{
bool noWinner = false;
bool stopLoop = false;
Console.WriteLine("<<<WELCOME TO DART 501>>>");
Console.WriteLine("\nPress [S] to start game!");
Console.Beep();
Console.ReadLine();
Console.Clear();
do
{
Console.WriteLine("Enter name of players and type [D]ator for adding NPC\nType [S]top to start the game");
string addPlayer = Console.ReadLine();
string FirstUpperLetter = UpperCaseFirst(addPlayer);
if (FirstUpperLetter == "Stop" || FirstUpperLetter == "S")
{
stopLoop = true;
}
if (FirstUpperLetter == "D" || FirstUpperLetter == "Dator")
{
string computer = FirstUpperLetter;
AddComputer(computer);
}
else
{
AddPlayer(FirstUpperLetter);
}
} while (stopLoop == false) ;
players.RemoveAt(players.Count - 1);
do
{
Console.Clear();
foreach (Player arrowThrows in players)
{
noWinner = true;
Console.WriteLine("\n~~~Starting Round~~~~");
arrowThrows.DoThrow();
Console.WriteLine("This round you got {0}", arrowThrows.CalculatePoints());
if (arrowThrows.Score > 501)
{
Console.Clear();
Console.WriteLine("<<<WE HAVE A WINNER>>>");
System.Threading.Thread.Sleep(500);
Console.WriteLine("...The winner is: ");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("{0} He made these epic throws: ", arrowThrows.Name);
foreach(Arrows finalResult in arrowThrows.arrowList)
{
Console.WriteLine(finalResult);
Console.ReadLine();
}
noWinner = false;
}
}
foreach (Player computerThrows in computers)
{
computerThrows.RandomThrow();
System.Threading.Thread.Sleep(500);
}
}while(noWinner == true);
}
}
class Player
{
public List<Arrows> arrowList = new List<Arrows>();
public List<int> ScoreBoard = new List<int>();
public Player() { }
public int Score { get; set; }
public Player(int score)
{
Score = score;
}
public string Name { get; set; }
public Player(string name)
{
Name = name;
}
public int RoundScore { get; set; }
public void RandomThrow()
{
Random rndComp = new Random();
Console.WriteLine("...Loading Npc_throw.exe");
System.Threading.Thread.Sleep(300);
int random1 = rndComp.Next(0, 60);
System.Threading.Thread.Sleep(300);
int random2 = rndComp.Next(0, 60);
System.Threading.Thread.Sleep(300);
int random3 = rndComp.Next(0, 60);
Console.WriteLine("Random computer got this random score {0}", random1 + random2 + random3);
arrowList.Add(new Arrows(random1, random2, random3));
}
public void DoThrow()
{
Console.WriteLine("###{0} make your throws###", Name);
var tries = 3;
for (int i = 0; i < tries; i++)
{
Console.WriteLine("\nEnter score for {0} arrow", i + 1);
string arrowScore = Console.ReadLine();
int addScore = int.Parse(arrowScore);
while(-1 > addScore || 61 < addScore)
{
Console.WriteLine("\nInvalid score! Enter a score between 0-60/n<<<You may type [R]andom or [R] for a random score>>>");
arrowScore = Console.ReadLine().ToUpper();
if (arrowScore == "R" || arrowScore == "RANDOM")
{
Random rnd = new Random();
addScore = rnd.Next(0, 60);
goto start;
}
else
{
addScore = int.Parse(arrowScore);
}
}
start:
ScoreBoard.Add(addScore);
}
ScoreBoard.ToArray();
arrowList.Add(new Arrows(ScoreBoard[0],ScoreBoard[1], ScoreBoard[2]));
}
public int CalculatePoints()
{
Score = ScoreBoard.Sum();
return Score;
}
public void AddArrows(Arrows toArrowList)
{
toArrowList.ToString();
arrowList.Add(new Arrows(ScoreBoard[0], ScoreBoard[1], ScoreBoard[2]));
}
}
class Arrows
{
private int arrowOne;
private int arrowTwo;
private int arrowThree;
public int score { get; set; }
public Arrows(int ArrowOne, int ArrowTwo, int ArrowThree)
{
arrowOne = ArrowOne;
arrowTwo = ArrowTwo;
arrowThree = ArrowThree;
}
public int GetScore()
{
return arrowOne + arrowTwo + arrowThree;
}
public override string ToString()
{
return string.Format("{0}-1:st arrow: {1}-2:nd arrow: {2}- 3:rd arrow: {3}", GetScore(), arrowOne, arrowTwo, arrowThree);
}
}
}
The problem with your approach, is your utilizing a List. This collection has no unique information, simply a grouping of data. Which would have me recommend either a Tuple, Dictionary, KeyValuePair, or a clean Data Model.
Without the requirements are approaches may not be viable. Your issue stems from persistence related issues. Your multiple inheritance title is also incorrect, C# only allows a single class to be inherited.
What I would potentially do would be:
public class Player
{
public string Name { get; set; }
public string Throw { get; set; }
public string Points { get; set; }
}
What this does, is incredibly beneficial. The above class represents a specific Model. When your method is called for a throw you apply said results. Then when you calculate the score you iterate through the List<Player> for a specific person or all and display the output.
I'm not going to write your application, but think of it like this:
Player Registers
Player Turn
Player Throws
Play Scored
Store Player Result
Repeat Steps two through five, three times.
Display Output: Player, Throw, Score, and Total Score
By utilizing that model, you hold the relative information for your outcome. This conceptual notion is important for Object Oriented Programming.
You can use a Dictionary to save scores for each player
Dictionary<Player, List<int>> playerScores = new Dictionary<Player, List<int>>();
playerScores.Add(player1, new List<int>()); //init dictionary with a new player
playerScores[player1].Add(number); //add a value to the list associated with the player
So each player has a list of scores.