I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?
Thanks!
private int GameLogicChecker(int x, int y)
{
int count = 0;
if (_grid[x, y] != -1)
{
if (x + 1 < SizeX)
{ //Right
if (_grid[x + 1, y] == -1)
count++;
}
if (x - 1 > 0)
{ //Left
if (_grid[x - 1, y] == -1)
count++;
}
if (y + 1 < SizeY)
{ //Upper
if (_grid[x, y + 1] == -1)
count++;
}
if (y - 1 > 0)
{ //Lower
if (_grid[x, y - 1] == -1)
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY)
{ //Right-Upper
if (_grid[x + 1, y + 1] == -1)
count++;
}
if (x + 1 < SizeX && y - 1 > 0)
{ //Right-Lower
if (_grid[x + 1, y - 1] == -1)
count++;
}
if (x - 1 > 0 && y + 1 < SizeY)
{ //Left-Upper
if (_grid[x - 1, y + 1] == -1)
count++;
}
if (x - 1 > 0 && y - 1 > 0)
{ //Left-Lower
if (_grid[x - 1, y - 1] == -1)
count++;
}
}
return count;
}
void OpenEmptySpace(int x, int y)
{
for (var k = -1; k <= 1; k++)
{
for (var l = -1; l <= 1; l++)
{
if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
{
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
}
}
}
private bool CheckBounds(int x, int y)
{
return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
}
For k = 0 and l = 0, you are calling yourself again and again and again...
Thanks to #BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored, I've added the condition for it in the code below.
If you insist on your current code, try changing the condition to:
if (CheckBounds(x + k, y + l)
&& GameLogicChecker(x + k, y + l) == 0
&& !(k == 0 && l == 0)
&& !Explored[x + k, y + l])
{
Explored[x + k, y + l] = true;
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.
1. GameLogicChecker()
private int GameLogicChecker(int x, int y)
{
if (_grid[x, y] == -1) return 0;
int count = 0;
if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
{
count++;
}
if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
{
count++;
}
if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
{
count++;
}
if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
{
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
{
count++;
}
if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
{
count++;
}
if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
{
count++;
}
if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
{
count++;
}
return count;
}
What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.
2. OpenEmptySpace()
public/private void OpenEmptySpace(int x, int y)
{
for (var deltaX = -1; deltaX <= 1; deltaX += 2)
{
for (var deltaY = -1; deltaY <= 1; deltaY += 2)
{
var thisX = x + deltaX;
var thisY = y + deltaY;
if (OpeningNotNeeded(thisX, thisY))
{
continue;
}
Explored[thisX, thisY] = true;
_buttons[thisX, thisY].Text = "0";
OpenEmptySpace(thisX, thisY);
}
}
}
private bool OpeningNotNeeded(int x, int y)
{
return !CheckBounds(x, y)
|| GameLogicChecker(x, y) != 0
|| Explored[x, y];
}
What's better? Properly named indexing variables in both loops. Properly written condition (+= 2 instead of ++). Reduced nesting in If(...). Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.
3. CheckBounds() is written fine.
Related
A 2 dimensional array with a size of NxN, composed of 1 and 0.
A neighbor is a 1 in the north / south / west / east of the index
Recursively find how many neighbors an index in the array has (neighbors that touch other neighbors are also included).
For the array I built I should get 6, but instead I get a stack overflow exception, and I don't get why.
Below is my 7x7 array, that for index 2, 5 should return the value of 6.
Example:
static void Main(string[] args)
{
int[,] arr = {
{ 0,0,0,1,0,0,0 },
{ 1,0,0,1,1,0,0 },
{ 0,0,0,0,1,1,0 },
{ 0,0,0,0,1,0,0 },
{ 0,0,0,0,0,0,0 },
{ 0,1,1,1,1,0,0 },
{ 1,0,0,1,0,0,0 },
};
Console.WriteLine(Recursive(arr,2,5));
Console.ReadLine();
}
Routine under test:
static public int Recursive(int[,] arr, int x, int y)
{
if (x < 0 || y < 0 || x > arr.GetLength(0) || y > arr.GetLength(1))
{
return 0;
}
// check if a 1 has neighbors
if (arr[x, y] == 1)
{
return 1 +
Recursive(arr, x - 1, y) +
Recursive(arr, x + 1, y) +
Recursive(arr, x, y - 1) +
Recursive(arr, x, y + 1);
}
else
{
return 0;
}
}
Please, note that when you compute Recursive(arr, x, y) you call both Recursive(arr, x - 1, y) and Recursive(arr, x + 1, y):
return 1 +
Recursive(arr, x - 1, y) + // <- both x - 1
Recursive(arr, x + 1, y) + // <- and x + 1
Recursive(arr, x, y - 1) +
Recursive(arr, x, y + 1);
On the next recursive call, when you try to compute Recursive(arr, x + 1, y) it calls Recursive(arr, x + 2, y) as well as Recursive(arr, x + 1 - 1, y) which is Recursive(arr, x, y). So you have a vicious circle: to compute Recursive(arr, x, y) you must compute Recursive(arr, x, y) and stack overflow as the the result.
The way out is to break the circle and don't let read the same cell again and again (we can just set it to 0 for this):
public static int Recursive(int[,] arr, int x, int y)
{
// out of the grid
if (x < 0 || y < 0 || x > arr.GetLength(0) || y > arr.GetLength(1))
return 0;
// empty cell
if (arr[x, y] == 0)
return 0;
// do not read the cell again! From now on treat it as an empty cell
arr[x, y] = 0;
int result = 1; // the cell itself
// let have a loop instead of four calls
for (int d = 0; d < 4; ++d)
result += Recursive(arr, x + (d - 2) % 2, y + (d - 1) % 2);
// Restore after the recursive call:
// let us do not damage arr with permanently setting cells to 0
// and return arr to its original state
arr[x, y] = 1;
return result;
}
Edit: non recursive solution, where we memorize in visited all the visited cells:
public static int Memoization(int[,] arr, int x, int y) {
if (x < 0 || y < 0 || x > arr.GetLength(0) || y > arr.GetLength(1))
return 0;
if (arr[x, y] == 0)
return 0;
int result = 0;
var agenda = new Queue<(int x, int y)>();
agenda.Enqueue((x, y));
var visited = new HashSet<(int x, int y)> { (x, y) };
while (agenda.Count > 0) {
result += 1;
var (oldX, oldY) = agenda.Dequeue();
for (int d = 0; d < 4; ++d) {
int newX = oldX + (d - 2) % 2;
int newY = oldY + (d - 1) % 2;
if (newX < 0 || newY < 0 || newX > arr.GetLength(0) || newY > arr.GetLength(1))
continue;
if (arr[newX, newY] == 0)
continue;
if (visited.Add((newX, newY)))
agenda.Enqueue((newX, newY));
}
}
return result;
}
Start by considering the simplest possible input. In this case it would be an array like
int[,] arr = { {1, 1 }}
I.e. an array consisting of only two items.
Start by the first left item, this is one, so next all neighbors recursed to.
All but the right neighbor is outside the array so will be ignored.
The right item is one, so all neighbors to this will be recursed to, including the left item.
Since you end up processing the left item again, you will continue the recursion until you run out of stack space.
The point here is that you need to keep track of all the points you have already visited. For example by using a HashSet<(int x, int y)>.
I tried to make a function that finds the fastest route to the end of the array by making a recursion that chooses its path by first availability. for some reason, the recursion doesn't stop when it returns true. why?
static void Main(string[] args)
{
int[,] arr = new int[5, 5];
arr[0, 0] = 2;
if (PathFinder(arr, 0, 0))
{
printarr(arr);
}
}
static bool PathFinder(int[,] arr, int y,int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y + 1, x);
}
/////UP
if (y!=0 && arr[y-1,x]!=2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr,y-1,x);
}
/////Left
if (x != 0 && arr[y, x-1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
PathFinder(arr, y, x - 1);
}
return false;
}
}
static void printarr(int[,] arr)
{
for (int row = 0; row < arr.GetLength(0); row++)
{
for (int colom = 0; colom < arr.GetLength(1); colom++)
{
Console.Write(arr[row, colom] + " ");
}
Console.WriteLine("");
}
}
If you call a method that has a return type recursively without storing that return value, it will proceed after the call. You have called it by name PathFinder(... so when true is returned your recursive call doesn't pass it on. Change your code like this:
static bool PathFinder(int[,] arr, int y, int x)
{
if (arr[arr.GetLength(0) - 1, arr.GetLength(1) - 1] == 2)
{
return true;
}
else
{
/////Right
if (x != arr.GetLength(1) - 1 && arr[y, x + 1] != 2 && arr[y, x + 1] == 0)
{
arr[y, x + 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x + 1);
}
/////Down
if (y != arr.GetLength(0) - 1 && arr[y + 1, x] != 2 && arr[y + 1, x] == 0)
{
arr[y + 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y + 1, x);
}
/////UP
if (y != 0 && arr[y - 1, x] != 2 && arr[y - 1, x] == 0)
{
arr[y - 1, x] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y - 1, x);
}
/////Left
if (x != 0 && arr[y, x - 1] != 2 && arr[y, x - 1] == 0)
{
arr[y, x - 1] = 2;
printarr(arr);
Console.WriteLine("");
return PathFinder(arr, y, x - 1);
}
return false;
}
}
This way, when you hit return true;, that value will be passed along all the way back the call stack and you won't continue processing until your return false;
Recursive calls to methods without a return type should have a return; statement somewhere so they can escape otherwise you'll hit a StackOverflowException.
I'm writing an FPTAS algorithm for Knapsack problem, and found out that I need to implement dynamic programming by profit for that. I have found many resources for dynnamic programming by weight (O(n * W), n - number of items, W - max capacity), but very little for profit based (O(n^2 * C), n - number of items, C highest profit from one item).
I have found only one source with pseudo code here (it's in Polish, but you can see code and functions starting at page 7):
http://www.asdpb.republika.pl/wyk78.pdf
My code:
F = new int[items.Count + 1, (Pmax * items.Count) + 1];
int y;
int k;
int profit = 0;
for (k = 0; k < items.Count; k++)
{
for (y = 0; y < (Pmax * items.Count); y++)
{
if (y == 0 && k >= 1)
F[k, y] = 0;
else if (y >= 1 && k == 0)
F[k, y] = int.MaxValue;
else if (k >= 1 && y >= 1)
{
if (y - items[k].profit < 0)
F[k, y] = (int)Math.Min(F[k - 1, y], int.MaxValue);
else
F[k, y] = (int)Math.Min(F[k - 1, y], F[k - 1, y - items[k].profit] + items[k].weight);
}
}
}
y = 0;
do
{
y++;
for (k = 1; k < items.Count; k++)
{
if (y - items[k].profit < 0)
F[k, y] = F[k - 1, y];
else if (F[k - 1, y - items[k].profit] == int.MaxValue)
F[k, y] = F[k - 1, y];
else
F[k, y] = (int)Math.Min(F[k - 1, y], F[k - 1, y - items[k].profit] + items[k].weight);
if(F[items.Count,y] <= maxCapacity)
profit = y;
}
} while (y < Pmax * items.Count);
I'm using sample data from website linked before:
n = 3
profits = [2,3,1]
weights = [1,3,3]
capacity = 5
But it returns profit = 9 and entirely diffrent table F.
What's wrong with my code? Are there any other good sources for this?
Alternatively I can implement PTAS algorithm but I could not find any good sources either.
Creating a Go Board Game but I'm stuck at checking the board for groups of stones that have been surrounded. To do this I thought I'd need to come up with some recursive functionality:
(Updated)
public List<Point> FindSurrounded(Board board, Point p, Player player, List<Point> group)
{
int[,] b = board.board;
for (int dx = -1; dx <= 1; dx++){
for (int dy = -1; dy <= 1; dy++)
{
//check if group allready contain this spot
if (p.X + dx < board.width && p.Y + dy < board.height && p.X + dx > 0 && p.Y + dy > 0 && (dy == 0 || dx == 0) && !(dy == 0 && dx == 0) && !group.Contains(new Point(p.X + dx, p.Y + dy)))
{
// is the spot empty
if (b[p.X + dx, p.Y + dy] == 0)
return null;
//check the suroundings of this spot and add them to the group
//if(b[p.X + dx, p.Y + dy] != player.Identifier)// is there an enemy on this spot
// return new List<Point>();
if (b[p.X + dx, p.Y + dy] != player.Identifier)
{
group.Add(new Point(p.X + dx, p.Y + dy));
List<Point> temp = FindSurrounded(board, new Point(p.X + dx, p.Y + dy), player, new List<Point>());
if (temp == null)
return null;
//group.AddRange(temp);
}
}
}
}
return group;
}
This code however gives me a System.StackOverFlowException error when I put a stone that surrounds stones of the opponent. The error would concern the following line:
if (p.X + dx < board.width && p.Y + dy < board.height && p.X + dx > 0 && p.Y + dy > 0 && (dy == 0 || dx == 0) && !(dy == 0 && dx == 0) && !group.Contains(new Point(p.X + dx, p.Y + dy)))
But I have no idea why.
Does anyone know a way in which I can check whether a group of stones on the board is surrounded?
Thanks in advance!
Best regards,
Skyfe.
EDIT: Forgot to mention I still have to create an array to temporarily store all found stones that form a group together in order to remove them from the board when they're surrounded.
Answer to the specific question:
Does anyone know a way in which I can check whether a group of stones on the board is surrounded?
Try this approach:
Board b;
int N, M; // dimensions
int timer;
int[,] mark; // assign each group of stones a different number
int[,] mov = // constant to look around
{
{ 0, -1 }, { 0, +1 },
{ -1, 0 }, { +1, 0 }
};
// Checks for a group of stones surrounded by enemy stones
// Returns the first group found or null if there is no such group.
public List<Point> CheckForSurrounded()
{
mark = new int[N,M];
for (int i = 0; i < b.SizeX; ++i)
for (int j = 0; j < b.SizeX; ++j)
if (mark[i, j] == 0) // not visited
{
var l = Fill(i, j);
if (l != null)
return l;
}
return null;
}
// Marks all neighboring stones of the same player in cell [x,y]
// Returns the list of stones if they are surrounded
private List<Point> Fill(int x, int y)
{
int head = 0;
int tail = 0;
var L = new List<Point>();
mark[x, y] = ++timer;
L.Add(new Point(x,y));
while (head < tail)
{
x = L[head].X;
y = L[head].Y;
++head;
for (int k = 0; k < 4; ++k)
{
// new coords
int xx = x + mov[k,0];
int yy = y + mov[k,1];
if (xx >= 0 && xx < N && yy >= 0 && yy < M) // inside board
{
if (mark[xx, yy] == 0) // not visited
{
if (b[xx, yy].IsEmpty) // if empty square => not surrounded
return null;
if (b[xx, yy].IsMine)
{
L.Add(new Point(xx,yy)); // add to queue
mark[xx, yy] = timer; // visited
++tail;
}
}
}
}
}
// the group is surrouneded
return L;
}
This method doesn't use recursion so you don't have to deal with stack overflow (the exception not the site).
You could do it with code that does something like this.
pseudocode
isSurrounded(stone){
//mark that you have seen the stone before
stone.seen = true;
//check if all the surrounding spots are surrounded
for(spot in surrounded.getSpotsAround){
//An empty spot means the stone is not surrounded
if(spot = empty){
return false;
}
else{
//don't recheck stones you have seen before or opponents stones
if(spot.stone.seen != true || !stone.belongsToOpponent){
//recursively call this method, if it returns false your stone is not surrounded
if(!isSurrounded(spot.stone){
return false;
}
}
}
}
//if all of the surrounding stones are surrounded,seen already, or belong to other players, this stone is surrounded
return true;
}
Then you would have to remove all the stones where seen = true or reset seen on all stones.
I came up with this
(Updated)
public List<Point> FindSurrounded(int[,] b, Point p, Player player, List<Point> group)
{
for (int dx = -1; dx <= 1; dx++){
for (int dy = -1; dy <= 1; dy++)
{
//check if group allready contain this spot
if ((dy == 0 || dx == 0) && !(dy == 0 && dx == 0) && !group.Contains(new Point(p.X + dx, p.Y + dy))
{
// is the spot empty
if( b[p.X + dx, p.Y + dy] == 0)
return null;
if(b[p.X + dx, p.Y + dy] == player.Identifier)// is this your own stone
{
//If this is my stone add it to the list and check for it
group.Add( new Point( p.X + dx, p.Y + dy ) );
List<Point> temp = removeSurrounded(b, new Point(p.X + dx, p.Y + dy), player, group);
if(temp == null)
return null;
}
}
}
}
return group;
}
This returns null if there is any empty spot near your group else it will return a list of Points which represents your group.
Afterwards you can remove them like that
List<Point> group = FindSurrounded(b, p, player, new List<Point>());
if(group != null)
foreach(Point point in group)
b[point.x, point.y] = 0;
I was bored and had only 30 minutes of free time so I decided to have a crack at making the game of life. I followed that rules on wikipedia and it doesn't seem to be working correctly. Could someone please tell me what I would be doing wrong?
Here are the rules:
Any live cell with fewer than two live neighbours dies, as if caused by under-population.
Any live cell with two or three live neighbours lives on to the next generation.
Any live cell with more than three live neighbours dies, as if by overcrowding.
Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
public void PerformLogic()
{
if (in_game)
{
time_elapsed += rate;
if (time_elapsed > frame_rate)
{
time_elapsed = 0;
for (int x = 0; x < board_width; x++)
{
for (int y = 0; y < board_height; y++)
{
if (board[x, y] == alive)
{
int surrounding_cells = 0;
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= 1; y2++)
{
if (!(x2 + x <= -1 || y2 + y <= -1 || x + x2 >= board_width || y + y2 >= board_height))
{
if (board[x + x2, y + y2] == alive)
{
surrounding_cells++;
}
}
}
}
if (surrounding_cells < 2)
{
board[x, y] = dead;
}
if (surrounding_cells == 2 ||
surrounding_cells == 3)
{
board[x, y] = alive;
}
if (surrounding_cells > 3)
{
board[x, y] = dead;
}
}
else if (board[x, y] == dead)
{
int surrounding_cells = 0;
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= ; y2++)
{
if (!(x2 + x <= -1 || y2 + y <= -1 || x + x2 >= board_width || y + y2 >= board_height))
{
if (board[x + x2, y + y2] == alive)
{
surrounding_cells++;
}
}
}
}
if (surrounding_cells == 3)
{
board[x, y] = alive;
}
}
}
}
}
}
}
Any ideas?
I believe you are updating the board too early. The game of life should update the board after it finishes scanning the whole board, rather than while scanning.
E.g.:
if (surrounding_cells > 3)
{
board[x, y] = dead;
}
After this, for the cell next to it, this cell would be treated as dead.
Marc is right, too.
for (int x2 = -1; x2 <= 1; x2++)
{
for (int y2 = -1; y2 <= 1; y2++)
{
looks to me like you're including the central cell in this loop, so 9 instead of 8.
I'm not sure the nested for is the best option, but if you are using that, add:
if(x2 == 0 && y2 == 0) continue;
at the start of the inner loop (i.e. after the last line that I've posted above)