So I am trying to learn some C#, currently on a short course on An Introduction to Programming. I have a question in my text book which is giving me pretty much simular results to this post Same random numbers from instantiated class
I have tried to follow the solution but get the same results every time, the task is to Roll two dice and display their numbers using 2 instances of a class. But like the post above the "dice" role the same number. If I call the same instance of the class twice and out put the values to separate labels I get completely different values like i want. here is the class:
namespace CH10_Ex10._5
{
public class ThrowDice
{
public ThrowDice()
{
}
private Random newRandom = new Random();
private int x;
public void Throw()
{
x = newRandom.Next(1, 7);
}
public int value
{
get
{
return x;
}
}
}
}
and here is my main form:
namespace CH10_Ex10._5
{
public partial class Form1 : Form
{
ThrowDice Die1;
ThrowDice Die2;
public Form1()
{
InitializeComponent();
Die1 = new ThrowDice();
Die2 = new ThrowDice();
}
private void button1_Click(object sender, EventArgs e)
{
Die1.Throw();
dieOneLabel.Text = Convert.ToString(Die1.value);
Die2.Throw();
dieTwoLabel.Text = Convert.ToString(Die2.value);
}
}
}
I have tried to find an answer with out opening a new post so i am sorry if this have been answered before. I am very green at this.
My understanding is that if i declare objects with new, then i am creating separate instances of the class and therefore when i call those objects they should run independently/separately, but use the same rules which are specified in my class. I have tried to debug and as i step through the code i see the 2 separate calls to the class and what it looks like is the call 1 generates a random number eg 6 and call 2 seems to generate 6 as well.
thanks in advance
The problem is that the random instance will be initialized with the current time since you're using the default constructor. Since that happens on two instances very quick they get the same seed here:
public Form1()
{
InitializeComponent();
Die1 = new ThrowDice();
Die2 = new ThrowDice();
}
You could make it static:
private static Random newRandom = new Random();
Random constructor:
The default seed value is derived from the system clock and has finite
resolution. As a result, different Random objects that are created in
close succession by a call to the default constructor will have
identical default seed values and, therefore, will produce identical
sets of random numbers.
However, Random is not thread safe. So you should have a look at this answer.
This is also really worth reading: C# in Depth: Random numbers which suggests to use ThreadLocal<T> which is new in .NET 4 instead of static with lock.
You can fix this using same random instance in both instances.For example you can add a constructor like this:
private Random newRandom;
public ThrowDice(Random rnd)
{
newRandom = rnd;
x = newRandom.Next(1, 7);
}
Then:
Random rnd = new Random;
public Form1()
{
InitializeComponent();
Die1 = new ThrowDice(rnd);
Die2 = new ThrowDice(rnd);
}
What i usually use :
private Random newRandom = new Random(Guid.NewGuid().GetHashCode());
Related
Which is better and is there a difference in the random results ?
void Func1(Random rand)
{
var num=rand.Next();
}
void Func2(ref Random rand)
{
var num=rand.Next();
}
They are functionally equivalent. You don't update the rand reference in the function so passing it by ref does nothing.
Rule of thumb: don't use ref unless you absolutely have to and understand what it does.
1) Never use ref if you don't need it explicitely.
2) Usually you shouldn't need to pass Random through methods. If you have to, probably you are doing something wrong in your code.
Why? Because to be sure of a true randomness, it's better to always use the same Random instance instead of creating many of them.
That's why you should always declare one and use it around, like in this example:
class Program
{
static void Main(string[] args)
{
RandomNumbersPrinter randomNumbersPrinter = new RandomNumbersPrinter();
int randomInteger = randomNumbersPrinter.GetRandomInteger();
Console.WriteLine(randomInteger);
}
}
public class RandomNumbersPrinter
{
private static readonly Random _random = new Random();
public int GetRandomInteger()
{
return _random.Next();
}
}
Since Random is a reference type, the only difference is that the reference to the instance get copied when calling Func1.
In Func2, you are passing the actual existing reference to the Random itself to the method.
Please consult the docs for more information about this.
The bottom line is that you shouldn't use the ref keyword here unless you intend to assign rand to a new Random object in the method.
i have a listBox and i want everytime show random item from my list.
var random = new Random();
int index = random.Next(listBox1.Items.Count);
Console.Writeline(listBox1.Items[index].toString());
var random = new Random();
int index = random.Next(0, listBox1.Items.Count);
Console.Writeline(listBox1.Items[index].toString());
var random=new Random();
int index=random.Next(0,listBox1.Items.Count);
Basically random.Next(min,max) require min and max values so that random number is generated between the given range.
You should provide range also .
Console.Writeline(listBox1.Items[index].toString());
I just use your code #ilyas it's working fine, stick with it, just use
MessageBox.Show(listBox1.Items[index].ToString());
instead of
Console.Writeline(listBox1.Items[index].toString());
i assume you are creating WinForm Application
Your code seems to be ok. But if you are using it in a tight loop, it would give you always the same number. Maybe this is your problem?
Every time you do new Random() it is initialized using the clock.
This means that in a tight loop you get the same value lots of times. You should keep a single Random instance and keep using Next on the same instance.
//Define your random class with a static field
public static class RandomAccessor {
// Static field for your Random to create one instance only
private static readonly Random random = new Random();
// Object to lock sync on
private static readonly object syncLock = new object();
// Method to generate random number
public static int RandomNumber(int max)
{
lock(syncLock) {
// returns a random non-negative number less that max
return random.Next(max);
}
}
}
Then use it in your code like this:
int index = RandomAccessor.RandomNumber(listBox1.Items.Count);
Console.Writeline(listBox1.Items[index].toString());
Ask if you have any questions.
Here is a basic example how it will work.
using System;
using System.Windows.Forms;
namespace SimpleFormsApplication
{
public partial class Form1 : Form
{
private readonly Random _random = new Random();
public Form1()
{
InitializeComponent();
}
private void button_random_Click(object sender, EventArgs e)
{
int randomIndex = _random.Next(listBox1.Items.Count);
var randomItem = listBox1.Items[randomIndex];
MessageBox.Show($"Random item at index {randomIndex} is {randomItem}");
}
}
}
Please also have a look in here https://msdn.microsoft.com/en-us/library/system.random(v=vs.100).aspx and exermine the examples there.
I'm creating a card game using C#. I want to assign a value to my card example: Ace(image) = 1; and I want to random it. Here's my code:
private void button1_Click(object sender, EventArgs e)
{
Random cards = new Random();
card = cards.Next(0, 9);
switch (card)
{
case 0:
pictureBox1.Image = Properties.Resources.king_d;
pictureBox2.Image = Properties.Resources.jack_s;
break;
case 1:
pictureBox1.Image = Properties.Resources.ace_c;
pictureBox2.Image = Properties.Resources.ten_d;
break;
}
}
}
new the random out of the method. you can take it from a singleton class (read this) or for simplicity if you are in windows app make it static like this:
static Random cards = new Random();
private void button1_Click(object sender, EventArgs e)
{
card = cards.Next(0, 9);
switch (card)
{
case 0:
pictureBox1.Image = Properties.Resources.king_d;
pictureBox2.Image = Properties.Resources.jack_s;
break;
case 1:
pictureBox1.Image = Properties.Resources.ace_c;
pictureBox2.Image = Properties.Resources.ten_d;
break;
}
}
}
Update
The best way to have a card that contains a value, picture, etc. is to have a new class for that. Since PictureBox already has most properties and behaviors that you need, I recommend using it.
The code has to be something like this:
Public Class MyCard:PictureBox
{
public int GamePoint {get;set;}
}
Then instead of using PictureBox in your code, use this.
To be honest I like to encapsulate the code a bit more so I prefer this:
Public Class MyCard:PictureBox
{
public CardType CardType {set;get;}
public int GamePoint {get{ return (int)this.CardType; }}
public MyCard(CardType _cardType)
{
CardType = _cardType;
}
}
enum CardType
{ Ace=1,
King=2,
...
}
Although I don't see an actual question in your question, I think you want to do this in a simpler way.
Well first of all, don't create a Random every time the method is called, make it a class-level variable and initialize it:
private static Random cards = new Random();
Currently, you're using a switch to decide what to show in the two picture boxes. If the random number is 0, put these two cards, if the number is 1, put those two cards... This means that each number from 0 to 9 corresponds to two Bitmaps.
You can use a dictionary to map 0 to 9 to Tuple<Bitmap, Bitmap>, but I think it's better to use an array.
What you basically need to do is to declare an array that stores those Tuple<Bitmap, Bitmap>. Let's call it CardCombinations. I recommend you to put this array in a utility class called CardUtility or something. Then, you can just do:
card = cards.Next(0, 9);
pictureBox1.Image = CardUtility.CardCombinations[card].Item1;
pictureBox2.Image = CardUtility.CardCombinations[card].Item2;
As you can see, this greatly reduced the code in the button1_Click method. Now we can declare the array that I was talking about.
It's pretty simple:
public static Tuple<Bitmap, Bitmap>[] CardCombinations => new[] {
new Tuple<Bitmap, Bitmap>(Properties.Resources.king_d, Properties.Resources.jack_s),
...
};
"But that's still verbose!" you cried. Protip: you can use the using static directive to shorten the bitmap names to king_d and jack_s!
using static SomeNamespace.Properties.Resources;
I am very new to programming and I am working on a project for school in Visual Studio but I am kinda stuck. I have multiple forms in my solution. One of my forms is an invoice and I am trying to create an invoice number when the checkout button on the previous form is clicked. I have the following code in the textBox field that I want to display my number but the number is not showing in the textBox. Please help!!
private void txtBoxInvoiceNo_TextChanged(object sender, EventArgs e)
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
txtInvoiceNo.Text = invoiceNo.ToString();
}
Probably need to see a bit more code here, but from what you have shown it suggests you are generating the invoice number on the textChanged event of txtBoxInvoiceNo. This event will fire when the text changes within that box. Not on creation of the form.
My suggestion would be to call a function on construction of your form. The code you have written should work, it just needs to be called in the right place.
I'm assuming you're writing winforms but something like:
public MyForm()
{
InitializeComponent();
GenerateInvoiceNumber();
}
private void GenerateInvoiceNumber()
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
txtInvoiceNo.Text = invoiceNo.ToString();
}
You can refactor this later into a static or extension method so it can be used by multiple forms, but the call should be made in the constructor, not in a text box changed event.
If you want to utilize something on multiple forms you better Add a Class and write a method which will return integer. Refer below sample
Public class GenerateNumber
{
public static int GetRandomNo()
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
return invoiceNo;
}
}
Then you can make object of class and call this function on the required form. Refer Below code
GenerateNumber randomNo = new GenerateNo();
txtInvoiceNo.Text = randomNo.GetRandomNo().ToString()
I have a method that updates my observableCollection
public void UpdateBeat()
{
SequenceCollection = new ObservableCollection<Sequence>();
Random random = new Random();
int randomNumber = random.Next(0, 100);
SequenceCollection.Add(new Sequence(1, 2));
}
I have 2 different methods fired from events - the view updates from 1 of the methods but not the other.
//Does not work
private void BsOnUpdateStep(object sender, EventArgs eventArgs)
{
Console.WriteLine("BS Update");
UpdateBeat();
}
//Works
void total_AudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
Console.WriteLine("ASIO Written");
UpdateBeat();
}
I have no idea what the difference could be here. The only thing I can tell is that the 1st method fires more often than the 2nd. I cannot get the 2nd to work at all.
I suppose your calls to UpdateBeat are from different threads but ObservableCollection is not thread safe, that is why -probably- you have such strange results.
You should look for an concurrent ObservableCollection.
One such implementation can be found here: http://www.codeproject.com/Tips/414407/Thread-Safe-Improvement-for-ObservableCollection
Try this:
private SequenceCollection = new ObservableCollection<Sequence>();
Random random = new Random();
public void UpdateBeat()
{
int randomNumber = random.Next(0, 100);
SequenceCollection.Add(new Sequence(1, 2));
}
I put the Random instantiation outside of the method too as you should only instantiate this once to get a proper stream of random numbers.