简体   繁体   English

if else 逻辑有什么更好的方法来实现这个?

[英]What would be a better way to implement this if else logic?

I honestly couldn't come up with a better title since it's a scenario-based question:老实说,我想不出更好的标题,因为这是一个基于场景的问题:

We have a Battleships game, and we want to ask the player for a pair of coordinates to set one of their ships on the grid (more specifically, the starting point and the ending point of the ship).我们有一个 Battleships 游戏,我们想要求玩家提供一对坐标,以便在网格上设置他们的一艘船(更具体地说,是船的起点和终点)。 Assuming that the coordinates were properly given and that the ship is in bounds of the grid plane, we only need to check if the ship collides with any other ship currently on the grid plane.假设坐标已经正确给出并且船在网格平面的范围内,我们只需要检查船是否与当前在网格平面上的任何其他船发生碰撞。

Context: A Grid has a Content property, and it's either ShipContent or EmptyContent.上下文:Grid 有一个 Content 属性,它可以是 ShipContent 或 EmptyContent。

The CollisionChecker() method loops through the space between the pair of coordinates that were previously given (mind that these can't be diagonal, this is also assumed to be checked prior). CollisionChecker() 方法循环遍历先前给定的坐标对之间的空间(请注意,这些坐标不能是对角线,这也被假定为事先检查过的)。

The player wants to put their battleship between A1 and A4.玩家想把他们的战舰放在 A1 和 A4 之间。 Since the letters are equal, we loop through 1 to 4, simple enough.由于字母相等,我们循环遍历 1 到 4,很简单。 However, the player could've entered A4 and A1 respective to their order.但是,玩家可以按照他们的顺序分别输入 A4 和 A1。 Both of these scenarios are expected to work as they are logically sound, but they can cause OutOfBound exceptions and/or improper loops if they are not handled accordingly.这两种情况在逻辑上都可以正常工作,但如果不进行相应处理,它们可能会导致 OutOfBound 异常和/或不正确的循环。

Last bit of context, CoordinateLetter is an enum that has the entire English alphabet in it.最后一点上下文,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;
    }

This block of code sends shivers down my spine.这段代码让我脊背发凉。 I don't like chaining if else's like this.如果其他情况是这样的,我不喜欢链接。 What would be a better way to implement this?有什么更好的方法来实现这一点?

You could make the code easier to follow and maintain, maybe a little more logical in the naming.您可以使代码更易于遵循和维护,也许在命名上更合乎逻辑。

But sometimes you do what you have to.但有时你会做你必须做的事。

This is just me messing around with it...这只是我在玩弄它...

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

What you're really doing here is interpolating between two vectors, so you don't need to handle each of the cases explicitly, you can just use their normalized difference to step through the grid.您在这里真正要做的是在两个向量之间进行插值,因此您无需明确处理每种情况,只需使用它们的归一化差异来逐步遍历网格。 Let me explain better.让我解释得更好。

First, let's replace the letters in your coordinate system with numbers (just to make things simpler) so that A1 = (1; 1), B4 = (2; 4), and so on.首先,让我们用数字替换坐标系中的字母(只是为了让事情更简单),这样 A1 = (1; 1)、B4 = (2; 4) 等等。 Imagine that you're trying to go from E1 to A1, or X = (5; 1) to Y = (1; 1).想象一下,您正在尝试将 go 从 E1 到 A1,或 X = (5; 1) 到 Y = (1; 1)。 To make that journey in one go, you need to remove 4 units from the first component of X, which can be written mathematically as X + (-4; 0) = Y. Rearranging this gives us the formula to find the difference between any two vectors: Y - X = (-4; 0), that is, just subtract your starting position (X) from your target position (Y).要在一个 go 中完成这一旅程,您需要从 X 的第一个分量中删除 4 个单位,这在数学上可以写为 X + (-4; 0) = Y。重新排列它为我们提供了找到任何之间差异的公式两个向量:Y - X = (-4; 0),也就是说,只需从目标 position (Y) 中减去起始 position (X)。

But you don't want to make this journey in one go, you want to do it in small steps to check if another ship is blocking you.但是你不想在一个 go 中完成这个旅程,你想以小步骤检查另一艘船是否阻挡了你。 Now, since you're in a discrete integer grid (ie you're either in position 1 or 2, you can't be in position 1.5), this simplifies things: the longest step you can take while not missing any ships along the way is of length 1. So if the difference between your points is (-4; 0), you want a step of (-1; 0).现在,因为你在一个离散的 integer 网格中(即你在 position 1 或 2 中,你不能在 position 中,而错过了最长的步骤 1.5) way 的长度为 1。因此,如果您的点之间的差异为 (-4; 0),则您需要 (-1; 0) 的步长。 If the difference is (0; 5), you want a step of (0; 1).如果差为 (0; 5),则需要 (0; 1) 的步长。 This process of taking a vector and reducing it to a length of 1 while keeping its direction is called normalization .这种在保持方向不变的情况下获取向量并将其减少到长度 1 的过程称为归一化 Since your vectors will always be axis-aligned (ie you won't be walking diagonally), you can cheat and just use Math.sign on each component instead of doing a "full" vector normalization.由于您的向量将始终是轴对齐的(即您不会沿对角线行走),您可以作弊并在每个组件上使用Math.sign而不是进行“完整”向量归一化。

Putting it all together gives you something like this (consider this pseudocode, I don't even know if it'll compile):把它们放在一起会给你这样的东西(考虑这个伪代码,我什至不知道它是否会编译):

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;

I would also recommend creating a struct to hold both coordinates of a position (the letter and the number) so that you can do operations directly on a position rather than on its components.我还建议创建一个结构来保存 position 的两个坐标(字母和数字),以便您可以直接在 position 上而不是在其组件上进行操作。 That makes it easier to reason about 2D code.这使得推理二维码变得更容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM