gpt4 book ai didi

c# - 递归调用方法时防止 System.StackOverflowException

转载 作者:太空宇宙 更新时间:2023-11-03 22:41:16 25 4
gpt4 key购买 nike

我是 c#(或一般编码)的新手,我想这个问题真的很愚蠢和令人困惑(我知道我做起来很困难)但请帮助我。

我正在尝试使用表单应用程序制作一个扫雷器。我做了一个 10 x 10 的按钮,如果你点击它,它周围的地雷数量就会显示出来。如果有地雷,就会出现“F”(“False”的第一个字母)。

有一个构造函数,其中包含按钮、x 和 y 位置、周围方 block 的列表、周围地雷的数量,以及一个指示是否有地雷的 bool 值。

我试图做的是当玩家点击一个周围没有地雷的方 block 时清除周围的 8 个方 block (从列表中),如果围绕该方 block 的方 block 也没有任何地雷,这些该 block 周围的 block 也将被清除。该方法使用 foreach 来显示和检查该 block 周围的地雷数量。如果没有地雷,相同的方法将应用于该 block (递归调用该方法)。问题是我不断收到 System.StackOverflowException

我以某种方式理解为什么会这样,但我就是想不出其他方法。

//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)
{
}
}
}
}
}
}

这是 Square 类:

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)

这个话题让很多新开发者感到困惑;不要为此紧张!

If there's no mines, same method will be applied to that block (calling the method recursively).

递归方法可能令人困惑,但如果您使用标准模式设计它们,您将避免 SO 异常。您没有使用标准模式设计您的。

成功递归方法的标准模式是:

  • 我是否处于不需要递归的情况下?
  • 如果是,请进行必要的计算以产生所需的效果并返回。现在问题已经解决了。
  • 如果没有,那么我们将递归。
  • 将当前问题分解为一些较小问题。
  • 通过递归解决每个较小的问题。
  • 结合较小问题的解决方案来解决当前问题。
  • 问题已经解决,返回。

设计递归方法的最重要每次递归都必须解决一个较小的问题,并且较小问题的序列必须在以下位置触底不需要递归的情况。如果不满足这两个条件,那么您发生堆栈溢出。

将那个模式内在化,每次你写一个递归方法,实际写出来:​​

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
}
}

用您的真实代码填写该模板,您将更有可能避免堆栈溢出。几十年来我一直在编写递归方法,而且我仍然遵循这种模式。

现在,在您的示例中,什么情况不需要递归? 必须有一个,所以写下它是什么。接下来,您将如何保证递归可以解决较小的问题?这通常是艰难的一步!考虑一下。

关于c# - 递归调用方法时防止 System.StackOverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52107850/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com