Prevent Stack Overflow in a Minesweeper Clone - c#

I'm creating a Minesweeper clone. Thus far, I've gotten to revealing adjacent tiles when the tile clicked has zero adjacent mines, below is my method for revealing mines.
struct data
{
public Button tile;
public bool mine, flag, clicked;
public int adjMines;
}
data[,] dat;
//Defaults
Size gridSize = new Size(16, 16);
Size tileSize = new Size(16, 16);
int mines = 40, flags = 0;
bool valid(int x, int y)
{
return (x >= 0 && y >= 0 && y < gridSize.Height && x < gridSize.Width);
}
void reveal(Button btn)
{
btn.BackColor = Color.DimGray;
start = true;
btn.Enabled = false;
//find button clicked, forget everything you ever learned about efficiency.
for (int i = 0; i < gridSize.Width; i++)
for (int j = 0; j < gridSize.Height; j++)
if (dat[i, j].tile == btn)
{
if (dat[i, j].adjMines == 0)
{
for (int ii = -1; ii <= 1; ii++)
for (int jj = -1; jj <= 1; jj++)
if (valid(i + ii, j + jj))
reveal(dat[i + ii, j + jj].tile);
}
else
btn.Text = dat[i, j].adjMines.ToString();
}
}
I keep getting a StackOverflowException when I run it, which doesn't come as much of a surprise, but I don't know how to fix it without doing away with the struct, which is a requirement. Any ideas?

The problem is that when you "reveal", you reveal all the neighbors. When the neighbor is revealed, it reveals all of its neighbours, including the first one, and now you have an infinite recursion.
The trick is: before you reveal the very first one, make a hash set of "in progress reveals". Before you recurse, add the current button to the "in progress" set. In the reveal method return immediately if the button is already in the in-progress set. You know that all its neighbours are already in the process of being revealed, so there's no work to do.

It would probably help if you didn't recursively try to reveal the same tile:
for (int ii = -1; ii <= 1; ii++)
for (int jj = -1; jj <= 1; jj++)
if (valid(i + ii, j + jj) && !(ii == 0 && jj == 0))
reveal(dat[i + ii, j + jj].tile);
Note the !(ii == 0 && jj == 0) test added - that will stop one of the stack overflow reasons. Apart from that, you also need to mark the node as 'enabled' before going recursive, it'll keep bouncing back and forth otherwise.
It's not a really efficient method you've chosen to implement, but it should work with this fix.

It looks like you are calling reveal from inside reveal. Reveal goes through each tile. You are calling it for all adjacent tiles which then goes through each tile and then calls all adjacent tiles. I would suggest looking through your use of recursion.

Related

max consecutive 1 or 0 that can be obtained by flipping one bit of binary nubmer

