I am new to c# (or coding in general) and I guess this question is really stupid and confusing (I know I'm doing it a hard way) but please help me.
I'm trying to make a minesweeper with form app. I made a 10 x 10 of buttons and if you click it, number of mines around it will be revealed. If a mine is there "F" (the first letter of "False") will appear.
There's a constructor that contains the button, x and y position, list of surrounding blocks, number of mines around it, and a boolean that indicates if there's a mine or not.
What I tried to do was to make the 8 surrounding blocks (from the list) cleared when the player clicked a block with no mine around it and if the block surrounding that block also doesn't have any mine around it, these blocks that surrounding that block will also be cleared. The method uses foreach to reveal and check the number of mines around that block. If there's no mines, same method will be applied to that block (calling the method recursively). The problem is that I keep getting System.StackOverflowException.
I somehow understand why it's happening but I just can't come up with the other way.
//scroll to the bottom for the method with the problem
private void Form1_Load(object sender, EventArgs e)
{
Random random = new Random();
Button[,] buttons = new Button[10, 10]
{
{ r0c0, r0c1, r0c2, r0c3, r0c4, r0c5, r0c6, r0c7, r0c8, r0c9 },
{ r1c0, r1c1, r1c2, r1c3, r1c4, r1c5, r1c6, r1c7, r1c8, r1c9 },
{ r2c0, r2c1, r2c2, r2c3, r2c4, r2c5, r2c6, r2c7, r2c8, r2c9 },
{ r3c0, r3c1, r3c2, r3c3, r3c4, r3c5, r3c6, r3c7, r3c8, r3c9 },
{ r4c0, r4c1, r4c2, r4c3, r4c4, r4c5, r4c6, r4c7, r4c8, r4c9 },
{ r5c0, r5c1, r5c2, r5c3, r5c4, r5c5, r5c6, r5c7, r5c8, r5c9 },
{ r6c0, r6c1, r6c2, r6c3, r6c4, r6c5, r6c6, r6c7, r6c8, r6c9 },
{ r7c0, r7c1, r7c2, r7c3, r7c4, r7c5, r7c6, r7c7, r7c8, r7c9 },
{ r8c0, r8c1, r8c2, r8c3, r8c4, r8c5, r8c6, r8c7, r8c8, r8c9 },
{ r9c0, r9c1, r9c2, r9c3, r9c4, r9c5, r9c6, r9c7, r9c8, r9c9 }
};
Square[,] squares = new Square[10, 10];
for (int i = 0, ii = 0, iii = 0; i < 100; i++, ii++)
{
if (ii == 10)
{
ii = 0;
iii++;
}
squares[ii, iii] = new Square(i, buttons[ii, iii], ii, iii, 0, true);
}
List<int> randoms = new List<int>();
for (int i = 0; i < 10; i++)
{
int ii = random.Next(100);
if (!randoms.Contains(ii))
{
squares[ii % 10, ii / 10].setSafe(false);
}
else
{
i--;
}
randoms.Add(ii);
}
for (int i = 0; i < 10; i++)
{
for (int ii = 0; ii < 10; ii++)
{
for (int iii = -1; iii < 2; iii++)
{
for (int iiii = -1; iiii < 2; iiii++)
{
try
{
if (squares[i + iii, ii + iiii].getSafe() == false)
squares[i, ii].addNumber();
}
catch (System.IndexOutOfRangeException)
{
}
}
//if (squares[i, ii].getSafe() == false) squares[i, ii].getButton().Text = squares[i, ii].getSafe().ToString();
//else squares[i, ii].getButton().Text = squares[i, ii].getNumber().ToString();
}
}
}
for (int i = 0; i < 10; i++)
{
for (int ii = 0; ii < 10; ii++)
{
for (int iii = -1; iii < 2; iii++)
{
for (int iiii = -1; iiii < 2; iiii++)
{
try
{
squares[i, ii].addList(squares[i + iii, ii + iiii]);
}
catch (System.IndexOutOfRangeException)
{
}
}
}
}
}
}
Here's the Square class:
public class Square
{
int id;
Button button;
int x;
int y;
int number;
bool safe;
List<Square> list = new List<Square>();
public Square(int id, Button button, int x, int y, int number, bool safe)
{
this.id = id;
this.button = button;
this.x = x;
this.y = y;
this.number = number;
this.safe = safe;
button.Text = "";
button.Click += button_Click;
}
public int getId()
{
return id;
}
public void setId(int i)
{
id = i;
}
public Button getButton()
{
return button;
}
public void setButton(Button b)
{
button = b;
}
public int getX()
{
return x;
}
public void setX(int i)
{
x = i;
}
public int getY()
{
return y;
}
public void setY(int i)
{
y = i;
}
public int getNumber()
{
return number;
}
public void setNumber(int i)
{
number = i;
}
public void addNumber()
{
number++;
}
public bool getSafe()
{
return safe;
}
public void setSafe(bool b)
{
safe = b;
}
private void button_Click(object sender, EventArgs e)
{
if (getSafe() == false) button.Text = getSafe().ToString();
else button.Text = getNumber().ToString();
if (getNumber() == 0) zeroReveal();
}
//---------------------------------------------------
// this is the method that reveals surrounding blocks
//---------------------------------------------------
private void zeroReveal()
{
foreach (Square s in list)
{
//revealing the blocks
s.getButton().Text = s.getNumber().ToString();
//call the same method if there's no mine
//this is the line that keeps giving me exception
if (s.getNumber() == 0) s.zeroReveal();
}
}
//-----------------------------------------------------
public List<Square> getList()
{
return list;
}
public void setList(List<Square> sl)
{
list = sl;
}
public void addList(Square s)
{
list.Add(s);
}
}
I am new to c# (or coding in general) and I guess this question is really stupid and confusing (I know I'm doing it a hard way)
This topic confuses many a new developer; don't stress out about it!
If there's no mines, same method will be applied to that block (calling the method recursively).
Recursive methods can be confusing but if you design them using the standard pattern, you will avoid SO exceptions. You have not designed yours using the standard pattern.
The standard pattern for successful recursive methods is:
Am I in a case that requires no recursion?
If yes, do the necessary computations to produce the desired effect and return. The problem is now solved.
If no, then we're going to recurse.
Break the current problem down into some number of smaller problems.
Solve each smaller problem by recursing.
Combine the solutions of the smaller problem to solve the current problem.
The problem is now solved, so return.
The most important thing about designing a recursive method is that each recursion must be solving a smaller problem, and the sequence of smaller problems must bottom out at a case that does not require recursion. If those two conditions are not met, then you will get a stack overflow.
Internalize that pattern, and every time you write a recursive method, actually write it out:
int Frob(int blah)
{
if (I am in the base case)
{
solve the base case
return the result
}
else
{
find smaller problems
solve them
combine their solutions
return the result
}
}
Fill in that template with your real code, and you will be much more likely to avoid stack overflows. I've been writing recursive methods for decades, and I still follow this pattern.
Now, in your example, what is the case that does not require recursion? There must be one, so write down what it is. Next, how will you guarantee that the recursion solves a smaller problem? That is often the hard step! Give it some thought.
The stack overflow is occurring because zeroReveal is recursively calling itself forever. To fix this we need to find ways where we do not need it to make further calls to itself.
The name of the method gives us a clue. If the square has already been revealed, then surely the method does not need to do anything, since it has already been revealed.
It looks like the button's Text property is an empty string if it has not yet been revealed. So change the foreach so that it doesn't process squares that have already been revealed:
foreach (Square s in list)
{
if (s.getButton().Text == ""))
{
// existing code in the foreach loop goes here
}
}
Once I run the following local, it is woking fast, but when I submit it to Kattis, It only exceeds 2/5 and I get Time Limit Exceeded.
Any suggestion?
I have tried with a input file with 10000 numbers and it is still fast localy :S
using System;
namespace phonelist
{
class Program
{
static void Main(string[] args)
{
int nrOfPhoneNrs = 0;
bool consistent;
int nrOfTestCases = Convert.ToInt32(Console.ReadLine().Trim());
for (byte i = 0; i < nrOfTestCases; i++)
{
consistent = false;
nrOfPhoneNrs = Convert.ToInt32(Console.ReadLine().Trim());
string[] phList = new string[nrOfPhoneNrs];
int n = 0;
while (n < nrOfPhoneNrs)
{
phList[n] = Console.ReadLine();
n++;
}
Array.Sort(phList);
int runs = nrOfPhoneNrs - 1;
for (int p = 0; p < runs; p++)
{
if (phList[p + 1].StartsWith(phList[p]))
{
consistent= true;
break;
}
}
Console.WriteLine(consistent? "NO" : "YES");
}
}
}
}
I think that your main problem is that you're using StartsWith and Array.Sort methods.
I don't want to give you too detailed advice (so that you can still solve it by yourself) but let me just suggest considering a different data structure than an array of strings, perhaps HashSet<string>.
I'm trying to get my program to start the user with 20 lives and while Lives is greater than 0, flip a coin (random number generator 0(Tails) or 1(Heads)). Every time the user gets Heads it adds 1 to Heads counter and 1 to Flips counter. Every time the user gets Tails it takes 1 from Lives and adds 1 to Flips counter. I think my only problem is my random number generator!? Please be kind, total n00b :)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Coin_Flip_2015
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Random r = new Random(1);
private void cmdFlipCoin_Click(object sender, EventArgs e)
{
int rand = r.Next(1);
int Heads;
int counterFlips;
int Lives;
Lives = 20;
Heads = 0;
counterFlips = 0;
while (Lives > 0)
if (rand == 0)
{
Lives = Lives -= 1;
counterFlips++;
}
else if (rand == 1)
{
Heads = Heads += 1;
counterFlips++;
}
lblFlips.Text = "Flips = " + counterFlips.ToString();
lblHeads.Text = "Heads = " + Heads.ToString();
lblLivesLeft.Text = "Lives Left = " + Lives.ToString();
MessageBox.Show("sorry you are out of lives m8");
}
}
}
The Random.Next(int) method
Returns a non-negative random integer that is less than the specified maximum.
So r.Next(1) is always 0. Use r.Next(2) to get 0 or 1.
You should also move the rand = r.Next(1); inside the while loop. Now it's only assigned once, at the beginning of the method.
I'll take a swing at fixing all the issues:
public partial class Form1 : Form
{
int Heads, counterFlips, Lives;
public Form1()
{
InitializeComponent();
Lives = 20;
Heads = 0;
counterFlips = 0;
}
private Random r = new Random();
private void cmdFlipCoin_Click(object sender, EventArgs e)
{
int rand = r.Next(2);
if (Lives > 0)
{
if (rand == 0)
{
Lives -= 1;
counterFlips++;
}
else
{
Heads += 1;
counterFlips++;
}
}
else
MessageBox.Show("sorry you are out of lives m8");
lblFlips.Text = "Flips = " + counterFlips.ToString();
lblHeads.Text = "Heads = " + Heads.ToString();
lblLivesLeft.Text = "Lives Left = " + Lives.ToString();
}
}
Issues:
The Heads, counterFlips and Lives variables were stored locally, they need to be global
The code was changed so that you flip a coin each time you click the button (changed the while to an if). while loops that have the capability of never exiting should not be used in UI threads.
private Random r = new Random() notice removed the 1, use the default constructor to seed it properly.
Added an "else" to show when the lives were used, it shows your message
Changed the Lives = Lives -= 1 (same with Heads) to proper code
Used r.Next(2) to get either 0 or 1, since the upper bound is exclusive.
Other than that, I'm not sure what you are doing with the Lives and Heads numbers, so I'll leave that up to you to fix.
Here one that is a bit different.. snap beat me by a few seconds!
public partial class Form1 : Form
{
// Leave the seed alone on this line
private readonly Random _r = new Random();
// these need to be outside of your Click event
private int _counterFlips;
private int _heads;
private int _lives = 20;
public Form1()
{
InitializeComponent();
}
private void cmdFlipCoin_Click(object sender, EventArgs e)
{
// x = starting number, y = ending number + 1
// This should be either a zero or one:
int rand = _r.Next(0, 2);
switch (rand)
{
default:
_lives --;
_counterFlips++;
break;
case 1:
_heads ++;
_counterFlips++;
break;
}
if (_lives < 1)
{
MessageBox.Show(#"sorry you are out of lives m8");
button1.Enabled = false;
return;
}
lblFlips.Text = #"Flips = " + _counterFlips;
lblHeads.Text = #"Heads = " + _heads;
lblLivesLeft.Text = #"Lives Left = " + _lives;
}
}
im working in a project where it has to import excel file and show its details in 3 different data grid .i have a button with codes here.
private void btn1_Click(object sender, EventArgs e)
{
try
{
if (Convert.ToInt32(txtreg.Text) > 0)
{
for (int i = 0; i < dgResult1.Columns.Count; i++)
{
if (dgResult1.Columns[i].HeaderText == "REGHRS")
{
for (int j = 0; j < dgResult1.Rows.Count; j++)
{
if (Convert.ToInt32(dgResult1.Rows[j].Cells["REGHRS"].Value.ToString()) >= 12)
{
dgResult1.Rows[j].Cells["REGHRS"].Value = txtreg.Text;
dgResult2.Rows[j].Cells["REGHRS"].Value = Convert.ToInt32(dgResult2.Rows[j].Cells["REGHRS"].Value.ToString().Trim()) - Convert.ToInt32(txtreg.Text);
dgResult3.Rows[j].Cells["REGHRS"].Value = 0;
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
and it throws an error with input string was not in a correct format .can somebody help me .thanks
This is classic Debugging 101, and it's a good idea to learn it early in your career unless you're the coding Kwisatz Haderach, who can write bug-free code first time, every time :-)
Every time before you attempt a conversion with something like:
Convert.ToInt32(blah)
(I see four of those in your code, two on a single line), you should put in some temporary debug code (message box, or console writeline, or something) to find out what blah is actually set to. This should include the actual string, surrounded by [] characters, and the length of the string.
This will let you identify which string is failing the integer conversion. Once you've established that, the next step will be to work out why.
Handling Convert.ToInt32
your exception occurs by Convert.ToInt32(...) - you use it several times.. that means that in some point a string without a number passed to this function
my guess is that some field from the database contains null and represented by an empty string
althougth Convert.ToInt32 can deal with null values it fails on empty string values
a potential solution - use your own method:
int ConvertInt(string val)
{
return (val.IsNullOrEmpty(val)) ? 0 : int.Parse(val); // Parse aimed to deal with strings only while Convert deals withe several types
}
private void btn1_Click(object sender, EventArgs e)
{
int regNumber = 0;
bool regFlag = int.TryParse(txtreg.Text, regNumber)
if(!regFlag)
{
MessageBox.Show("Reg textbox doesn't have integer value");
return;
}
if(regNumber <= 0)
{
MessageBox.Show("Reg textbox has negative or 0 value");
return;
}
for (int i = 0; i < dgResult1.Columns.Count; i++)
{
if (dgResult1.Columns[i].HeaderText != "REGHRS")
continue;
for (int j = 0; j < dgResult1.Rows.Count; j++)
{
string regHrs = dgResult1.Rows[j].Cells["REGHRS"].Value.ToString();
int regValue = 0;
bool regCheck = int.TryParse(regHrs, out regValue)
if(!regCheck || reg < 12)
continue;
dgResult1.Rows[j].Cells["REGHRS"].Value = txtreg.Text;
//till now both converts should be okay.
dgResult2.Rows[j].Cells["REGHRS"].Value = Convert.ToInt32(dgResult2.Rows[j].Cells["REGHRS"].Value.ToString()) - Convert.ToInt32(txtreg.Text);
dgResult3.Rows[j].Cells["REGHRS"].Value = 0;
}
}
}
The error is that you are converting somewhere wrong integer values. Also you have really bad structure of the code. You should avoid nested if. I wrote how the code should probably look like. Also why catch system exceptions, no user cares about them. You should show relevant text.
Below is my opinion
private void btn1_Click(object sender, EventArgs e)
{
try
{
if (Convert.ToInt32(txtreg.Text) > 0)
{
for (int i = 0; i < dgResult1.Columns.Count; i++)
{
if (dgResult1.Columns[i].HeaderText == "REGHRS")
{
for (int j = 0; j < dgResult1.Rows.Count; j++)
{
if (Convert.ToInt32(dgResult1.Rows[j].Cells["REGHRS"].Value.ToString()) >= 12)
{
dgResult1.Rows[j].Cells["REGHRS"].Value = txtreg.Text;
dgResult2.Rows[j].Cells["REGHRS"].Value = Convert.ToInt32(dgResult2.Rows[j].Cells["REGHRS"].Value.ToString().Trim()) - Convert.ToInt32(txtreg.Text);
dgResult3.Rows[j].Cells["REGHRS"].Value = "0";//UpDate this
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
I have to allow 20 balls to move around the screen. I would like to know how do I use a loop so I would not have to type the codes out long. Currently, the codes I have are
for (int i = 0; i < ballSpeedXAxis.Length; i++)
{
ballSpeedXAxis[i] = 1;
}
for (int i = 0; i < ballSpeedYAxis.Length; i++)
{
ballSpeedYAxis[i] = 1;
}
private void OnUpdate(object sender, object e)
{
Canvas.SetLeft(this.ball1, this.ballSpeedXAxis[1] + Canvas.GetLeft(this.ball1));
Canvas.SetTop(this.ball1, this.ballSpeedYAxis[1] + Canvas.GetTop(this.ball1));
Canvas.SetLeft(this.ball2, this.ballSpeedXAxis[2] + Canvas.GetLeft(this.ball2));
Canvas.SetTop(this.ball2, this.ballSpeedXAxis[2] + Canvas.GetTop(this.ball2));
...
Canvas.SetLeft(this.ball20, this.ballSpeedXAxis[20] + Canvas.GetLeft(this.ball20));
Canvas.SetTop(this.ball20, this.ballSpeedXAxis[20] + Canvas.GetTop(this.ball20));
}
ball1, ball2 ... ball3 are images name.
There are varying ways.. the most obvious being instead of this:
Image ball1;
Image ball2;
Image ball3;
// .. etc ...
You would put those in an array also:
Image[] balls = new Image[20];
..same with your speeds. Then you can change your update method to this:
private void OnUpdate(object sender, object e) {
for (int i = 0; i < balls.Length; i++) {
Canvas.SetLeft(balls[i], ballSpeedXAxis[i] + Canvas.GetLeft(balls[i]));
Canvas.SetTop(balls[i], ballSpeedYAxis[i] + Canvas.GetTop(balls[i]));
}
}
Others include putting the already created images into a List<Image>.. but that's a bit yuck.