2 votes

Comment puis-je simplifier ce code ? (Test d'obstruction d'un jeu d'échecs)

Je crée un jeu d'échecs en Java et je vérifie qu'aucune pièce ne bloque le chemin de la pièce déplacée. La pièce se déplace de (srcX,srcY) à (dstX,dstY).

J'ai écrit ce code qui vérifie s'il y a des obstructions pour une tour :

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

mais c'est un peu gros et je suis sûr que cela peut être simplifié des idées ?

ps, c'est UNIQUEMENT un test d'obstruction. J'ai déjà validé tout le reste.

4voto

marcog Points 39356

Une fois que vous avez testé la direction, vous pouvez définir les valeurs dx, dy (par exemple, dx=1, dy=0 pour l'est). Vous pouvez alors avoir une seule boucle for pour tous les cas et simplement incrémenter x et y de dx et dy respectivement à chaque itération.

Vous pouvez alors simplifier le contrôle de la direction comme suit :

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

Code :

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;

Sachez également que ce code (et le vôtre) échouera si le déplacement n'est pas horizontal, vertical ou diagonal.

2voto

NPE Points 169956

Vous pourriez faire quelque chose de ce genre (non testé car je n'ai pas de compilateur sous la main) :

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

0voto

PaulJWilliams Points 11641

D'abord, écrivez des tests. Beaucoup, beaucoup de tests. De cette façon, vous pouvez être sûr que vous simplifiez sans changer la signification du code.

Refactorer sans tests unitaires, c'est comme marcher sur un fil sans filet de sécurité.

0voto

multiholle Points 1128

Presque la même chose, mais avec des boucles 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;
}

0voto

Ralph Points 42744

Ma solution serait d'introduire une classe de direction, puis de faire la vérification de cette manière : isBlocked(startPossition, direction, numberOfFields)

J'ai fait un petit exemple, en utilisant 3 classes.

  • Direction - un enum pour représenter les 8 directions (2 horizontales, 2 verticales, 4 diagonales)
  • Position - la valeur x et y d'une position
  • LinarMove - représente un mouvement linéaire (startPosition, direction, numberOfFields) et contient la méthode isBlockedMethod.

L'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);
    }
}

La raison d'être du second constructeur est seulement qu'il permet d'écrire les mouvements diagonaux d'une manière plus lisible.

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

Le Move contient la méthode isBlocked - vous pouvez voir à quel point il devient petit et lisible. Au moins, il n'y a pas d'instruction if liée à une seule direction à gauche.

Le nom LinareMove suggère qu'il existe un autre type de mouvement pour le cavalier.

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

Et voici comment cela fonctionne :

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

Vous avez peut-être remarqué que le mouvement des cavaliers est une sorte de problème. Avec cette soultion, vous pouvez la modéliser de deux façons :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X