Index is not in array issues - C# - c#

I'm currently in the process of making mine sweeper for a class project. I have got most of the fundamentals but when I click on an edge button, because it checks all buttons around it, the code crashes when there is no index value. E.g. When x is equal to 10 but the code calls for buttonArray[x + 1, y]. Its a null value and just crashes. Any Ideas on how to fix this? Code is included...
decimal MineCount = 0;
#region MineCount
if ((buttonArray[x + 1, y] != null) && (isMine[x + 1, y] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x + 1, y + 1] != null) && (isMine[x + 1, y + 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x + 1, y - 1] != null) && (isMine[x + 1, y - 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x, y + 1] != null) && (isMine[x, y + 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x, y - 1] != null) && (isMine[x, y - 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x - 1, y - 1] != null) && (isMine[x - 1, y - 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x - 1, y] != null) && (isMine[x - 1, y] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}
if ((buttonArray[x - 1, y + 1] != null) && (isMine[x - 1, y + 1] == true))
{
isNeighbour[x, y] = true;
isBlank[x, y] = false;
MineCount += 1m;
}

You can use this function for this, instead of duplicate code.
The point of the function is to use limited boundaries.
void CountCells()
{
for(int ix = Math.Max(x - 1, 0); ix <= Math.Min(x + 1, isMine.GetLength(0)); ix++)
{
for(int iy = Math.Max(y - 1, 0); iy <= Math.Min(y + 1, isMine.GetLength(1)); iy++)
{
if ((buttonArray[ix,iy] != null) && isMine[ix,iy])
{
isNeighbour[ix, iy] = true;
isBlank[ix, iy] = false;
MineCount += 1m;
}
}
}
}
Hope it's can be helpfull!

Related

Find Even and Odd columns and rows of Bitmap with LockBits() function

