37 posts

## Randomnesessesses

Back to Forum: Coffeehouse
• Behold! This 'ere Sea-Sharp be not workingzor properleeeeey:

```            // randomly pick buttons that are mines
for(int i=0; i<Mines; i++) {

Random R = new Random( DateTime.Now.Second );
double rX = R.NextDouble();
double rY = R.NextDouble();

// Convert X and Y to integers between 0 and Width|Height
int X = Convert.ToInt32(rX * (Width  - 1));
int Y = Convert.ToInt32(rY * (Height - 1));

//                if(Boxes[X, Y].isMine == true) {
//                    i--;
//                } else {
Boxes[X, Y].isMine = true;
//                }

}
```

(Boxes is a 2-dimesnional array of a class with boolean property "isMine"), Width = 24, Height = 36, Mines = 20

When I uncomment the commmented bit, it sometimes gets stuck in an infinite loop, when I set "Mines" to something small, like 8, the function takes about 15 seconds to complete (rather than the 15 miliseconds it takes when I leave the comments in).

any ideas?

• So you're picking cells at random... and if they're already a mine, you pick another cell at random?

Hmm...

Try this method instead.  Number the cells from 1 to 20.

for (i = 1 to # of mines)
{
Pick a random number n from 1 to # of cells
Count *unmined* cells until you reach n (when you reach the last cell, wrap)
Put a mine on that cell
}

That at least has an upper bound on the time it takes to complete

• I guess I would need to know what you are trying to do in the above example before commenting further.  Are you trying to populate an array with randomly placed mines, or trying to find them? Or something completely different?

• W3bbo wrote:
 Random R = new Random( DateTime.Now.Second );

The root of your problem, though, is this line.  When you create two Random objects with the same seed, they will give you the same random sequence.

Create the Random object prior to the for loop, and reuse it.

EDIT: As an experiment, print out the value of X and Y from your code.  You should see something like:

X = 17, Y = 5
X = 17, Y = 5
...
... one second later...
X = 3, Y = 12
X = 3, Y = 12
...
... one second later...
(etc.)

• Maurits wrote:
W3bbo wrote:
 Random R = new Random( DateTime.Now.Second );

The root of your problem, though, is this line.  When you create two Random objects with the same seed, they will give you the same random sequence.

Create the Random object prior to the for loop, and reuse it.

EDIT: As an experiment, print out the value of X and Y from your code.  You should see something like:

X = 17, Y = 5
X = 17, Y = 5
...
... one second later...
X = 3, Y = 12
X = 3, Y = 12
...
... one second later...
(etc.)

Yep, that was the cause of the problem, having changed it to "DateTime.Now.Milisecond" it works faster.

But now I've got another problem, I'm adding a grid of System.Windows.Forms.Button to a Panel, but even with SuspendLayout and ResumeLayout, I can still see the redraw, and it takes about 1.5 seconds (and raises CPU% to 100%, although I can't argue the nice "slide-in, slide-out" effect caused by the repainting looks bad.

Is there any way to add a hundred or so buttons to a panel without it doing it all curtains-y?

The same happens when I call Panel.Controls.Clear(), it "curtains" it out.

• Here's a shot of it so far. I inserted the Suspend and ResumeLayout calls just before and after all control-related calls.

• W3bbo wrote:

Yep, that was the cause of the problem, having changed it to "DateTime.Now.Milisecond" it works faster.

... eh...

You really only need one Random object per program.  This is a rare exception to the principle that objects should be created in the smallest possible scope.

(Also, it doesn't really matter for this project, but things like DateTime.Now.Second and DateTime.Now.Millisecond are lousy random seeds if you care about randomness.  There's only sixty-ish possibilities for .Second, for example.  So if you play the game sixty-one times, you'll see the same starting position twice.)

• Maurits wrote:
You really only need one Random object per program.  This is a rare exception to the principle that objects should be created in the smallest possible scope.

Manip suggested I do that, blame him.

Maurits wrote:
(Also, it doesn't really matter for this project, but things like DateTime.Now.Second and DateTime.Now.Millisecond are lousy random seeds if you care about randomness.  There's only sixty-ish possibilities for .Second, for example.  So if you play the game sixty-one times, you'll see the same starting position twice.)

I tried using Convert.ToIn32(.Ticks) but I got overflow/too-large exceptions.

• put this line outside of the for loop

Random R = new Random( DateTime.Now.Second );

You're re-seeding R with the same value -- even with milisecond, it'll still be the same value if your computer is fast enough.

• W3bbo wrote:

I tried using Convert.ToIn32(.Ticks) but I got overflow/too-large exceptions.
Seeding needs to be done only once every time you run the program. In that case, it doesn't matter the second or milisecond value you use (assuming you can't start your app again a second later)

• W3bbo wrote:

I tried using Convert.ToIn32(.Ticks) but I got overflow/too-large exceptions.

The beauty of persisting a single Random object is that you can just call the argumentless constructor and you don't have to worry about the time-dependent issue you ran into.

That said, MSDN lists a way to force .Ticks into an Int32 in the Random(Int32) manpage...

Random rdm1 = new Random(unchecked((int)DateTime.Now.Ticks));

• Oh, and one more thing... Random can return random integers between 0 and a given upper bound directly, which could simplify your code.

See Random.Next(Int32)

• Nevermind, I just found the second override of the Next() method, I'm an eejit

But I've still got performance problems with the redrawing.

• Wouldn't it be faster and more efficient to ownerdraw the contents into the panel instead of using a trillion of buttons? I'm sure GDI loathes you for that one.

• Tom Servo wrote:
Wouldn't it be faster and more efficient to ownerdraw the contents into the panel instead of using a trillion of buttons? I'm sure GDI loathes you for that one.

...I'm not sure if I understand you.

• What Tom said There are *far* too many buttons on that Form. Draw it yourself (on a single control) and maybe you can even have some nice lil animations. It'll be much faster.

• Rossj wrote:
What Tom said There are *far* too many buttons on that Form. Draw it yourself (on a single control) and maybe you can even have some nice lil animations. It'll be much faster.

...but then how would I get the "button press" effect?

...actually, how would I "draw" a button anyway? Do I need to type out "DrawLine(co-ords)" over and over again?

• Ahem.