O'Reilly Forums: Lab#1 Trying To Understand Issue With Random() Initilization - O'Reilly Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Lab#1 Trying To Understand Issue With Random() Initilization

#1 User is offline   ThagaSa 

  • New Member
  • Pip
  • Group: Members
  • Posts: 1
  • Joined: 20-September 12

Posted 20 September 2012 - 10:37 AM

My first time around I initialized the Randomizer Random() object within the Greyhound class instead of in Form1.cs and pointing each Randomizer reference to it.

This broke the program in a very weird way and I'm trying to understand why.

With Randomizer being initialized in each Greyhound object I was getting the following results.

The first dog would always win and the remaining 3 dogs would ALWAYS end up with the same position (somewhere behind the first dog).

Here is the weird thing - if I added a breakpoint early on, stepped through everything while watching the dogs' location, everything would run just fine. But if I moved the breakpoint to the end - where it stops the timer after one dog wins - then I would get the weird result mentioned above - first dog wins, other 3 dogs' locations identical.

Why is the program behaving differently when stepping through all the steps vs running normally or stopping it right before it kills the timer?

Here are the classes set up in this wrong way (please ignore the inefficient code, will get it cleaned up).

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Lab_DayAtTheRaces
{
    public partial class Form1 : Form
    {
        Greyhound[] dogs = new Greyhound[4];



        
        public Form1()
        {
            InitializeComponent();

            dogs[0] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog1};
            dogs[1] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog2};
            dogs[2] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog3};
            dogs[3] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog4};
        }


        private void button2_Click(object sender, EventArgs e)
        {
            RaceTimer.Start();
        }

        private void RaceTimer_Tick(object sender, EventArgs e)
        {
            
            for (int x = 0; x < 4; x++)
            {
                if (dogs[x].Run())
                {
                    RaceTimer.Stop();
                    MessageBox.Show("Dog " + x + " has won!");

                    for (int y = 0; y < 4; y++)
                    {
                        dogs[y].TakeStartingPosition();
                    }
                    break;
                }

            }

        }


    }
}


Greyhound.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;


namespace Lab_DayAtTheRaces
{
    public class Greyhound
    {
        public int StartingPosition;
        public int RacetrackLength;
        public PictureBox MyPictureBox = null;
        public int Location;
        public Random Randomizer;

        
        public bool Run()
        {
            // move forward either 1,2,3, or 4 spaces at random
            // Update the position of my PictureBox on the form
            // Return true if I won the race

            Randomizer = new Random();  /// <----------- INITIALIZED HERE INSTEAD OF FORM1.CS--------------------
            int distance = Randomizer.Next(1,300);

            Point p = MyPictureBox.Location;
            p.X += distance;
            MyPictureBox.Location = p;
            

            if (p.X >= RacetrackLength)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public void TakeStartingPosition()
        {
            Point p = MyPictureBox.Location;
            p.X = StartingPosition;
            MyPictureBox.Location = p;
        }

    }
}

0

#2 User is offline   Raymii 

  • Active Member
  • PipPip
  • Group: Members
  • Posts: 11
  • Joined: 11-October 11

Posted 20 September 2012 - 11:33 AM

This is a real classic, I think this happened to all of us. Key to understanding what happens is to know how the random class works. A random object cannot create real random numbers, it just uses the system clock and maybe some other internal variables as a basis for the numbers it computes. So if you create several random objects at the same time, they all use the same basis for their "random" numbers. That's why you tend to get identical results. This also explains why your program works if you insert breakpoints. Due to the time delay caused by the breakpoints, now the different instances of random are indeed based on different values.

You could solve this by introducing a dealy between the creation of the different Greyhound objects, thus basing their random objects on different values. However, the more elegant solution is to only have one random object and passing the reference to it to the different Greyhound objects.

This post has been edited by Raymii: 20 September 2012 - 11:34 AM

0

#3 User is offline   Diaz 

