Как я могу упростить этот код? (Тестирование препятствий в шахматной игре) - PullRequest
2 голосов
/ 30 ноября 2010

Я делаю шахматную игру на 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 ]

4 голосов
/ 30 ноября 2010

После того как вы проверили направление, вы можете установить значения dx, dy (например, dx = 1, dy = 0 для востока). Тогда вы можете иметь один цикл for для всех случаев и просто увеличивать x и y на dx и dy соответственно на каждой итерации.

Затем вы можете упростить проверку направления следующим образом:

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;

Также помните, что этот код (и ваш) не будет работать, если перемещение не горизонтальное, вертикальное или диагональное.

2 голосов
/ 30 ноября 2010

Вы могли бы сделать что-то вроде этого (не проверено, так как у меня нет компилятора):

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;
}
0 голосов
/ 30 ноября 2010

Моя мысль была бы: ввести класс направления, а затем выполнить проверку в этом стиле: isBlocked (startPossition, direction, numberOfFields)

Я сделал небольшой пример, используя 3 класса.

  • Направление - перечисление для представления 8 направлений (2 по горизонтали, 2 по вертикали, 4 по диагонали)
  • Позиция - значение x и y для позиции
  • LinarMove - представляетодин линейный Move (startPossition, direction, numberOfFields) и содержит isBlockedMethod

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)
0 голосов
/ 30 ноября 2010

Почти то же самое, но с циклами 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;
}
0 голосов
/ 30 ноября 2010

Сначала напишите тесты. Много-много тестов. Таким образом, вы можете быть уверены, что упрощаете, не меняя смысла кода.

Рефакторинг без юнит-тестов похож на хождение по проволоке без защитной сетки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...