given a binary number find the maximum consecutive 1s or 0s that can be obtained by flipping only one bit (either a 1 or a 0)
the code given was
public int getMacCon(string[] A)
{
int n = A.Length;
int result = 0;
for (int i = 0; i < n - 1; i++)
{
if (A[i] == A[i + 1])
result = result + 1;
}
int r = -2;
for (int i = 0; i < n; i++)
{
int count = 0;
if (i > 0)
{
if (A[i - 1] != A[i])
count = count + 1;
else
count = count - 1;
}
if (i < n - 1)
{
if (A[i + 1] != A[i])
count = count + 1;
else
count = count - 1;
}
r = Math.Max(r, count);
}
return result + r;
}
Im finding hard to figure out the logic here. specially the given below part
for (int i = 0; i < n - 1; i++)
{
if (A[i] == A[i + 1])
result = result + 1;
}
I would highly apretiate if any one can explain me the logic in this solution.
Thanks
The bit you've highlighted just counts the number of currently adjacent equal values, i.e. where one value (A[i]) is equal to the next (A[i+1]). It then asks (the second loop), for each value in turn, whether flipping it would increase vs decrease vs not change the number of adjacent equal values; so if a value is currently different from the one before it (A[i-1] != A[i]), a flip would be an increase - else decrease; likewise the one after it. The final result is the pre-existing number of adjacent equal values (result), plus the best delta (r) found in the sweep.
public int getMacCon(string[] A)
{
int n = A.Length;
int result = 0;
// find how many adjacent values are currently in the string
for (int i = 0; i < n - 1; i++)
{
// if same as the next value, that's a hit
if (A[i] == A[i + 1])
result = result + 1;
}
// worst case delta from flipping one value is that me make it
// worse on both sides, so -2
int r = -2;
// now consider each value in turn
for (int i = 0; i < n; i++)
{
int count = 0;
if (i > 0) // test value before, if not the first value
{
if (A[i - 1] != A[i])
count = count + 1; // before is different; flip is incr
else
count = count - 1; // before is same; flip is decr
}
if (i < n - 1) // test value after, if not the last value
{
if (A[i + 1] != A[i])
count = count + 1; // after is different; flip is incr
else
count = count - 1; // after is same; flip is decr
}
// compare that to the tracking counter, and keep the best value
r = Math.Max(r, count);
}
// final result is sum of pre-existing count plus the delta
return result + r;
}
Incidentally, an optimization might be to change the second loop test from i < n to i < n && r != 2 - i.e. stop as soon as the best possible delta is found (making it better on both sides, +2)
Not an direct answer to your question (as Marc Gravell's answer covers it enough) but I just need to add how would I solve this instead:
encode your string with RLE (run length encoding)
so you need array of b,v,n values. Where b>=0 is start position, v={0,1} is bit value and n is the count of consequent occurencies. For example something like:
const int _max=100; // max number of bits
int b[_max],v[_max],n[_max],bvns=0;
The bvns is number of used b,v,n in the arrays. You can also use any dynamic list/template instead.
reset your actual solution
You need bit position to change ix and the count of consequent bits resulting after its flip sz. Set booth to zero.
scan the RLE for items with n=1
if found that means item before and after in the RLE is the same so flipping will join them. So compute the resulting size and if bigger then store as actual solution something like:
for (int i=1;i<bvns-1;i++) // scann RLE except first and last item
if (n[i]==1) // single bit found
{
l=n[i-1]+1+n[i+1]; // resulting size
if (l>=sz) { sz=l; ix=b; } // update solution
}
test if enlarging single sequence is not bigger
simply:
for (int i=0;i<bvns;i++) // scann RLE
if (n[i]>=sz) // result is bigger?
{
sz=l; ix=b-1; // update solution
if (ix<0) ix=b+n[i];
}

Something strange with BoundingBox in XNA

I have strange problem with BoundingBox and things that in make.
For loop wont work correctly and cause problem that dont change variable.
for (int i = 0; i < thing.Length; i++)
{
for (int j = 0; j < thing.Length; j++)
{
if (thing[i].bb.Intersects(thing[j].bb) && i != j)
{
thing[i].spriteSpeed *= -1;
thing[j].spriteSpeed *= -1;
soundEffect.Play(0.2f, -1f, 0f);
}
}
}
But if i change j variable to static number, like zero, code will work fine.
for (int i = 0; i < thing.Length; i++)
{
for (int j = 0; j < thing.Length; j++)
{
if (thing[i].bb.Intersects(thing[0].bb) && i != 0)
{
thing[i].spriteSpeed *= -1;
thing[0].spriteSpeed *= -1;
soundEffect.Play(0.2f, -1f, 0f);
}
}
}
P.S. Thing is a struct that looks like:
struct Thing
{
public Texture2D myTexture;
public Vector2 spritePosition;
public Vector2 spriteSpeed;
public BoundingBox bb;
public Vector3 start, end;
}
The problem is that you are updating both objects both times.
Consider the case where you have two items in the list and their bounding boxen are overlapping. Passing through your loop you get:
i == 0, j == 0: Skip because (i == j)
i == 0, j == 1: Reverse direction of [0] and [1]
i == 1, j == 0: Reverse direction of [1] and [0]
i == 1, j == 1: Skip because (i == j)
Working through the sequence you have reversed the items twice, returning them to their original headings.
To prevent this, and incidentally reduce the number of tests required to process the full list of objects, the j variable should always start 1 higher than i, since all comparisons for i <= j are either already done or are invalid.
Try this code instead:
for (int i = 0; i < thing.Length; i++)
{
for (int j = i + 1; j < thing.Length; j++)
{
if (thing[i].bb.Intersects(thing[j].bb))
{
thing[i].spriteSpeed *= -1;
thing[j].spriteSpeed *= -1;
soundEffect.Play(0.2f, -1f, 0f);
}
}
}
This has the effect of reducing the number of comparisons by about half (actually (n^2-n)/2 if we're being precise) as well as removing all of the double reversals. Each possible combination of items in the list is tested only once.

Checkers Board Assistance

I'm just wondering if there is a simpler way of doing this:
for (int i = 0; i < 1; i++)
{
for (int j = 0; i < 8; j+2)
{
board[ i, j ] = 2;
board[( i + 1 ), j ] = 2;
board[( i + 2 ), j ] = 2;
}
}
What I'm trying to do is place checkers pieces on the actual checkers board. So this is to place the black pieces on the top.
P.S. If you could also give me some help on the bottom set of pieces(white).
Apart from fixing the loop you could otherwise explicitly place the pieces, makes it more readable
int[,] board = new[,]{{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1}};
Modulo will do the trick but i think that TonyS's anwser was my first reaction and I would prefer that insteed the one shown below.
char[,] board = new char[8,8];
private void InitializeBoard()
{
string BoardRepresentation = "";
//for every board cell
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
//initialize board cell
board[i, j] = '0';
if (j <= 2)//black top
{
//Modulo is the trick
if ((j - i) == 0 || ((j - i) % 2) == 0)
{
board[i, j] = 'B';
}
}
else if (j >= 5) //white bot
{
if ((j - i) == 0 || ((j - i) % 2) == 0)
{
board[i, j] = 'W';
}
}
}
}
for (int j = 0; j < 8; j++)
{
for (int i = 0; i < 8; i++)
{
BoardRepresentation += board[i, j] + " ";
}
BoardRepresentation += Environment.NewLine;
}
}
You missed to tell us what exactly is it that you want to achieve. I see several big errors in your code, so I'll assume that you don't have full grasp of how for loop works. I hope it's not too presumptuous that I'm trying to explain it here
For loop
For loop is used to execute same portion of code several times. How many times it will be executed depends on conditions you set. Most often, you will see it in this format:
for (int i = 0; i < n; i++)
{
// Some code
}
This for loop executed code within the brackets ({ and }) n times. This is not only way to define a loop. More thorough definition of a loop is following:
for (<initialization>; <condition>; <afterthought>)
Initialization - You can some variables needed for looping. This is executed once before code within the loop is executed first time. This is optional, and you can leave it empty and use variable declared before in condition.
Condition - This is executed before each execution of code within the loop. If condition expression evaluates to true, loop is executed. Once loop is executed and afterthought is executed, condition is evaluated again and again until it evaluates to false. Condition is also optional. If you leave it out, in C# loop will be executed again until you break the loop in a different way.
Afterthought - This is executed each time code within the loop is finished executing. This is usually used to increment a variable on which loop depends. This is also optional.
Fixing your code
I assume you wanted to mark fields in a 8x8 matrix like in a checkerboard, although this is not stated in your question. You could do it this way:
// For each row in a board (start with 0, go until 7, increase by 1)
for (int i = 0; i < 8; i++)
{
// start coloring the row. Determine which field within the row needs
// to be black. In first row, first field is black, in second second
// field is black, in third row first field is black again and so on.
// So, even rows have black field in first blace, odd rows have black
// on second place.
// We calculate this by determining division remained when dividing by 2.
int firstBlack = i % 2;
// Starting with calculated field, and until last field color fields black.
// Skip every second field. (start with firstBlack, go until 7, increase by 2)
for (int j = firstBlack; j < 8; j += 2)
{
// Color the field black (set to 2)
board[i][j] = 2;
}
}
You can see my comments inline.
Big errors in your code
// This loop would be executed only once. It goes from 0 to less than 1 and is increased
// after first execution. You might as well done it without the loop.
for (int i = 0; i < 1; i++)
{
// This doesn't make sense, because you use i in condition, and initialize
// and update j.
// Also, you are trying to update j, but you are not doing so. You are not
// assigning anything to you. You should do j+=2 to increase by two. Or you
// can do j = j + 2
for (int j = 0; i < 8; j+2)
{
// I didn't really understand what you were trying to achieve here
board[ i, j ] = 2;
board[( i + 1 ), j ] = 2;
board[( i + 2 ), j ] = 2;
}
}