  • New Member
  • Pip
  • Group: Members
  • Posts: 4
  • Joined: 30-September 12

Posted 04 October 2012 - 10:22 PM

Hi!

Did you get it worked with Timer object?
I am trying to fix my timer with my own code. But still no luck. I even tried your code (I had no issues with Randomizer-decalred in form.cs)
So for timer, still not working... I am having a new issue as well. When I start the race by clicking RACE button, all dog pictures are clustered in to
top left hand corner. Plus timer doesn't seem to work, as I dont see any dog moving in the track. At the end it gives the random winner though.

Can someone please tell what I may have done wrong....I have a feeling startingPosition=19 has something to do with this new cornering....
But I didn't have this issue, before I embarked in Timer_Tick event... Earlier I was pointing at RACE Button click event from Timer_Tick.

Regardless of a Timer or a DoEvents(), Thread class - my programme still teleports/flashes dogs.

When I stepped through the code, I can see during first loop, dogs move respective Distance (X forward). But after that they just dont move at all. At least I can't see them moving. I am just confused and desperate to know what's happening here.. Coz at the end, all 4 dogs flashes and show up in finishing line to claim a Winner too..
Please help me understand the situation..

Form.cs

//Dog instances
            Dogs[0] = new Dog() {startingPosition = 19, raceTrackLength = picRaceTrack .Width - 100, myPictureBox = picDog1, Randomizer = this.Randomizer};
            Dogs[1] = new Dog() { startingPosition = 19, raceTrackLength = picRaceTrack.Width - 100, myPictureBox = picDog2, Randomizer = this.Randomizer};
            Dogs[2] = new Dog() { startingPosition = 19, raceTrackLength = picRaceTrack.Width - 100, myPictureBox = picDog3, Randomizer = this.Randomizer};
            Dogs[3] = new Dog() { startingPosition = 19, raceTrackLength = picRaceTrack.Width - 100, myPictureBox = picDog4, Randomizer = this.Randomizer};


private void btnRace_Click(object sender, EventArgs e)
        {   
            btnBet.Enabled = false ;
            timer1.Enabled = true;
            timer1.Start();           

            //To balance out each Bettor's cash.
            for (j = 0; j < Guys.Length; j++)
            {
                Guys[j].Collect(Winner);
                Guys[j].UpdateLabel();
            }      

            //set dogs back to starting line
            for (k = 0; k < Dogs.Length; k++)
            {
                Dogs[k].takeStartingPosition();
            }

            btnBet .Enabled =true ;
        }



private void timer1_Tick(object sender, EventArgs e)
        {
            while (!isWon)
            {
                for (i = 0; i < Dogs.Length; i++)
                {
                    //Dogs [i]. Distance = Randomizer.Next(1, 4);
                    if (Dogs[i].Run())
                    {
                        timer1.Enabled = false;
                        timer1.Stop();
                        
                        MessageBox.Show("We have a winner! Dog #" + i);
                        //i is meant for the index of the dog. Not dog number
                        //to avoid returning a 0 as dog number... 
                        Winner = i + 1;
                        isWon = true;
                        break;
                    }
                }

            }
        }



Dog.cs

public bool Run()
        {               

            Distance = Randomizer.Next(1, 4);
            p = myPictureBox.Location;
            p.X += Distance ;
            myPictureBox.Location = p;

            //return true if I won the game
            if (p.X >= raceTrackLength)
            {
                return true ;
            }
            else
            {
                return false ;
            }
        }


View PostThagaSa, on 20 September 2012 - 10:37 AM, said:

My first time around I initialized the Randomizer Random() object within the Greyhound class instead of in Form1.cs and pointing each Randomizer reference to it.

This broke the program in a very weird way and I'm trying to understand why.

With Randomizer being initialized in each Greyhound object I was getting the following results.

The first dog would always win and the remaining 3 dogs would ALWAYS end up with the same position (somewhere behind the first dog).

Here is the weird thing - if I added a breakpoint early on, stepped through everything while watching the dogs' location, everything would run just fine. But if I moved the breakpoint to the end - where it stops the timer after one dog wins - then I would get the weird result mentioned above - first dog wins, other 3 dogs' locations identical.

Why is the program behaving differently when stepping through all the steps vs running normally or stopping it right before it kills the timer?

Here are the classes set up in this wrong way (please ignore the inefficient code, will get it cleaned up).

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Lab_DayAtTheRaces
{
    public partial class Form1 : Form
    {
        Greyhound[] dogs = new Greyhound[4];



        
        public Form1()
        {
            InitializeComponent();

            dogs[0] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog1};
            dogs[1] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog2};
            dogs[2] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog3};
            dogs[3] = new Greyhound() { StartingPosition = 23, RacetrackLength = 482, MyPictureBox = dog4};
        }


        private void button2_Click(object sender, EventArgs e)
        {
            RaceTimer.Start();
        }

        private void RaceTimer_Tick(object sender, EventArgs e)
        {
            
            for (int x = 0; x < 4; x++)
            {
                if (dogs[x].Run())
                {
                    RaceTimer.Stop();
                    MessageBox.Show("Dog " + x + " has won!");

                    for (int y = 0; y < 4; y++)
                    {
                        dogs[y].TakeStartingPosition();
                    }
                    break;
                }

            }

        }


    }
}


Greyhound.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;


namespace Lab_DayAtTheRaces
{
    public class Greyhound
    {
        public int StartingPosition;
        public int RacetrackLength;
        public PictureBox MyPictureBox = null;
        public int Location;
        public Random Randomizer;

        
        public bool Run()
        {
            // move forward either 1,2,3, or 4 spaces at random
            // Update the position of my PictureBox on the form
            // Return true if I won the race

            Randomizer = new Random();  /// <----------- INITIALIZED HERE INSTEAD OF FORM1.CS--------------------
            int distance = Randomizer.Next(1,300);

            Point p = MyPictureBox.Location;
            p.X += distance;
            MyPictureBox.Location = p;
            

            if (p.X >= RacetrackLength)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public void TakeStartingPosition()
        {
            Point p = MyPictureBox.Location;
            p.X = StartingPosition;
            MyPictureBox.Location = p;
        }

    }
}


This post has been edited by Diaz: 04 October 2012 - 11:58 PM

0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users