I am building a minesweeper game in C#, and one of my functions keeps crashing the program. The erorr message is Process is terminated due to StackOverflowException. I tried to find where is the problem in my recursion, but I didn't find it. The problem only happen if Openk is called, so I am pretty sure the problem is there. I tried to find if there is an infinite recursion, but didn't find it. What could be the problem?
public void Openk(int row, int col)
{
if (sqrs[row, col].IsBlank() == true)
{
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
if (IsValid(row - i, col - j))
{
if (sqrs[row - i, col - j].IsMine() == false)
sqrs[row - i, col - j].Open();
Openk(row - i, col - j);
}
}
}
}
}
public bool IsValid(int row, int col)
{
if (row >= n || row <= 0 || col >= n || col <= 0)
return false;
return true;
}
Your problem is that you keep looping and executing Openk on the same middle square each time. Maybe it is because of the unguarded if statement. It goes like this in your code.
You pass the selected coordinates of a square, say [5,5].
Then you loop a row before 5 (4), row 5, and a row after 5 (6).
For each row, your loop a square before the selected column 5 (4), column 5, and and the next column of 5 (6).
In your code, only when you reach the middle square (i = 0, j = 0), you execute the checking of square if it is a mine, and if it is not mine, you pass the selected coordinates after subtracting with zeros (i = 0, j = 0), which effectively loops the same spot again!
.
public void Openk(int row, int col)
{
if (sqrs[row, col].IsBlank() == true)
{
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
// Only execute the following code when checking the middle square, where i = 0, and j = 0.
if (i == 0 && j == 0) // Notice the braces I added, the code has the same effect if you don't type them.
{
// This if statement has not effect.
if (IsValid(row - i, col - j)) // It is like if (true)
{
if (sqrs[row-i, col-j].IsMine() == false)
sqrs[row - i, col - j].Open();
Openk(row - i, col - j); // row - 0 = row, col - 0 = col, your looping infinitely here.
}
}
}
}
}
}
Related
I've written the following method in C# for a small Forms program I'm working on, but whenever I try to run this method the entire program freezes.
There are no errors and I've tried to do for (int n = 0; n<8; n++) instead of while(true), but that didn't seem to change anything...
Any ideas?
Thanks in advance!
public bool legalMove(int y, int x)
{
// Check if the cell is occupied
if (grid[x, y] != 0)
return false;
// Check if there's an opponents circle somewhere around it
for (int i = -1; i<=1; i++)
for (int j = -1; i<=1; j++)
{
if (i == 0 && j == 0)
continue;
int row = x + i;
int col = y + j;
if (row >= 0 && row < 8 && col >= 0 && col < 8 && grid[col,row] == -turn)
{
// Now we know that there's an opponents circle somewhere around this space, we now check if it can be captured
while(true)
{
row += i;
col += j;
if (row < 0 || row > 7 || col < 0 || col > 7 || grid[row, col] == 0)
return false; // Outside of the board or an empty space
else if (grid[row, col] == turn)
return true; // No empty spaces between our cell and another cell of ours
}
}
}
return false; // No cell found around ours
}
Here's the problem: for (int j = -1; i<=1; j++). Should be j<=1 instead of i<=1.
I am trying to calculate the Neighbour near my cells, but the code works for only the middle cells and not for the corner ones, for which I can use many if loops but I wanna know how it works with for and if loops.
I tried creating extra if loops or writing like if row ==0 etc. but everything seems to give me wrong answer. btw bool[,] grid has the values of false and true. and we need to calculate how many trues and false are their in give row/ col.
public static int CountNeighbours(bool[,] grid, int row, int col)
{
int total = 0;
for (int i = row - 1; i < row + 2; i++)
{
for (int j = col - 1; j < col + 2; j++)
{
if (grid[i, j] == grid[row, col])
{
total += 1;
}
}
}
Console.WriteLine("total neighbours for row {0} and column {1}: {2}",row,col,total-1);
return total-1;
}
The result should give perfect answer for corners and rows.
Your problem is that you count the cell itself as its own neighbour and that you don't check the boundaries of your grid.
Change your loop conditions like that:
for (int i = Math.Max(0, row - 1); i < row + 2 && i < grid.GetLength(0); i++)
{
for (int j = Math.Max(0, col - 1); j < col + 2 && j < grid.GetLength(1); j++)
{
if (i == row && j == col) continue; // skip current cell
So with Math.Max() you ensure that you don't use a negative i or j, because that would lead to an IndexOutOfRangeException.
With grid.GetLength() you get the array size in the respective dimension, because using a i or j greater or equal to that length would again raise an IndexOutOfRangeException.
And finally the last line checks that you don't count the cell in question itself.
I want to fill my array with struct in a way that it will look like this
I have this code so far :
`for (int i = 1; i <= n; i++)
{
for (int j = 0; j <=(n - i); j++)
//i should fill m[,] here
for (int j = 1; j <= i; j++)
//i should fill m[,] here
for (int k = 1; k < i; k++)
//i should fill m[,] here
}
for (int i = n - 1; i >= 1; i--)
{
for (int j = 0; j < (n - i); j++)
//i should fill m[,] here
for (int j = 1; j <= i; j++)
//i should fill m[,] here
for (int k = 1; k < i; k++)
//i should fill m[,] here
}`
but I 'm a little bit confused with the index .
how can I adopt this code?
As it's unclear wether the array always has the size 5 I'll assume it has the size n with n being odd and n > 0 (The size is the x and the y size, as I assume that your matrix is quadratic). Then there are several ways to reach the goal your trying to reach, I'll try to present you one I thought of.
First of all we have to think about the array - as it's the easiest way, I'll assume it consists of boolean values (even though you said "I want to fill my array with struct", but as I'm not quite sure what you wanted to say with that and wether you really meant a struct, I'll let this up to you, as this shouldn't be the most difficult part):
var matrix = new bool[n,n];
Then we have to evalueate which fields have to be filled. Therefore we must realize a few things:
The filled fields are always central in their line
The first and last line always have one filled item
The following line always has two more/less filled items, so that the offset is one more than in the previous line
The center line has most items and is the turning point in the amount of filled items
As a first step in developing the algorithm, I'd write a function to fill lines of the array with specific amounts of fields:
private static void FillLine(int line, int count, bool[,] matrix)
{
//Firstly we have to evaluate the offset:
var offset = (matrix.GetLength(0) - count) / 2;
//Then we have to fill the line
for (var x = offset; x < offset + count; x++)
matrix[x, line] = true;
}
Now we simply have to fill the lines for the whole array:
public static void FillDiamond(bool[,] matrix)
{
var count = 1;
for (var line = 0; line < matrix.GetLength(1) / 2; line++)
{
FillLine(line, count, matrix);
count += 2;
}
FillLine(matrix.GetLength(1) / 2, count, matrix);
count = 1;
for (var line = matrix.GetLength(1) - 1; line > matrix.GetLength(1) / 2; line--)
{
FillLine(line, count, matrix);
count += 2;
}
}
Now in a console application you could use this like that:
using System;
namespace SO_c
{
internal static class Program
{
private static void Main()
{
while (true)
{
var n = int.Parse(Console.ReadLine());
if (n < 1 || n % 2 == 0)
continue;
var matrix = new bool[n, n];
FillDiamond(matrix);
for (var y = 0; y < matrix.GetLength(1); y++)
{
for (var x = 0; x < matrix.GetLength(0); x++)
Console.Write(matrix[x, y] ? "█" : " ");
Console.WriteLine();
}
}
}
private static void FillLine(int line, int count, bool[,] matrix)
{
//Firstly we have to evaluate the offset:
var offset = (matrix.GetLength(0) - count) / 2;
//Then we have to fill the line
for (var x = offset; x < offset + count; x++)
matrix[x, line] = true;
}
public static void FillDiamond(bool[,] matrix)
{
var count = 1;
for (var line = 0; line < matrix.GetLength(1) / 2; line++)
{
FillLine(line, count, matrix);
count += 2;
}
FillLine(matrix.GetLength(1) / 2, count, matrix);
count = 1;
for (var line = matrix.GetLength(1) - 1; line > matrix.GetLength(1) / 2; line--)
{
FillLine(line, count, matrix);
count += 2;
}
}
}
}
This can result in output like that:
That's it! Now you should get your diamond for every matrix that fits the rules :)
One way to do it is to calculate the center of the grid and fill in each row, from the center column. In each successive row, we increment the number of blocks we fill in on each side of the center column until we get to the center row, and then we decrement the number of blocks we fill in until we get to the end.
To determine how many blocks to put on each side of the center column for any given row, we can use the row index for the calculation.
Working our way from the top down to the center, the row index represents the number of blocks to add. So, for row index 0, we add 0 blocks on either side of the center column, row index 1 we add 1 block on each side, until we get to the center.
After we get to the center, we want to decrement the number of blocks each time, which can be done by subtracting the row index from the total number of rows.
The code says it better, I think:
private static void Main()
{
while (true)
{
// Get grid size from user and keep it between 1 and the window width
var gridSize = GetIntFromUser("Enter the size of the grid: ");
gridSize = Math.Min(Console.WindowWidth - 1, Math.Max(1, gridSize));
var grid = new bool[gridSize, gridSize];
var center = (gridSize - 1) / 2;
// Populate our grid with a diamond pattern
for (int rowIndex = 0; rowIndex < grid.GetLength(0); rowIndex++)
{
// Determine number of blocks to fill based on current row
var fillAmount = (rowIndex <= center)
? rowIndex : grid.GetUpperBound(0) - rowIndex;
for (int colIndex = 0; colIndex <= fillAmount; colIndex++)
{
grid[rowIndex, center - colIndex] = true;
grid[rowIndex, center + colIndex] = true;
}
}
// Display the final grid to the console
for (int row = 0; row < grid.GetLength(0); row++)
{
for (int col = 0; col < grid.GetLength(1); col++)
{
Console.Write(grid[row, col] ? "█" : " ");
}
Console.WriteLine();
}
}
}
Oh, and this is the helper function I used to get an integer from the user. It's pretty helpful to keep around because you don't have to do any validation in your main code:
private static int GetIntFromUser(string prompt)
{
int value;
// Write the prompt text and get input from user
Console.Write(prompt);
string input = Console.ReadLine();
// If input can't be converted to a double, keep trying
while (!int.TryParse(input, out value))
{
Console.Write($"'{input}' is not a valid number. Please try again: ");
input = Console.ReadLine();
}
// Input was successfully converted!
return value;
}
OUTPUT
I'm taking a class that uses C# and our first assignment is to implement Conway's game of Life. We must do this by reading in a text file formatted something like this:
*
*
***
***
We then have to display the next 10 generations on the screen.
I have the file read into a string array, then I copy it to another array. I then go through it character by character and change the copied array to match what the next generation should be. My problem is that the code I have to count the live neighbors isn't working and I can't figure out why. I displayed the number of live neighbors for each cell on the screen and about half of them are wrong. I know the error is occurring with cells on the edge of the "board," but I can't figure out how to fix it.
Now, I don't want the whole thing written for me, that'd be a bit pointless. I just can't figure out where my logic is off. Any help would be appreciated. Also, I'm aware that my code is pretty poor, overall. This was just the only way I could figure it out. Sorry.
class Program
{
static void Main(string[] args)
{
//gets file name from command arguments
//checks to make sure file exists, exits if file does not exist
if (!File.Exists(Environment.GetCommandLineArgs()[1])) { System.Environment.Exit(1); }
//gets file name from command arguments then reads file into array of strings
string[] gen0 = File.ReadAllLines(Environment.GetCommandLineArgs()[1]);
string[] gen1 = gen0;
char alive = '*';
char dead = ' ';
//displays first generation
foreach (string s in gen0)
{
Console.WriteLine(s);
}
Console.WriteLine("=====================================");
//counts live neighbors of a cell
int count = 0;
for (int i = 0; i < gen0.Length; i++)
{
count = 0;
for (int j = 0; j < gen0[i].Length; j++)
{
//check top left neighbor
if (i > 0 && j > 0 && j < gen0[i-1].Length )
{
if (gen0[i - 1][j - 1] == alive) { count++; }
}
//check above neighbor
if (i > 0 && j < gen0[i-1].Length)
{
if (gen0[i - 1][j] == alive) { count++; }
}
//check top right neighbor
if (i > 0 && j + 1 < gen0[i - 1].Length)
{
if (gen0[i - 1][j + 1] == alive) { count++; }
}
//check left neighbor
if (j > 0)
{
if (gen0[i][j - 1] == alive) { count++; }
}
//check right neighbor
if (j + 1 < gen0[i].Length)
{
if (gen0[i][j + 1] == alive) { count++; }
}
//check bottom left neighbor
if (i + 1 < gen0.Length && j > 0 && j < gen0[i+1].Length)
{
if (gen0[i + 1][j - 1] == alive) { count++; }
}
//check below neighbor
if (i + 1 < gen0.Length && j < gen0[i+1].Length)
{
if (gen0[i + 1][j] == alive) { count++; }
}
//check bottom right neighbor
if (i + 1 < gen0.Length && j + 1 < gen0[i].Length && j + 1 < gen0[i+1].Length)
{
if (gen0[i + 1][j + 1] == alive) { count++; }
}
//Console.WriteLine(count);
//kills cells
if (count < 2 || count > 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, dead.ToString());
}
//births cells
if (count == 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, alive.ToString());
}
}
}
foreach (string s in gen1)
{
Console.WriteLine(s);
}
}
}
Your problem is very simple - you're resetting count in the wrong place. Put it inside the loop and it will (probably) work.
Regarding the rest of the code, if you want to make it significantly easier to follow just give your game area a one-element border.
You'll need to pad the file you read in (blank line above and below, blank characters to the left and right), and alter your loops to:
for (int i = 1; i < gen0.Length - 1; i++)
and
for (int j = 1; j < gen0[i].Length - 1; j++)
but your central count calculation can then be reduced down to a single calculation:
count = (gen0[i - 1][j - 1] == alive) ? 1 : 0 +
(gen0[i - 1][j] == alive) ? 1 : 0 +
... etc ...
which should make for cleaner code and ensure that any other errors you may make are significantly easier to spot.
So the first bug I see is that you don't actually copy the board for the next iteration.
gen1 = gen0;
The code above only assigns the gen1 reference to the same object as gen0. So when you modify gen1, you actually modify gen0 as well... causing inconsistencies in latter iterations. Try this:
gen1 = (string[])gen0.Clone();
Second bug is that int count = 0 should be in the second loop instead of first:
for (int i = 0; i< gen0.Length; i++)
{
// not here
// int count = 0
for (int j = 0; j < gen0[i].Length; j++)
{
// here
int count = 0
...
}
...
}
This way you reset the count for every cell instead of every row.
I want to browse a matrix like these one :
I want browse the first row, get the smallest number, then browse the row matching with the precedent smallest number.
Ex : I browse the A row : I browse the cell A,A , I get 0. I don't keep it (because it's 0) I browse the cell A,D I get 5. I keep it. I browse the cell A,G I get 8 but i don't keep it because it is superior to 5. I browse cell A,K and I get 4 I keep it (< 5).
For the moment it's ok, a simple loop is sufficient to do this. Then I want to browse the row K and if possible don't browse the cell K,A because I already browsed it when I browsed the row A.
You need to loop through an upper/lower half of the matrix? I assume a matrix is an array of int arrays.
var matrix = new int[][]{ ... };
int smallest = 0;
for(int i = 0; i < matrix.Length; i++)
{
for(int j = 0; j < matrix.Length; j++)
{
int number = matrix[i][j];
if (number != 0 && number < smallest)
smallest = number;
}
}
Although, I didn't quite get
then browse the row matching with the precedent smallest number
part.
Here the solution I found :
private static IEnumerable<int> ComputeMatrix(int[,] matrix)
{
// check args
if (matrix.Rank != 2) { throw new ArgumentException("matrix should have a rank of 2"); }
if (matrix.GetUpperBound(0) != matrix.GetUpperBound(1)) { throw new ArgumentException("matrix should have the same size");}
// indice treated
List<int> treatedIndex = new List<int>();
for (int i = 0; i <= matrix.GetUpperBound(0); i++)
{
if (treatedIndex.Count == matrix.GetUpperBound(0))
break;
// distance minimum between 2 points
int distanceMin = Int32.MaxValue;
// next iteration of index
int nextI = i;
// add the index to ignore in the next iteration
int nextJ = -1;
for (int j = 0; j <= matrix.GetUpperBound(1); j++)
{
if (treatedIndex.IndexOf(j) == -1)
{
if (matrix[i, j] != 0 && matrix[i, j] < distanceMin)
{
distanceMin = matrix[i, j];
nextI = j;
nextJ = i;
}
}
}
i = nextI - 1;
treatedIndex.Add(nextJ);
yield return distanceMin;
}
}