C# check given word to answer word

I'm making a simple spell checker for C#, I want to try and compare a given answer to the randomly chosen word.
I want to compare the first letter to all the letters given in the answer so I can tell if it's correct, it's there was a swap of letters, a deletion or an added letter. I would ultimately like to be able to tell if only one letter was wrong to see a substitution was used.
For example, correct answer hello:
checking first letter ~H
h e l l o
1 0 0 0 0
h h e l l o
1 1 0 0 0 0
e l l o
0 0 0 0
Then go through it for the second letter.
I've absolutely no idea when it comes to C#.
I've tried
int CheckErrors(string Answer, string Guess)
{
if (Answer == Guess)
{
return 1;
}
if (Answer == null || Guess == null)
{
return -1;
}
for (int i = 0; i <= Answer.Length; i++)
{
if (Guess[i] != Answer[i])
{
count++;
//substitution = -4
//deletion = -5
//transposition = -6
//insertion = -7
}
return count;
}
return -9;
}
but I just can't get any further.
UPDATE:
with further research I guess what I was trying to do is something like:
STRING answer = answer_given
STRING input = correct_answer
int check = 0;
FOR (int i = 0; i < input.Length; i++)
{
FOR (int ii = 0; ii < answer.Length; ii++)
{
if (input[i] == answer[i])
{
int check++;
}
}
}
Obviously I know this would keep adding check up, but I can't guess what how else to do it.
ANOTHER UPDATE!
I can use this-
int CheckErrors(string Answer, string Guess)
{
int[,] d = new int[Answer.Length + 1, Guess.Length + 1];
for (int i = 0; i <= Answer.Length; i++)
d[i, 0] = i;
for (int j = 0; j <= Guess.Length; j++)
d[0, j] = j;
for (int j = 1; j <= Guess.Length; j++)
for (int i = 1; i <= Answer.Length; i++)
if (Answer[i - 1] == Guess[j - 1])
d[i, j] = d[i - 1, j - 1]; //no operation
else
d[i, j] = Math.Min(Math.Min(
d[i - 1, j] + 1, //a deletion
d[i, j - 1] + 1), //an insertion
d[i - 1, j - 1] + 1 //a substitution
);
return d[Answer.Length, Guess.Length];
}
But I need a way to do a count for the amount of times each error is used?
Several issues with your function:
You're trying to use a single return value to handle multiple scenarios in which the meaning of that value is not consistent. It's not advisable for a function to be able to return both a state (match, one or both values null, no match, etc) and a counter.
If you're going to use numbers to represent return states, use enum to make it more readable.
Your for loop always terminates after one iteration because it hits the return statement every time. Your return statement needs to be moved after the for loop.
if (Guess[i] != Answer[i]) will throw an exception if i is greater than the length of Guess.
It's not clear what count is supposed to represent, and it's not defined in the function.
You need to better define what exactly is your function supposed to do. If answer is "Hello" and guess is "Hhello", what are you returning? The number of letters that don't match (1)? A code that represents what the error was (Insertion)? Where the error is located? If you need more than one of those things, then you need a separate function.
You may get inspiration by looking at Approximate String Matching in Wikipedia and StackOverflow.
Have you considered trying string.Compare(...)?
http://msdn.microsoft.com/en-us/library/zkcaxw5y.aspx

