/* * This file is part of MazeSolver. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Copyright (c) 2014 MazeSolver * Sergio M. Afonso Fumero <theSkatrak@gmail.com> * Kevin I. Robayna Hernández <kevinirobaynahdez@gmail.com> */ /** * @file Direction.java * @date 21/10/2014 */ package es.ull.mazesolver.util; import java.awt.Point; import java.io.Serializable; /** * Enum que representa una dirección de movimiento en 2D. Cada posible opción es * un flag, por lo que se pueden hacer operaciones de bit para representar * varias direcciones en la misma variable simultáneamente. */ public enum Direction implements Serializable { NONE ((short) 0x00), UP ((short) 0x01), DOWN ((short) 0x02), LEFT ((short) 0x04), RIGHT ((short) 0x08); /** * Número máximo de direcciones. */ public static int MAX_DIRECTIONS = 5; /** * Valor asociado a una dirección (campo de bits). */ public short val; private static Direction [] values = Direction.values(); private Direction (short val) { this.val = val; } /** * Transforma un short en dirección, comparando sus valores directamente. * * @param value * Valor (dentro de los valores posibles de dirección). * @return Dirección asociada a ese valor. */ public static Direction fromValue (short value) { for (Direction i: values) if (i.val == value) return i; return null; } /** * Devuelve la dirección asociada a un índice. * * @param index * Índice de la dirección. El orden es el siguiente: * <ol start="0"> * <li>NONE</li> * <li>UP</li> * <li>DOWN</li> * <li>LEFT</li> * <li>RIGHT</li> * </ol> * @return Dirección asociada al índice. */ public static Direction fromIndex (int index) { return values[index]; } /** * Extrae la dirección asociada al paso entre 2 posiciones contiguas. * * @param p1 * Posición de inicio. * @param p2 * Posición de destino. * @return La dirección que une los 2 puntos contiguos o {@code null} si los * puntos no están contiguos, */ public static Direction fromPoints (Point p1, Point p2) { Point diff = new Point(p2.x - p1.x, p2.y - p1.y); switch (diff.x) { case -1: // izquierda return diff.y == 0? Direction.LEFT : null; case 1: // derecha return diff.y == 0? Direction.RIGHT : null; case 0: // misma posición en X switch (diff.y) { case -1: // arriba return Direction.UP; case 1: // abajo return Direction.DOWN; case 0: // misma posición return Direction.NONE; } default: return null; } } /** * Crea una dirección de forma aleatoria. * * @return Una dirección aleatoria. No va a ser {@code Direction.NONE}. */ public static Direction random () { return values[1 + (int) (Math.random() * 4.0)]; } /** * Descompone la dirección en sus componentes x e y, con una magnitud de 1. * * @return Pareja con la descomposición de la dirección (x, y). */ public Pair <Integer, Integer> decompose () { Pair <Integer, Integer> p = new Pair <Integer, Integer>(0, 0); switch (this) { case NONE: break; case UP: p.second = -1; break; case DOWN: p.second = 1; break; case LEFT: p.first = -1; break; case RIGHT: p.first = 1; break; } return p; } /** * Invierte la posición actual. * * @return Dirección contraria de la actual. */ public Direction getOpposite () { switch (this) { case UP: return DOWN; case DOWN: return UP; case LEFT: return RIGHT; case RIGHT: return LEFT; default: return NONE; } } /** * Rota la dirección absoluta actual en el sentido indicado. * * @param rot * Sentido de rotación que aplicar. * @return La nueva dirección rotada. */ public Direction rotate (Rotation rot) { switch (this) { case UP: return rot == Rotation.CLOCKWISE? RIGHT : LEFT; case DOWN: return rot == Rotation.CLOCKWISE? LEFT : RIGHT; case LEFT: return rot == Rotation.CLOCKWISE? UP : DOWN; case RIGHT: return rot == Rotation.CLOCKWISE? DOWN : UP; default: return NONE; } } /** * Desplaza un punto en la dirección y lo guarda en un punto nuevo. * * @param p * Punto que se desea mover en esta dirección. * @return Nuevo punto equivalente al indicado desplazado en esta dirección. */ public Point movePoint (final Point p) { Pair <Integer, Integer> desp = decompose(); return new Point(p.x + desp.first, p.y + desp.second); } /** * @return Si la dirección es vertical. */ public boolean isVertical () { return this == UP || this == DOWN; } /** * @return Si la dirección es horizontal. */ public boolean isHorizontal () { return this == LEFT || this == RIGHT; } }