如何遍历点 (x, y) 上的有序方向?

How to iterate over ordinal directions over a point (x, y)?

下面这个函数叫做 findNeighboringChains(i, j)。你传入一个点 (x, y),它 returns 存在于相邻点 (x + 1, y), (x - 1, y), (x, y + 1) 中的所有链对象, 和 (x, y - 1)。如果 (x, y) 处不存在链,则 findChainId(x, y) = -1,否则它将 return ID >= 0。每个 (x, y) 处只能存在一条链。有关更多上下文,这是我用来在围棋游戏中查找单元格的相邻链的函数。

我觉得到目前为止我的内容有点冗长,但我不确定如何让它变得更好。如果我可以通过循环迭代这些点 (x + 1, y) .​​.. (x, y - 1) 似乎是理想的。有什么建议吗?

public ArrayList<Integer> findNeighboringChains(int i, int j) {
    ArrayList<Integer> neighboringChains = new ArrayList<>();

    int tmp = findChainId(i - 1, j);
    if (tmp != -1) {
        neighboringChains.add(tmp);
    }

    tmp = findChainId(i + 1, j);
    if (tmp != -1) {
        neighboringChains.add(tmp);
    }

    tmp = findChainId(i, j - 1);
    if (tmp != -1) {
        neighboringChains.add(tmp);
    }

    tmp = findChainId(i, j + 1);
    if (tmp != -1) {
        neighboringChains.add(tmp);
    }

    return neighboringChains;
}

一种方法是利用 Java 中内置的 Point 对象,并遍历点列表 - 每次调用相同的代码段。在我的 solution/refactoring 中,我创建了一个名为 "getNeighboringPoints(Point p)" 的新方法,用于检索四个相邻点。然后,在您的函数 findNeighboringChains 中,您可以使用 for-each 循环遍历该点列表。

您可以对这种模式进行多种变体,但您认为可以减少冗余的想法绝对是正确的。尝试遵循 DRY 原则总是一个好主意。

public ArrayList<Integer> findNeighboringChains(int i, int j) {
    ArrayList<Integer> neighboringChains = new ArrayList<>();

    Point p = new Point(i, j);
    List<Point> neighboringPoints = getNeighboringPoints(p);

    for (Point point : neighboringPoints) {
        int tmp = findChainId(point.x, point.y);
        if (tmp != -1) {
            neighboringChains.add(tmp);
        }
    }

    return neighboringChains;
}

/**
 * 
 * @param p
 *            The input point.
 * @return a list of points neighboring point p
 */
private List<Point> getNeighboringPoints(Point p) {
    ArrayList<Point> neighboringPoints = new ArrayList<Point>();
    neighboringPoints.add(new Point(p.x - 1, p.y));
    neighboringPoints.add(new Point(p.x + 1, p.y));
    neighboringPoints.add(new Point(p.x, p.y + 1));
    neighboringPoints.add(new Point(p.x, p.y - 1));
    return neighboringPoints;
}

上述方法的一个好处是,现在您可以稍后发现您可能需要对所有相邻点进行另一次操作,并且您可以重用方法 getNeighboringPoints()。

编辑:

另一种减少冗余的方法是使用 extract method 技术。

public ArrayList<Integer> findNeighboringChains(int i, int j) {
    ArrayList<Integer> neighboringChains = new ArrayList<>();

    int tmp = findChainId(i - 1, j);
    checkChain(neighboringChains, tmp);

    tmp = findChainId(i + 1, j);
    checkChain(neighboringChains, tmp);

    tmp = findChainId(i, j - 1);
    checkChain(neighboringChains, tmp);

    tmp = findChainId(i, j + 1);
    checkChain(neighboringChains, tmp);

    return neighboringChains;
}

private void checkChain(ArrayList<Integer> neighboringChains, int tmp) {
    if (tmp != -1) {
        neighboringChains.add(tmp);
    }
}

这可能会更好,因为它不会强制在尚未使用积分的项目上使用积分 class。 (当有一种方法使用点而其他所有方法都需要输入两个整数时,这可能会很烦人)。