如何简化此代码? (国际象棋游戏障碍测试)

时间:2010-11-30 16:03:44

标签: java algorithm

我正在用Java制作国际象棋游戏,并进行测试以确保没有任何碎片阻挡被移动的棋子的路径。这件作品从(srcX,srcY)移动到(dstX,dstY)。

我写过这段代码,检查车上是否有任何障碍物:

    if(dstY == srcY) {

            // No change on Y axis, so moving east or west

            if(dstX > srcX) {
                // Moving east
                // Test every cell the piece will pass over
                for(int x = srcX+1; x < dstX; x++) {
                    // Is the cell set?
                    if(isPiece(x, srcY)) {
                        return true;
                    }
                }
            } else {
                // Must be moving west
                // Test every cell the piece will pass over
                for(int x = srcX-1; x > dstX; x--) {
                    // Is the cell set?
                    if(isPiece(x, srcY)) {
                        return true;
                    }
                }
            }

        } else if(dstX == srcX) {

            // No change on X axis, so moving north or south

            if(dstY > srcY) {
                // Moving north
                // Test every cell the piece will pass over
                for(int y = srcY+1; y < dstY; y++) {
                    // Is the cell set?
                    if(isPiece(srcX, y)) {
                        return true;
                    }
                }
            } else {
                // Must be moving south
                // Test every cell the piece will pass over
                for(int y = srcY-1; y > dstY; y--) {
                    // Is the cell set?
                    if(isPiece(srcX, y)) {
                        return true;
                    }
                }
            }
        }

但它有点大,我确信它可以简化......任何想法?

ps,这只是阻碍测试。我已经验证了其他所有内容。

5 个答案:

答案 0 :(得分:4)

一旦测试了方向,就可以设置dx,dy值(例如dx = 1,dy = 0表示东方)。然后你可以为所有情况都有一个for循环,并且在每次迭代时分别用dx和dy递增x和y。

然后,您可以将方向检查简化为以下内容:

if dstY == srcY: dy = 0
else: dy = (dstY - srcY) / abs(dstY - srcY)
if dstX == srcX: dx = 0
else: dx = (dstX - srcX) / abs(dstX - srcX)

代码:

int dx, dy;
if (dstY == srcY) dy = 0;
else dy = (dstY - srcY) / Math.abs(dstY - srcY);
if (dstX == srcX) dx = 0;
else dx = (dstX - srcX) / Math.abs(dstX - srcX);

while (srcX != dstX || srcY != dstY) {
  srcX += dx; srcY += dy;
  if (isPiece(srcX, srcY))
    return true;
}
return false;

另外请注意,如果移动不是水平,垂直或对角线,此代码(和您的代码)将失败。

答案 1 :(得分:2)

你可以沿着这些方向做一些事情(未经测试,因为我没有编译器可用):

int dx = 0;
int dy = 0;
if (dstX != srcX) {
  dx = (dstX > srcX) ? 1 : -1;
} else if (dstY != srcY) {
  dy = (dstY > srcY) ? 1 : -1;
}
int x = srcX + dx;
int y = srcY + dy;
while (x != dstX || y != dstY) {
  if (isPiece(x, y)) return true;
  x += dx;
  y += dy;
}

答案 2 :(得分:0)

首先,编写测试。大量的测试。这样,您可以确信在不改变代码含义的情况下进行简化。

没有单元测试的重构就像在没有安全网的情况下走高线。

答案 3 :(得分:0)

几乎相同,但有for循环:

// move along x axis
for (int x = 1; x < Math.abs(srcX - dstX); x++) {
    int curX = (srcX - dstX) < 0 ? srcX - x : srcX + x;
    if (isPiece(curX, srcY))
        return true;
}   
// move along y axis
for (int y = 1; y <= Math.abs(srcY - dstY); y++) {
    int curY = (srcY - dstY) < 0 ? srcY - y : srcY + y;
    if (isPiece(srcX, curY))
        return true;
}

答案 4 :(得分:0)

我的灵魂将是:引入一个方向类,然后以这种方式进行检查: isBlocked(startPossition,direction,numberOfFields)

我做了一个小例子,使用了3个类。

  • 方向 - 表示8个方向的枚举(2个水平,2个垂直,4个对角线)
  • 位置 - 位置的x和y值
  • LinarMove - 表示一个线性Move(startPossition,direction,numberOfFields)并包含isBlockedMethod

The Enum:

public enum Direction {

    UP(0, 1),
    DOWN(0, -1),
    LEFT(1, 0),
    RIGHT(-1, 0),

    UP_LEFT(UP, LEFT),
    UP_RIGTH(UP, RIGHT),
    DOWN_LEFT(DOWN, LEFT),
    DOWN_RIGHT(
            DOWN, RIGHT);

    private final int incrementX;
    private final int incrementY;


    private Direction(int incrementX, int incrementY) {
        this.incrementX = incrementX;
        this.incrementY = incrementY;
    }

    private Direction(Direction sub1, Direction sub2) {
        this.incrementX = sub1.incrementX + sub2.incrementX;
        this.incrementY = sub1.incrementY + sub2.incrementY;
    }

    public Position oneField(Position start) {
        return new Position(start.getX() + this.incrementX, start.getY()
                + this.incrementY);
    }
}

第二个构造函数的唯一之处仅在于它能够以更易读的方式编写对角线移动。

public class Position {
    private final int x;
    private final int y;

    public Position(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public String toString() {
        return "x:" + x + ", y:" + y;
    }
}

Move包含isBlocked方法 - 您可以看到它有多小,以及它的可读性。如果声明离开,至少没有单一方向相关。

LinareMove这个名字表明,骑士可能会采取其他行动。

public class LinearMove {

    private final Position start;
    private final Direction direction;

    /** Length of the move. */
    private final int numberOfFields;

    public LinearMove(Position start, Direction direction, int numberOfFields) {
        super();
        this.start = start;
        this.direction = direction;
        this.numberOfFields = numberOfFields;
    }

    boolean isBlocked() {
        Position pos = this.start;
        for (int i = 0; i < (this.numberOfFields - 1); i++) {
            pos = this.direction.oneField(pos);
            if (isPiece(pos)) {
                return true;
            }
        }
        return false;
    }

    boolean isPiece(Position pos) {
        //Dummy;
        System.out.println(pos);
        return false;
    }   
}

这就是它的工作原理:

    public static void main(String[] args) {
    new LinearMove(new Position(1, 1), Direction.RIGHT, 3).isBlocked();
    }

你可能会注意到,骑士的移动是某种形式的探测。有了这种灵魂,你可以用两种方式对它进行建模:

- 4 special Directions
- an other kind of move class (this is the more cleaner way, because you could always return true, in the isBockedMethod)