im using the second block code to find Even and Odd columns of a bitmap in order to build a Checkered page in bitmap i used my IsEven() and IsOdd() function
i want to do this job with lockbits:
public unsafe void DrawCheckeredPage()
{
Bitmap bmpShati = null;
bmpShati = new Bitmap(#"\ColorReductedBMP.bmp");
Color GrayOne = Color.FromArgb(153, 153, 153);
Color WhiteOne = Color.FromArgb(255, 255, 255);
for (int x = 0; x < bmpShati.Width; x++)
{
for (int y = 0; y < bmpShati.Height; y++)
{
Color PreCol = bmpShati.GetPixel(x, y);
if (OmitedPictureBoxes.Exists(item => (Color)item.Tag == PreCol))
{
if (IsEven(x) && IsEven(y))
{
bmpShati.SetPixel(x, y, GrayOne);
}
else if (IsOdd(x) && IsOdd(y))
{
bmpShati.SetPixel(x, y, GrayOne);
}
else if (IsEven(x) && IsOdd(y))
{
bmpShati.SetPixel(x, y, WhiteOne);
}
else if (IsOdd(x) && IsEven(y))
{
bmpShati.SetPixel(x, y, WhiteOne);
}
}
}
}
bmpShati = resizeBitmap2(bmpShati, newW, newH);
pbMain.Invoke((Action)(() => pbMain.Image = bmpShati));
}
but there is a problem that Checkered page is not drawing correct i did it with GetPixel() and SetPixel but i i must use LockBits, can you please help me?
here is my code :
public unsafe void DrawCheckeredPage()
{
Bitmap bmpShati = null;
bmpShati = new Bitmap(#"\ColorReductedBMP.bmp");
Rectangle rect = new Rectangle(0, 0, bmpShati.Width, bmpShati.Height);
var _bdata = bmpShati.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppRgb);
var _ptr = (byte*)_bdata.Scan0;
int _numBytes = _bdata.Stride * _bdata.Height, row, col;
for (int i = 0; i < _numBytes; i += 4)
{
Color PreCol = Color.FromArgb(
(*(_ptr + i + 2)),
(*(_ptr + i + 1)),
(*(_ptr + i))
);
if (OmitedPictureBoxes.Exists(item => (Color)item.Tag == PreCol))
{
row = i / _bdata.Stride;
col = i % _bdata.Stride;
if (IsEven(row) && IsEven(col))
{
(*(_ptr + i + 2)) = Convert.ToByte(153);
(*(_ptr + i + 1)) = Convert.ToByte(153);
(*(_ptr + i)) = Convert.ToByte(153);
}
else if (IsOdd(row) && IsOdd(col))
{
(*(_ptr + i + 2)) = Convert.ToByte(153);
(*(_ptr + i + 1)) = Convert.ToByte(153);
(*(_ptr + i)) = Convert.ToByte(153);
}
else if (IsEven(row) && IsOdd(col))
{
(*(_ptr + i + 2)) = Convert.ToByte(255);
(*(_ptr + i + 1)) = Convert.ToByte(255);
(*(_ptr + i)) = Convert.ToByte(255);
}
else if (IsOdd(row) && IsEven(col))
{
(*(_ptr + i + 2)) = Convert.ToByte(255);
(*(_ptr + i + 1)) = Convert.ToByte(255);
(*(_ptr + i)) = Convert.ToByte(255);
}
}
}
bmpShati.UnlockBits(_bdata);
bmpShati = resizeBitmap2(bmpShati, newW, newH);
pbMain.Invoke((Action)(() => pbMain.Image = bmpShati));
}
public bool IsOdd(int value)
{
return value % 2 != 0;
}
public static bool IsEven(int value)
{
return value % 2 == 0;
}

Why won't my C# Recursion stop when it hits true?

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.

Random movement of char in console c#

I made a maze game in a console application and by using keys I can control character to leave the maze. Now I want to figure out how to automate that process So that my character can go by random directions and try to find the way out. Here is my class.
The problem is in the randomMovement Method.
class Player: Maze
{
public int x = 1;
public int y = 1;
public string playerName;
public static void printMv() {
while (true)
{
for (int i = 0; i < 15; i++)
{
Console.Clear();
mazeDev();
Console.Write("0");
Thread.Sleep(1000);
}
}
}
public static void movementByUser()
{
int x = 1, y = 1;
while (true)
{
Console.Clear();
mazeDev();
Console.CursorLeft = x;
Console.CursorTop = y;
Console.Write("0");
ConsoleKeyInfo mv = Console.ReadKey();
if (mv.Key == ConsoleKey.Escape) break;
if (mv.Key == ConsoleKey.A && mazeBluePrint[y, x - 1] == 0) {
x--;
}
if (mv.Key == ConsoleKey.D && mazeBluePrint[y, x + 1] == 0)
{
x++;
}
if (mv.Key == ConsoleKey.W && mazeBluePrint[y - 1, x] == 0)
{
y--;
}
if (mv.Key == ConsoleKey.S && mazeBluePrint[y + 1, x] == 0)
{
y++;
}
}
}
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
int irandom = randMove.Next(4);
Console.CursorLeft = x;
Console.CursorTop = y;
if (irandom == mazeBluePrint[y, x - 1])
{
x--;
printMv();
}
else if (irandom == mazeBluePrint[y, x + 1])
{
x++;
printMv();
}
else if (irandom == mazeBluePrint[y - 1, x])
{
y--;
printMv();
}
else
{
y++;
printMv();
}
}
}
}
Your problem probably is the direction evaluation. Try this:
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
int irandom = randMove.Next(4);
Console.CursorLeft = x;
Console.CursorTop = y;
if (irandom == 0 && mazeBluePrint[y, x - 1] == 0)
{
x--;
printMv();
}
else if (irandom == 1 && mazeBluePrint[y, x + 1] == 0)
{
x++;
printMv();
}
else if (irandom == 2 && mazeBluePrint[y - 1, x] == 0)
{
y--;
printMv();
}
else if (mazeBluePrint [y + 1, x] == 0)
{
y++;
printMv();
}
}
However, this code still has a lot of weaknesses (e.g. you could walk out of the boundaries of the mazeBluePrint array, which would result in an exception).
EDIT
If you want to move in the other direction if the first didn't work, you could try something like this:
public static void randomMovement()
{
Random randMove = new Random();
int x = 1;
int y = 1;
Console.CursorLeft = x;
Console.CursorTop = y;
while (true)
{
int irandom = randMove.Next(4);
if (irandom == 0 && mazeBluePrint[y, x - 1] == 0)
{
x--;
printMv();
break;
}
else if (irandom == 1 && mazeBluePrint[y, x + 1] == 0)
{
x++;
printMv();
break;
}
else if (irandom == 2 && mazeBluePrint[y - 1, x] == 0)
{
y--;
printMv();
break;
}
else if (mazeBluePrint[y + 1, x] == 0)
{
y++;
printMv();
break;
}
}
}
However, this only moves one time, beginning from 1,1.

