Random values seem to be not really random?
Clash Royale CLAN TAG#URR8PPP
up vote
24
down vote
favorite
Trying to make a simple bacteria-killing game using WinForm in C#, but the bacteria (I am using Panel
for the time being) doesn't seem to move around at random.
Specifically, the problem I am having is, the bacteria tries to move towards the upper left corner and move around there only. Ideally, the bacteria needs to move around the rectangle range evenly, but I am not sure how to achieve that.
Look at the gif file below.
As you can see the red Panel
moves around the upper left corner only. How can I get it to move everywhere evenly and randomly?
Here is my code:
private Panel _pnlBacteria; //Panel representing a piece of bacteria
private Random r = new Random(); //For randomly-generated values
private int _prevX; //Stores the previous X location
private int _prevY; //Stores the previous Y location
public Form1()
InitializeComponent();
_pnlBacteria = new Panel();
/* Get more property assignments to this._pnlBacteria (omitted) */
//Bacteria's start position is also randomly selected
_prevX = r.Next(50, 300);
_prevY = r.Next(50, 500);
//Timer runs every 100 seconds changing the location of the bacteria
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
(y >= 500)
I tried changing the +10 to +12, leaving -10 as it is, but now this only made the bacteria move to the bottom right corner only. I am at a loss.
Can anyone please help?
c# winforms
 |Â
show 5 more comments
up vote
24
down vote
favorite
Trying to make a simple bacteria-killing game using WinForm in C#, but the bacteria (I am using Panel
for the time being) doesn't seem to move around at random.
Specifically, the problem I am having is, the bacteria tries to move towards the upper left corner and move around there only. Ideally, the bacteria needs to move around the rectangle range evenly, but I am not sure how to achieve that.
Look at the gif file below.
As you can see the red Panel
moves around the upper left corner only. How can I get it to move everywhere evenly and randomly?
Here is my code:
private Panel _pnlBacteria; //Panel representing a piece of bacteria
private Random r = new Random(); //For randomly-generated values
private int _prevX; //Stores the previous X location
private int _prevY; //Stores the previous Y location
public Form1()
InitializeComponent();
_pnlBacteria = new Panel();
/* Get more property assignments to this._pnlBacteria (omitted) */
//Bacteria's start position is also randomly selected
_prevX = r.Next(50, 300);
_prevY = r.Next(50, 500);
//Timer runs every 100 seconds changing the location of the bacteria
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
(y >= 500)
I tried changing the +10 to +12, leaving -10 as it is, but now this only made the bacteria move to the bottom right corner only. I am at a loss.
Can anyone please help?
c# winforms
4
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.prevX - 10
etc. Maybe change that10
to a random value as well.
â Sach
Aug 10 at 19:54
1
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
1
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
4
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has takenn
steps will have moved, on average, to a distance proportion tosqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.
â dmckee
Aug 11 at 0:38
 |Â
show 5 more comments
up vote
24
down vote
favorite
up vote
24
down vote
favorite
Trying to make a simple bacteria-killing game using WinForm in C#, but the bacteria (I am using Panel
for the time being) doesn't seem to move around at random.
Specifically, the problem I am having is, the bacteria tries to move towards the upper left corner and move around there only. Ideally, the bacteria needs to move around the rectangle range evenly, but I am not sure how to achieve that.
Look at the gif file below.
As you can see the red Panel
moves around the upper left corner only. How can I get it to move everywhere evenly and randomly?
Here is my code:
private Panel _pnlBacteria; //Panel representing a piece of bacteria
private Random r = new Random(); //For randomly-generated values
private int _prevX; //Stores the previous X location
private int _prevY; //Stores the previous Y location
public Form1()
InitializeComponent();
_pnlBacteria = new Panel();
/* Get more property assignments to this._pnlBacteria (omitted) */
//Bacteria's start position is also randomly selected
_prevX = r.Next(50, 300);
_prevY = r.Next(50, 500);
//Timer runs every 100 seconds changing the location of the bacteria
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
(y >= 500)
I tried changing the +10 to +12, leaving -10 as it is, but now this only made the bacteria move to the bottom right corner only. I am at a loss.
Can anyone please help?
c# winforms
Trying to make a simple bacteria-killing game using WinForm in C#, but the bacteria (I am using Panel
for the time being) doesn't seem to move around at random.
Specifically, the problem I am having is, the bacteria tries to move towards the upper left corner and move around there only. Ideally, the bacteria needs to move around the rectangle range evenly, but I am not sure how to achieve that.
Look at the gif file below.
As you can see the red Panel
moves around the upper left corner only. How can I get it to move everywhere evenly and randomly?
Here is my code:
private Panel _pnlBacteria; //Panel representing a piece of bacteria
private Random r = new Random(); //For randomly-generated values
private int _prevX; //Stores the previous X location
private int _prevY; //Stores the previous Y location
public Form1()
InitializeComponent();
_pnlBacteria = new Panel();
/* Get more property assignments to this._pnlBacteria (omitted) */
//Bacteria's start position is also randomly selected
_prevX = r.Next(50, 300);
_prevY = r.Next(50, 500);
//Timer runs every 100 seconds changing the location of the bacteria
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
(y >= 500)
I tried changing the +10 to +12, leaving -10 as it is, but now this only made the bacteria move to the bottom right corner only. I am at a loss.
Can anyone please help?
c# winforms
c# winforms
edited Aug 10 at 19:52
maccettura
7,67031426
7,67031426
asked Aug 10 at 19:46
Jessica.D
1354
1354
4
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.prevX - 10
etc. Maybe change that10
to a random value as well.
â Sach
Aug 10 at 19:54
1
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
1
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
4
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has takenn
steps will have moved, on average, to a distance proportion tosqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.
â dmckee
Aug 11 at 0:38
 |Â