creating a random (Gantt-ish) chart

I'm trying to write a test for one of my audio programs, and I'm having trouble wrapping my brain around this test setup. First, I've got a table of 60 rows by 10000 columns that needs to be filled. Each cell has a value of ON, OFF, or LEFT (meaning I have the same value as my nearest ON/OFF to my left). I want a random twenty to forty rows to be on at any given time. Each has to be on for a random 6 to 200 cells. The commands to set ON or OFF have to be ordered by row then column. I'm picturing a sparse dictionary coming out with a coordinate key and on/off value. What I don't understand is how store my ON/OFF cells such that I can easily determine if my current row is ON or OFF. Help? Thanks for your time.
After further thought on this, I realized I could do it in two passes. Here's what I ended up with. Feel free to comment on this approach:
var table = new byte[60, 10000];
for(int i = 0; i < 60; i++)
{
// we want at least half the row to be blank
int j = 0;
while(j < 10000)
{
var width = rand.Next(7, 200);
j += width * 2;
var vol = (byte)rand.Next(50, 125);
for(int k = j - width; k < Math.Min(10000, j); k++)
table[i, k] = vol;
}
}
var midiEvents = new List<BASS_MIDI_EVENT>();
midiEvents.Add(new BASS_MIDI_EVENT(BASSMIDIEvent.MIDI_EVENT_PROGRAM, 0, 0, 0, 0));
for(int j = 0; j < 10000; j++)
{
for(int i = 0; i < 60; i++)
{
var cur = (int)table[i, j];
var left = j > 0 ? table[i, j - 1] : 0;
if(cur > 0 && left == 0)
{
cur <<= 8;
cur |= i + 33;
midiEvents.Add(new BASS_MIDI_EVENT(BASSMIDIEvent.MIDI_EVENT_NOTE, cur, 0, j, 0));
}
else if(cur == 0 && left > 0)
{
midiEvents.Add(new BASS_MIDI_EVENT(BASSMIDIEvent.MIDI_EVENT_NOTE, i + 33, 0, j, 0));
}
}
}

Categories