Set opacity of particular pixels (and these radius) using Bitmap.LockBits and BitmapData

I'm trying to set opacity of surroundings of particular pixels in bitmap.
For now I can set opacity of pixels that meets some conditions. (e.g. pixel on left or rigt or top or down is not 100% white)
I'm using Bitmap.LockBits and BitmapData, becouse application will process very big images.
Here is my code:
private void SetOpacity(Bitmap processedBitmap, int radius)
{
int opacityStep = 255 / radius;
int opacity = 0;
unsafe
{
BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
byte* ptrFirstPixel = (byte*)bitmapData.Scan0;
for (int y = 0; y < heightInPixels; y++)
{
byte* currentLine = ptrFirstPixel + (y * bitmapData.Stride);
byte* previousLine = ptrFirstPixel + ((y - 1) * bitmapData.Stride);
byte* nextLine = ptrFirstPixel + ((y + 1) * bitmapData.Stride);
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
if (currentLine[x] + currentLine[x + 1] + currentLine[x + 2] == 765)
{
if (currentLine[x + bytesPerPixel] + currentLine[x + bytesPerPixel + 1] + currentLine[x + bytesPerPixel + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (currentLine[x - bytesPerPixel] + currentLine[x - bytesPerPixel - 1] + currentLine[x - bytesPerPixel - 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (previousLine[x] + previousLine[x + 1] + previousLine[x + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
else if (nextLine[x] + nextLine[x + 1] + nextLine[x + 2] != 765)
{
currentLine[x + 3] = (byte)opacity;
}
}
}
}
processedBitmap.UnlockBits(bitmapData);
}
}
Slow variant of this code is:
for (int x = 0; x < processedBitmap.Width; x++)
{
for (int y = 0; y < processedBitmap.Height; y++)
{
if (processedBitmap.GetPixel(x, y) == Color.White)
{
if (processedBitmap.GetPixel(x - 1, y) != Color.White || processedBitmap.GetPixel(x + 1, y) != Color.White
|| processedBitmap.GetPixel(x, y - 1) != Color.White || processedBitmap.GetPixel(x, y + 1) != Color.White)
{
processedBitmap.SetPixel(x, y, Color.FromArgb(0, processedBitmap.GetPixel(x, y)));
}
}
}
}
What I need is to set opacity not only of pixels that meet conditions, but also pixels in some radius.
Also I need some opacity steps.
What I'm trying to do is:
for (int r = Radius; Radius > 0; r--)
{
for (int x = 0; x < processedBitmap.Width; x++)
{
for (int y = 0; y < processedBitmap.Height; y++)
{
if (processedBitmap.GetPixel(x, y) == Color.White)
{
if (processedBitmap.GetPixel(x - 1, y) != Color.White || processedBitmap.GetPixel(x + 1, y) != Color.White
|| processedBitmap.GetPixel(x, y - 1) != Color.White || processedBitmap.GetPixel(x, y + 1) != Color.White)
{
processedBitmap.SetPixel(x, y, Color.FromArgb(0, processedBitmap.GetPixel(x, y)));
for (int i = -r; i < r; i++)
{
for (int j = -r; j < r; j++)
{
if ((i * i + j * j) < (r * r))
{
processedBitmap.SetPixel(x + i, y + j, Color.FromArgb(OpacityStep * r, processedBitmap.GetPixel(x + i, y + i)));
}
}
}
}
}
}
}
}
But way faster.
Pixel format of bitmaps i use is 32bbpArgb
Thanks for any suggestions.

recursive stackoverflow minesweeper c#

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.

Categories