show 5 more comments
4
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.prevX - 10
etc. Maybe change that10
to a random value as well.
â Sach
Aug 10 at 19:54
1
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
1
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
4
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has takenn
steps will have moved, on average, to a distance proportion tosqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.
â dmckee
Aug 11 at 0:38
4
4
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.
prevX - 10
etc. Maybe change that 10
to a random value as well.â Sach
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.
prevX - 10
etc. Maybe change that 10
to a random value as well.â Sach
Aug 10 at 19:54
1
1
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
1
1
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
4
4
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has taken
n
steps will have moved, on average, to a distance proportion to sqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.â dmckee
Aug 11 at 0:38
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has taken
n
steps will have moved, on average, to a distance proportion to sqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.â dmckee
Aug 11 at 0:38
 |Â
show 5 more comments
5 Answers
5
active
oldest
votes
up vote
13
down vote
accepted
A slightly different way to tackle this might be to choose a random direction and a random distance to travel in that direction. This will allow more movement over the form if we increase the maximum distance the bacteria can travel before changing direction.
We can also "weight" the randomness of the distance so that shorter distances are chosen more often. This will add more variety and randomness to the movement pattern, while still allowing a few long sprints to another location.
Here's an example that you can copy/paste into a new form project implementing this idea. You can play with the settings for maxDistance
(the furthest distance allowed before changing direction) and stepDistance
(the distance travelled on each iteration of the Timer
). A smaller stepDistance
will result in smoother, but slower movement. I've made it pretty small, so I've also decreased the Interval
property of the Timer
to speed it up.
You'll notice I also added a method to validate that the direction is valid, so that the bacteria doesn't run off the screen. I created an enum
to represent directions, which made it easy to check for movement in a particular direction (i.e. if the enum value contains "North" and we're too close to the top, then it's an invalid direction - this covers "North", "NorthWest", and "Northeast" directions).
Edit: I moved the creation of the "weighted distances" list to the constructor, and modified it to select exponentially fewer items rather than linearly fewer items.
Hope it makes sense:
public partial class Form1 : Form
// Program Settings and Controls
private readonly Panel pnlBacteria; // Panel representing a piece of bacteria
private readonly Random random = new Random(); // For randomly-generated values
private readonly Timer tmrMoveBacteria; // Timer used for bacteria movement
private readonly int bacteriaSize = 20; // Stores the size for our bacteria
private const int maxDistance = 50; // The maximum number of moves allowed in the same direction.
private const int stepDistance = 3; // The distance to travel on each iteration of the timer. Smaller number is slower and smoother
private readonly List<int> weightedDistances; // Contains a weighted list of distances (lower numbers appear more often than higher ones)
// Bacteria state variables
private Direction direction; // Stores the current direction bacteria is moving
private int distance; // Stores the distance remaining to travel in current direction
// Represents possible directions for bacteria to move
private enum Direction
North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest
public Form1()
InitializeComponent();
// Initialize our weighted differences array so that 1 is
// chosen most often and maxDistance is chosen the least often
weightedDistances = new List<int>();
for (var i = 0; i < maxDistance; i++)
var weight = maxDistance / (i + 1);
for (var j = 0; j <= weight; j++)
weightedDistances.Add(i + 1);
// Give life to the bacteria
pnlBacteria = new Panel
BackColor = Color.Red,
Width = bacteriaSize,
Height = bacteriaSize,
Left = random.Next(0, ClientRectangle.Width - bacteriaSize),
Top = random.Next(0, ClientRectangle.Height - bacteriaSize)
;
Controls.Add(pnlBacteria);
// Start bacteria movement timer
tmrMoveBacteria = new Timer Interval = 10;
tmrMoveBacteria.Tick += TmrMoveBacteria_Tick;
tmrMoveBacteria.Start();
/// <summary>
/// Sets the direction and distance fields to valid values based on the
/// current bacteria position, direction, and remaining distance
/// </summary>
private void UpdateDirectionAndDistance()
// Get all directions
var validDirections = Enum.GetValues(typeof(Direction)).Cast<Direction>();
// Remove invalid directions (based on the bacteria position)
if (pnlBacteria.Top < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("North"));
if (pnlBacteria.Right > ClientRectangle.Width - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("East"));
if (pnlBacteria.Left < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("West"));
if (pnlBacteria.Bottom > ClientRectangle.Height - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("South"));
// If we're supposed to keep on moving in the same
// direction and it's valid, then we can exit
if (distance > 0 && validDirections.Contains(direction)) return;
// If we got here, then we're setting a new direction and distance
distance = weightedDistances[random.Next(weightedDistances.Count)];
var directions = validDirections.Where(d => d != direction).ToList();
direction = directions[random.Next(directions.Count)];
/// <summary>
/// Executes on each iteration of the timer, and moves the bacteria
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
// Ensure direction and distance are valid
UpdateDirectionAndDistance();
// Move the bacteria
var dirStr = direction.ToString();
if (dirStr.Contains("North")) pnlBacteria.Top -= stepDistance;
if (dirStr.Contains("East")) pnlBacteria.Left += stepDistance;
if (dirStr.Contains("South")) pnlBacteria.Top += stepDistance;
if (dirStr.Contains("West")) pnlBacteria.Left -= stepDistance;
distance--;
add a comment |Â
up vote
22
down vote
If you read the documentation of Random.next(int,int) you'll find the the lower bound is inclusive and the upper bound is exclusive, that's why -10 and +11 works.
add a comment |Â
up vote
1
down vote
The left and right arguments of r.Next
are inclusive and exclusive respectively.
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
So the probability space of this code is a 19x19 square off center of (_prevX,_prevY)
to its upper left. This means displacement is more likely towards the upper left.
If we use 11s on the right, then the probability space is a 20x20 square centered at (_prevX,_prevY)
. The bacteria will move more evenly. Its average displacement within its probability square is zero, so there's not a single favored direction. But the diagonal directions will be favored since diagonal displacement is the greatest on average. This may or may not be important depending on the situation.
If we use radius and direction as explained by Rufus L, then we can generate a more "natural" circular probability space. That's why it's the preferred approach.
add a comment |Â
up vote
0
down vote
The problem is that you are moving the object back and forth because the range is prev -+10;
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
you should add a direction flag for yval and xval, set it with certain probability p(less then 1/2) , when the flag is on go right/up, when its off go left/down ,
if (forwardx)
x = r.Next(_prevX , _prevX + 10);
else
x = r.Next(_prevX - 10, _prevX );
if (forwardy)
y = r.Next(_prevY , _prevY + 10);
else
y = r.Next(_prevY - 10 , _prevY );
forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;
Good luck!
add a comment |Â
up vote
0
down vote
You should use the size of your panel.height - size of your square.height same for length instead of constants this way if the screen size changes your game will still work.
_prevX = r.Next(bateriaSize, this.Width-bacteriaSize); //this.Width Gets you the of form
_prevY = r.Next(bateriaSize, this.Height-bacteriaSize); //This.Height gets you the height of form
add a comment |Â
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
accepted
A slightly different way to tackle this might be to choose a random direction and a random distance to travel in that direction. This will allow more movement over the form if we increase the maximum distance the bacteria can travel before changing direction.
We can also "weight" the randomness of the distance so that shorter distances are chosen more often. This will add more variety and randomness to the movement pattern, while still allowing a few long sprints to another location.
Here's an example that you can copy/paste into a new form project implementing this idea. You can play with the settings for maxDistance
(the furthest distance allowed before changing direction) and stepDistance
(the distance travelled on each iteration of the Timer
). A smaller stepDistance
will result in smoother, but slower movement. I've made it pretty small, so I've also decreased the Interval
property of the Timer
to speed it up.
You'll notice I also added a method to validate that the direction is valid, so that the bacteria doesn't run off the screen. I created an enum
to represent directions, which made it easy to check for movement in a particular direction (i.e. if the enum value contains "North" and we're too close to the top, then it's an invalid direction - this covers "North", "NorthWest", and "Northeast" directions).
Edit: I moved the creation of the "weighted distances" list to the constructor, and modified it to select exponentially fewer items rather than linearly fewer items.
Hope it makes sense:
public partial class Form1 : Form
// Program Settings and Controls
private readonly Panel pnlBacteria; // Panel representing a piece of bacteria
private readonly Random random = new Random(); // For randomly-generated values
private readonly Timer tmrMoveBacteria; // Timer used for bacteria movement
private readonly int bacteriaSize = 20; // Stores the size for our bacteria
private const int maxDistance = 50; // The maximum number of moves allowed in the same direction.
private const int stepDistance = 3; // The distance to travel on each iteration of the timer. Smaller number is slower and smoother
private readonly List<int> weightedDistances; // Contains a weighted list of distances (lower numbers appear more often than higher ones)
// Bacteria state variables
private Direction direction; // Stores the current direction bacteria is moving
private int distance; // Stores the distance remaining to travel in current direction
// Represents possible directions for bacteria to move
private enum Direction
North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest
public Form1()
InitializeComponent();
// Initialize our weighted differences array so that 1 is
// chosen most often and maxDistance is chosen the least often
weightedDistances = new List<int>();
for (var i = 0; i < maxDistance; i++)
var weight = maxDistance / (i + 1);
for (var j = 0; j <= weight; j++)
weightedDistances.Add(i + 1);
// Give life to the bacteria
pnlBacteria = new Panel
BackColor = Color.Red,
Width = bacteriaSize,
Height = bacteriaSize,
Left = random.Next(0, ClientRectangle.Width - bacteriaSize),
Top = random.Next(0, ClientRectangle.Height - bacteriaSize)
;
Controls.Add(pnlBacteria);
// Start bacteria movement timer
tmrMoveBacteria = new Timer Interval = 10;
tmrMoveBacteria.Tick += TmrMoveBacteria_Tick;
tmrMoveBacteria.Start();
/// <summary>
/// Sets the direction and distance fields to valid values based on the
/// current bacteria position, direction, and remaining distance
/// </summary>
private void UpdateDirectionAndDistance()
// Get all directions
var validDirections = Enum.GetValues(typeof(Direction)).Cast<Direction>();
// Remove invalid directions (based on the bacteria position)
if (pnlBacteria.Top < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("North"));
if (pnlBacteria.Right > ClientRectangle.Width - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("East"));
if (pnlBacteria.Left < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("West"));
if (pnlBacteria.Bottom > ClientRectangle.Height - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("South"));
// If we're supposed to keep on moving in the same
// direction and it's valid, then we can exit
if (distance > 0 && validDirections.Contains(direction)) return;
// If we got here, then we're setting a new direction and distance
distance = weightedDistances[random.Next(weightedDistances.Count)];
var directions = validDirections.Where(d => d != direction).ToList();
direction = directions[random.Next(directions.Count)];
/// <summary>
/// Executes on each iteration of the timer, and moves the bacteria
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
// Ensure direction and distance are valid
UpdateDirectionAndDistance();
// Move the bacteria
var dirStr = direction.ToString();
if (dirStr.Contains("North")) pnlBacteria.Top -= stepDistance;
if (dirStr.Contains("East")) pnlBacteria.Left += stepDistance;
if (dirStr.Contains("South")) pnlBacteria.Top += stepDistance;
if (dirStr.Contains("West")) pnlBacteria.Left -= stepDistance;
distance--;
add a comment |Â
up vote
13
down vote
accepted
A slightly different way to tackle this might be to choose a random direction and a random distance to travel in that direction. This will allow more movement over the form if we increase the maximum distance the bacteria can travel before changing direction.
We can also "weight" the randomness of the distance so that shorter distances are chosen more often. This will add more variety and randomness to the movement pattern, while still allowing a few long sprints to another location.
Here's an example that you can copy/paste into a new form project implementing this idea. You can play with the settings for maxDistance
(the furthest distance allowed before changing direction) and stepDistance
(the distance travelled on each iteration of the Timer
). A smaller stepDistance
will result in smoother, but slower movement. I've made it pretty small, so I've also decreased the Interval
property of the Timer
to speed it up.
You'll notice I also added a method to validate that the direction is valid, so that the bacteria doesn't run off the screen. I created an enum
to represent directions, which made it easy to check for movement in a particular direction (i.e. if the enum value contains "North" and we're too close to the top, then it's an invalid direction - this covers "North", "NorthWest", and "Northeast" directions).
Edit: I moved the creation of the "weighted distances" list to the constructor, and modified it to select exponentially fewer items rather than linearly fewer items.
Hope it makes sense:
public partial class Form1 : Form
// Program Settings and Controls
private readonly Panel pnlBacteria; // Panel representing a piece of bacteria
private readonly Random random = new Random(); // For randomly-generated values
private readonly Timer tmrMoveBacteria; // Timer used for bacteria movement
private readonly int bacteriaSize = 20; // Stores the size for our bacteria
private const int maxDistance = 50; // The maximum number of moves allowed in the same direction.
private const int stepDistance = 3; // The distance to travel on each iteration of the timer. Smaller number is slower and smoother
private readonly List<int> weightedDistances; // Contains a weighted list of distances (lower numbers appear more often than higher ones)
// Bacteria state variables
private Direction direction; // Stores the current direction bacteria is moving
private int distance; // Stores the distance remaining to travel in current direction
// Represents possible directions for bacteria to move
private enum Direction
North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest
public Form1()
InitializeComponent();
// Initialize our weighted differences array so that 1 is
// chosen most often and maxDistance is chosen the least often
weightedDistances = new List<int>();
for (var i = 0; i < maxDistance; i++)
var weight = maxDistance / (i + 1);
for (var j = 0; j <= weight; j++)
weightedDistances.Add(i + 1);
// Give life to the bacteria
pnlBacteria = new Panel
BackColor = Color.Red,
Width = bacteriaSize,
Height = bacteriaSize,
Left = random.Next(0, ClientRectangle.Width - bacteriaSize),
Top = random.Next(0, ClientRectangle.Height - bacteriaSize)
;
Controls.Add(pnlBacteria);
// Start bacteria movement timer
tmrMoveBacteria = new Timer Interval = 10;
tmrMoveBacteria.Tick += TmrMoveBacteria_Tick;
tmrMoveBacteria.Start();
/// <summary>
/// Sets the direction and distance fields to valid values based on the
/// current bacteria position, direction, and remaining distance
/// </summary>
private void UpdateDirectionAndDistance()
// Get all directions
var validDirections = Enum.GetValues(typeof(Direction)).Cast<Direction>();
// Remove invalid directions (based on the bacteria position)
if (pnlBacteria.Top < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("North"));
if (pnlBacteria.Right > ClientRectangle.Width - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("East"));
if (pnlBacteria.Left < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("West"));
if (pnlBacteria.Bottom > ClientRectangle.Height - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("South"));
// If we're supposed to keep on moving in the same
// direction and it's valid, then we can exit
if (distance > 0 && validDirections.Contains(direction)) return;
// If we got here, then we're setting a new direction and distance
distance = weightedDistances[random.Next(weightedDistances.Count)];
var directions = validDirections.Where(d => d != direction).ToList();
direction = directions[random.Next(directions.Count)];
/// <summary>
/// Executes on each iteration of the timer, and moves the bacteria
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
// Ensure direction and distance are valid
UpdateDirectionAndDistance();
// Move the bacteria
var dirStr = direction.ToString();
if (dirStr.Contains("North")) pnlBacteria.Top -= stepDistance;
if (dirStr.Contains("East")) pnlBacteria.Left += stepDistance;
if (dirStr.Contains("South")) pnlBacteria.Top += stepDistance;
if (dirStr.Contains("West")) pnlBacteria.Left -= stepDistance;
distance--;
add a comment |Â
up vote
13
down vote
accepted
up vote
13
down vote
accepted
A slightly different way to tackle this might be to choose a random direction and a random distance to travel in that direction. This will allow more movement over the form if we increase the maximum distance the bacteria can travel before changing direction.
We can also "weight" the randomness of the distance so that shorter distances are chosen more often. This will add more variety and randomness to the movement pattern, while still allowing a few long sprints to another location.
Here's an example that you can copy/paste into a new form project implementing this idea. You can play with the settings for maxDistance
(the furthest distance allowed before changing direction) and stepDistance
(the distance travelled on each iteration of the Timer
). A smaller stepDistance
will result in smoother, but slower movement. I've made it pretty small, so I've also decreased the Interval
property of the Timer
to speed it up.
You'll notice I also added a method to validate that the direction is valid, so that the bacteria doesn't run off the screen. I created an enum
to represent directions, which made it easy to check for movement in a particular direction (i.e. if the enum value contains "North" and we're too close to the top, then it's an invalid direction - this covers "North", "NorthWest", and "Northeast" directions).
Edit: I moved the creation of the "weighted distances" list to the constructor, and modified it to select exponentially fewer items rather than linearly fewer items.
Hope it makes sense:
public partial class Form1 : Form
// Program Settings and Controls
private readonly Panel pnlBacteria; // Panel representing a piece of bacteria
private readonly Random random = new Random(); // For randomly-generated values
private readonly Timer tmrMoveBacteria; // Timer used for bacteria movement
private readonly int bacteriaSize = 20; // Stores the size for our bacteria
private const int maxDistance = 50; // The maximum number of moves allowed in the same direction.
private const int stepDistance = 3; // The distance to travel on each iteration of the timer. Smaller number is slower and smoother
private readonly List<int> weightedDistances; // Contains a weighted list of distances (lower numbers appear more often than higher ones)
// Bacteria state variables
private Direction direction; // Stores the current direction bacteria is moving
private int distance; // Stores the distance remaining to travel in current direction
// Represents possible directions for bacteria to move
private enum Direction
North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest
public Form1()
InitializeComponent();
// Initialize our weighted differences array so that 1 is
// chosen most often and maxDistance is chosen the least often
weightedDistances = new List<int>();
for (var i = 0; i < maxDistance; i++)
var weight = maxDistance / (i + 1);
for (var j = 0; j <= weight; j++)
weightedDistances.Add(i + 1);
// Give life to the bacteria
pnlBacteria = new Panel
BackColor = Color.Red,
Width = bacteriaSize,
Height = bacteriaSize,
Left = random.Next(0, ClientRectangle.Width - bacteriaSize),
Top = random.Next(0, ClientRectangle.Height - bacteriaSize)
;
Controls.Add(pnlBacteria);
// Start bacteria movement timer
tmrMoveBacteria = new Timer Interval = 10;
tmrMoveBacteria.Tick += TmrMoveBacteria_Tick;
tmrMoveBacteria.Start();
/// <summary>
/// Sets the direction and distance fields to valid values based on the
/// current bacteria position, direction, and remaining distance
/// </summary>
private void UpdateDirectionAndDistance()
// Get all directions
var validDirections = Enum.GetValues(typeof(Direction)).Cast<Direction>();
// Remove invalid directions (based on the bacteria position)
if (pnlBacteria.Top < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("North"));
if (pnlBacteria.Right > ClientRectangle.Width - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("East"));
if (pnlBacteria.Left < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("West"));
if (pnlBacteria.Bottom > ClientRectangle.Height - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("South"));
// If we're supposed to keep on moving in the same
// direction and it's valid, then we can exit
if (distance > 0 && validDirections.Contains(direction)) return;
// If we got here, then we're setting a new direction and distance
distance = weightedDistances[random.Next(weightedDistances.Count)];
var directions = validDirections.Where(d => d != direction).ToList();
direction = directions[random.Next(directions.Count)];
/// <summary>
/// Executes on each iteration of the timer, and moves the bacteria
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
// Ensure direction and distance are valid
UpdateDirectionAndDistance();
// Move the bacteria
var dirStr = direction.ToString();
if (dirStr.Contains("North")) pnlBacteria.Top -= stepDistance;
if (dirStr.Contains("East")) pnlBacteria.Left += stepDistance;
if (dirStr.Contains("South")) pnlBacteria.Top += stepDistance;
if (dirStr.Contains("West")) pnlBacteria.Left -= stepDistance;
distance--;
A slightly different way to tackle this might be to choose a random direction and a random distance to travel in that direction. This will allow more movement over the form if we increase the maximum distance the bacteria can travel before changing direction.
We can also "weight" the randomness of the distance so that shorter distances are chosen more often. This will add more variety and randomness to the movement pattern, while still allowing a few long sprints to another location.
Here's an example that you can copy/paste into a new form project implementing this idea. You can play with the settings for maxDistance
(the furthest distance allowed before changing direction) and stepDistance
(the distance travelled on each iteration of the Timer
). A smaller stepDistance
will result in smoother, but slower movement. I've made it pretty small, so I've also decreased the Interval
property of the Timer
to speed it up.
You'll notice I also added a method to validate that the direction is valid, so that the bacteria doesn't run off the screen. I created an enum
to represent directions, which made it easy to check for movement in a particular direction (i.e. if the enum value contains "North" and we're too close to the top, then it's an invalid direction - this covers "North", "NorthWest", and "Northeast" directions).
Edit: I moved the creation of the "weighted distances" list to the constructor, and modified it to select exponentially fewer items rather than linearly fewer items.
Hope it makes sense:
public partial class Form1 : Form
// Program Settings and Controls
private readonly Panel pnlBacteria; // Panel representing a piece of bacteria
private readonly Random random = new Random(); // For randomly-generated values
private readonly Timer tmrMoveBacteria; // Timer used for bacteria movement
private readonly int bacteriaSize = 20; // Stores the size for our bacteria
private const int maxDistance = 50; // The maximum number of moves allowed in the same direction.
private const int stepDistance = 3; // The distance to travel on each iteration of the timer. Smaller number is slower and smoother
private readonly List<int> weightedDistances; // Contains a weighted list of distances (lower numbers appear more often than higher ones)
// Bacteria state variables
private Direction direction; // Stores the current direction bacteria is moving
private int distance; // Stores the distance remaining to travel in current direction
// Represents possible directions for bacteria to move
private enum Direction
North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest
public Form1()
InitializeComponent();
// Initialize our weighted differences array so that 1 is
// chosen most often and maxDistance is chosen the least often
weightedDistances = new List<int>();
for (var i = 0; i < maxDistance; i++)
var weight = maxDistance / (i + 1);
for (var j = 0; j <= weight; j++)
weightedDistances.Add(i + 1);
// Give life to the bacteria
pnlBacteria = new Panel
BackColor = Color.Red,
Width = bacteriaSize,
Height = bacteriaSize,
Left = random.Next(0, ClientRectangle.Width - bacteriaSize),
Top = random.Next(0, ClientRectangle.Height - bacteriaSize)
;
Controls.Add(pnlBacteria);
// Start bacteria movement timer
tmrMoveBacteria = new Timer Interval = 10;
tmrMoveBacteria.Tick += TmrMoveBacteria_Tick;
tmrMoveBacteria.Start();
/// <summary>
/// Sets the direction and distance fields to valid values based on the
/// current bacteria position, direction, and remaining distance
/// </summary>
private void UpdateDirectionAndDistance()
// Get all directions
var validDirections = Enum.GetValues(typeof(Direction)).Cast<Direction>();
// Remove invalid directions (based on the bacteria position)
if (pnlBacteria.Top < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("North"));
if (pnlBacteria.Right > ClientRectangle.Width - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("East"));
if (pnlBacteria.Left < bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("West"));
if (pnlBacteria.Bottom > ClientRectangle.Height - bacteriaSize) validDirections =
validDirections.Where(dir => !dir.ToString().Contains("South"));
// If we're supposed to keep on moving in the same
// direction and it's valid, then we can exit
if (distance > 0 && validDirections.Contains(direction)) return;
// If we got here, then we're setting a new direction and distance
distance = weightedDistances[random.Next(weightedDistances.Count)];
var directions = validDirections.Where(d => d != direction).ToList();
direction = directions[random.Next(directions.Count)];
/// <summary>
/// Executes on each iteration of the timer, and moves the bacteria
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TmrMoveBacteria_Tick(object sender, EventArgs e)
// Ensure direction and distance are valid
UpdateDirectionAndDistance();
// Move the bacteria
var dirStr = direction.ToString();
if (dirStr.Contains("North")) pnlBacteria.Top -= stepDistance;
if (dirStr.Contains("East")) pnlBacteria.Left += stepDistance;
if (dirStr.Contains("South")) pnlBacteria.Top += stepDistance;
if (dirStr.Contains("West")) pnlBacteria.Left -= stepDistance;
distance--;
edited Aug 10 at 23:02
answered Aug 10 at 22:23
Rufus L
15.2k21528
15.2k21528
add a comment |Â
add a comment |Â
up vote
22
down vote
If you read the documentation of Random.next(int,int) you'll find the the lower bound is inclusive and the upper bound is exclusive, that's why -10 and +11 works.
add a comment |Â
up vote
22
down vote
If you read the documentation of Random.next(int,int) you'll find the the lower bound is inclusive and the upper bound is exclusive, that's why -10 and +11 works.
add a comment |Â
up vote
22
down vote
up vote
22
down vote
If you read the documentation of Random.next(int,int) you'll find the the lower bound is inclusive and the upper bound is exclusive, that's why -10 and +11 works.
If you read the documentation of Random.next(int,int) you'll find the the lower bound is inclusive and the upper bound is exclusive, that's why -10 and +11 works.
answered Aug 10 at 20:22
Turo
1,9421512
1,9421512
add a comment |Â
add a comment |Â
up vote
1
down vote
The left and right arguments of r.Next
are inclusive and exclusive respectively.
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
So the probability space of this code is a 19x19 square off center of (_prevX,_prevY)
to its upper left. This means displacement is more likely towards the upper left.
If we use 11s on the right, then the probability space is a 20x20 square centered at (_prevX,_prevY)
. The bacteria will move more evenly. Its average displacement within its probability square is zero, so there's not a single favored direction. But the diagonal directions will be favored since diagonal displacement is the greatest on average. This may or may not be important depending on the situation.
If we use radius and direction as explained by Rufus L, then we can generate a more "natural" circular probability space. That's why it's the preferred approach.
add a comment |Â
up vote
1
down vote
The left and right arguments of r.Next
are inclusive and exclusive respectively.
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
So the probability space of this code is a 19x19 square off center of (_prevX,_prevY)
to its upper left. This means displacement is more likely towards the upper left.
If we use 11s on the right, then the probability space is a 20x20 square centered at (_prevX,_prevY)
. The bacteria will move more evenly. Its average displacement within its probability square is zero, so there's not a single favored direction. But the diagonal directions will be favored since diagonal displacement is the greatest on average. This may or may not be important depending on the situation.
If we use radius and direction as explained by Rufus L, then we can generate a more "natural" circular probability space. That's why it's the preferred approach.
add a comment |Â
up vote
1
down vote
up vote
1
down vote
The left and right arguments of r.Next
are inclusive and exclusive respectively.
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
So the probability space of this code is a 19x19 square off center of (_prevX,_prevY)
to its upper left. This means displacement is more likely towards the upper left.
If we use 11s on the right, then the probability space is a 20x20 square centered at (_prevX,_prevY)
. The bacteria will move more evenly. Its average displacement within its probability square is zero, so there's not a single favored direction. But the diagonal directions will be favored since diagonal displacement is the greatest on average. This may or may not be important depending on the situation.
If we use radius and direction as explained by Rufus L, then we can generate a more "natural" circular probability space. That's why it's the preferred approach.
The left and right arguments of r.Next
are inclusive and exclusive respectively.
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
So the probability space of this code is a 19x19 square off center of (_prevX,_prevY)
to its upper left. This means displacement is more likely towards the upper left.
If we use 11s on the right, then the probability space is a 20x20 square centered at (_prevX,_prevY)
. The bacteria will move more evenly. Its average displacement within its probability square is zero, so there's not a single favored direction. But the diagonal directions will be favored since diagonal displacement is the greatest on average. This may or may not be important depending on the situation.
If we use radius and direction as explained by Rufus L, then we can generate a more "natural" circular probability space. That's why it's the preferred approach.
edited Aug 19 at 18:12
answered Aug 16 at 18:41
sfmiller940
113
113
add a comment |Â
add a comment |Â
up vote
0
down vote
The problem is that you are moving the object back and forth because the range is prev -+10;
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
you should add a direction flag for yval and xval, set it with certain probability p(less then 1/2) , when the flag is on go right/up, when its off go left/down ,
if (forwardx)
x = r.Next(_prevX , _prevX + 10);
else
x = r.Next(_prevX - 10, _prevX );
if (forwardy)
y = r.Next(_prevY , _prevY + 10);
else
y = r.Next(_prevY - 10 , _prevY );
forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;
Good luck!
add a comment |Â
up vote
0
down vote
The problem is that you are moving the object back and forth because the range is prev -+10;
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
you should add a direction flag for yval and xval, set it with certain probability p(less then 1/2) , when the flag is on go right/up, when its off go left/down ,
if (forwardx)
x = r.Next(_prevX , _prevX + 10);
else
x = r.Next(_prevX - 10, _prevX );
if (forwardy)
y = r.Next(_prevY , _prevY + 10);
else
y = r.Next(_prevY - 10 , _prevY );
forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;
Good luck!
add a comment |Â
up vote
0
down vote
up vote
0
down vote
The problem is that you are moving the object back and forth because the range is prev -+10;
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
you should add a direction flag for yval and xval, set it with certain probability p(less then 1/2) , when the flag is on go right/up, when its off go left/down ,
if (forwardx)
x = r.Next(_prevX , _prevX + 10);
else
x = r.Next(_prevX - 10, _prevX );
if (forwardy)
y = r.Next(_prevY , _prevY + 10);
else
y = r.Next(_prevY - 10 , _prevY );
forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;
Good luck!
The problem is that you are moving the object back and forth because the range is prev -+10;
x = r.Next(_prevX - 10, _prevX + 10);
y = r.Next(_prevY - 10, _prevY + 10);
you should add a direction flag for yval and xval, set it with certain probability p(less then 1/2) , when the flag is on go right/up, when its off go left/down ,
if (forwardx)
x = r.Next(_prevX , _prevX + 10);
else
x = r.Next(_prevX - 10, _prevX );
if (forwardy)
y = r.Next(_prevY , _prevY + 10);
else
y = r.Next(_prevY - 10 , _prevY );
forwardx = r.Next(10) == 1; //p = 0.1
forwardy = r.Next(10) == 1;
Good luck!
edited Aug 10 at 21:33
answered Aug 10 at 20:02
Dr.Haimovitz
1,087312
1,087312
add a comment |Â
add a comment |Â
up vote
0
down vote
You should use the size of your panel.height - size of your square.height same for length instead of constants this way if the screen size changes your game will still work.
_prevX = r.Next(bateriaSize, this.Width-bacteriaSize); //this.Width Gets you the of form
_prevY = r.Next(bateriaSize, this.Height-bacteriaSize); //This.Height gets you the height of form
add a comment |Â
up vote
0
down vote
You should use the size of your panel.height - size of your square.height same for length instead of constants this way if the screen size changes your game will still work.
_prevX = r.Next(bateriaSize, this.Width-bacteriaSize); //this.Width Gets you the of form
_prevY = r.Next(bateriaSize, this.Height-bacteriaSize); //This.Height gets you the height of form
add a comment |Â
up vote
0
down vote
up vote
0
down vote
You should use the size of your panel.height - size of your square.height same for length instead of constants this way if the screen size changes your game will still work.
_prevX = r.Next(bateriaSize, this.Width-bacteriaSize); //this.Width Gets you the of form
_prevY = r.Next(bateriaSize, this.Height-bacteriaSize); //This.Height gets you the height of form
You should use the size of your panel.height - size of your square.height same for length instead of constants this way if the screen size changes your game will still work.
_prevX = r.Next(bateriaSize, this.Width-bacteriaSize); //this.Width Gets you the of form
_prevY = r.Next(bateriaSize, this.Height-bacteriaSize); //This.Height gets you the height of form
edited Aug 11 at 18:59
Peter O.
20.1k95868
20.1k95868
answered Aug 10 at 19:56
Junior Cortenbach
355
355
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51793210%2frandom-values-seem-to-be-not-really-random%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
4
Random.Next(a,b) means a<=x<b. So I think b should be 11 here so the random to be balanced. Have you tried this?
â Sergey Prosin
Aug 10 at 19:54
I believe one problem is that you're moving it by a fixed amount relative to the previous coordinate.
prevX - 10
etc. Maybe change that10
to a random value as well.â Sach
Aug 10 at 19:54
1
It seems to be moving around in a proper manner to me. The reason it is staying in one general location is because that's where it starts and it is not likely to move too far away. This is because the randomness should average out over a long period of time to about zero movement from the original location. (Not an expert on this kind of stuff, someone correct me if I'm wrong)
â Blake Thingstad
Aug 10 at 19:55
1
Hmm please check my answer. It is not going to behave as you expect with a max 10 range with your code as is.
â Ben Hall
Aug 10 at 19:59
4
@BlakeThingstad You're more or less wrong. Einstein (yeah, Albert) showed that an the isotropic random walker on an unbounded field which has taken
n
steps will have moved, on average, to a distance proportion tosqrt(n)
away from it's starting place. Now, different walkers will go in different directions so the net motion of a statistical population is zero, but the expectation for a single walker is to travel. Bounded fields, as here, make the problem much more complicated, of course. Search terms: drunkard's walk and random walk.â dmckee
Aug 11 at 0:38