[英]What is the better alternative for If else in implementing the logic in a program? | C#
[英]What would be a better way to implement this if else logic?
老实说,我想不出更好的标题,因为这是一个基于场景的问题:
我们有一个 Battleships 游戏,我们想要求玩家提供一对坐标,以便在网格上设置他们的一艘船(更具体地说,是船的起点和终点)。 假设坐标已经正确给出并且船在网格平面的范围内,我们只需要检查船是否与当前在网格平面上的任何其他船发生碰撞。
上下文:Grid 有一个 Content 属性,它可以是 ShipContent 或 EmptyContent。
CollisionChecker() 方法循环遍历先前给定的坐标对之间的空间(请注意,这些坐标不能是对角线,这也被假定为事先检查过的)。
玩家想把他们的战舰放在 A1 和 A4 之间。 由于字母相等,我们循环遍历 1 到 4,很简单。 但是,玩家可以按照他们的顺序分别输入 A4 和 A1。 这两种情况在逻辑上都可以正常工作,但如果不进行相应处理,它们可能会导致 OutOfBound 异常和/或不正确的循环。
最后一点上下文,CoordinateLetter 是一个枚举,其中包含整个英文字母表。
static bool CollisionChecker(Grid[][] gridPlane, CoordinateLetter coordinateLetter1, CoordinateLetter coordinateLetter2, int coordinateNumber1, int coordinateNumber2)
{
bool lettersEqual = coordinateLetter1 == coordinateLetter2;
bool cL1Bigger = coordinateLetter1 > coordinateLetter2;
bool cN1Bigger = coordinateNumber1 > coordinateNumber2;
if (lettersEqual && cN1Bigger)
for (int num = coordinateNumber2; num <= coordinateNumber1; num++)
{
// Assume that if it collides, it returns false
}
else if (lettersEqual && !cN1Bigger)
{
for (int num = coordinateNumber1; num <= coordinateNumber2; num++)
{
// Assume that if it collides, it returns false
}
}
else if (!lettersEqual && cL1Bigger)
{
for (int num = (int)coordinateLetter2; num <= (int)coordinateLetter1; num++)
{
// Assume that if it collides, it returns false
}
}
else
{
for (int num = (int)coordinateLetter1; num <= (int)coordinateLetter2; num++)
{
// Assume that if it collides, it returns false
}
}
return true;
}
这段代码让我脊背发凉。 如果其他情况是这样的,我不喜欢链接。 有什么更好的方法来实现这一点?
您可以使代码更易于遵循和维护,也许在命名上更合乎逻辑。
但有时你会做你必须做的事。
这只是我在玩弄它...
static bool CollisionChecker(Grid[][] gridPlane, CoordinateLetter gridRow1, CoordinateLetter gridRow2, int gridCol1, int gridCol2)
{
bool sameRow = (gridRow1 == gridRow2);
if (!(sameRow || (gridCol1 == gridCol2)))
throw new ArgumentException("Diagonal not allowed!");
if (sameRow)
{
int row = (int)gridRow1;
int start = Math.Min(gridCol1, gridCol2);
int end = Math.Max(gridCol1, gridCol2);
for (int i = start; i <= end; i++)
{
//Check gridPlane[row][i]
}
}
else //Same column
{
int col = gridCol1;
int start = Math.Min((int)gridRow1, (int)gridRow2);
int end = Math.Max((int)gridRow1, (int)gridRow2);
for (int i = start; i <= end; i++)
{
//Check gridPlane[i][col]
}
}
return true;
}
您在这里真正要做的是在两个向量之间进行插值,因此您无需明确处理每种情况,只需使用它们的归一化差异来逐步遍历网格。 让我解释得更好。
首先,让我们用数字替换坐标系中的字母(只是为了让事情更简单),这样 A1 = (1; 1)、B4 = (2; 4) 等等。 想象一下,您正在尝试将 go 从 E1 到 A1,或 X = (5; 1) 到 Y = (1; 1)。 要在一个 go 中完成这一旅程,您需要从 X 的第一个分量中删除 4 个单位,这在数学上可以写为 X + (-4; 0) = Y。重新排列它为我们提供了找到任何之间差异的公式两个向量:Y - X = (-4; 0),也就是说,只需从目标 position (Y) 中减去起始 position (X)。
但是你不想在一个 go 中完成这个旅程,你想以小步骤检查另一艘船是否阻挡了你。 现在,因为你在一个离散的 integer 网格中(即你在 position 1 或 2 中,你不能在 position 中,而错过了最长的步骤 1.5) way 的长度为 1。因此,如果您的点之间的差异为 (-4; 0),则您需要 (-1; 0) 的步长。 如果差为 (0; 5),则需要 (0; 1) 的步长。 这种在保持方向不变的情况下获取向量并将其减少到长度 1 的过程称为归一化。 由于您的向量将始终是轴对齐的(即您不会沿对角线行走),您可以作弊并在每个组件上使用Math.sign而不是进行“完整”向量归一化。
把它们放在一起会给你这样的东西(考虑这个伪代码,我什至不知道它是否会编译):
int diffX = (int)coordinateLetter2 - (int)coordinateLetter1;
int diffY = coordinateNumber2 - coordinateNumber1;
int stepX = Math.sign(diffX);
int stepY = Math.sign(diffY);
CoordinateLetter currentX = coordinateLetter1;
int currentY = coordinateNumber1;
while (currentX != coordinateLetter2 || currentY != coordinateNumber2)
{
if (HasCollision(currentX, currentY))
return false;
currentX += stepX;
currentY += stepY;
}
return true;
我还建议创建一个结构来保存 position 的两个坐标(字母和数字),以便您可以直接在 position 上而不是在其组件上进行操作。 这使得推理二维码变得更容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.