/* * 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 RecursiveDivision.java * @date Jan 7, 2015 */ package es.ull.mazesolver.maze.algorithm; import java.awt.Point; import es.ull.mazesolver.maze.MazeCreationAlgorithm; import es.ull.mazesolver.util.Direction; import es.ull.mazesolver.util.Pair; /** * Implementación de algoritmo Division Recursiva para la generación aleatoria * de laberintos perfectos. */ public class RecursiveDivision extends MazeCreationAlgorithm { private final static int HORIZONTAL = 0; private final static int VERTICAL = 1; /** * Constructor. Crea una nueva instancia de la clase. * * @param rows * Número de filas del laberinto. * @param columns * Número de columnas del laberinto. */ public RecursiveDivision (int rows, int columns) { super(rows, columns); for (int y = 0; y < m_rows; y++) for (int x = 0; x < m_columns; x++) for (int i = 1; i < Direction.MAX_DIRECTIONS; i++) { Direction dir = Direction.fromIndex(i); Point next = dir.movePoint(new Point(x, y)); if (next.y >= 0 && next.y < m_rows && next.x >= 0 && next.x < m_columns) m_maze.get(y).get(x).toggleWall(dir); } } /* * (non-Javadoc) * * @see es.ull.mazesolver.maze.MazeCreationAlgorithm#runCreationAlgorithm() */ @Override protected void runCreationAlgorithm () { divide(0, 0, m_columns, m_rows, chooseOrientation(m_columns, m_rows)); } /** * Función principal recursiva que va generando sub-laberintos. * * @param x * Posición en el eje X desde la que se quiere partir. * @param y * Posición en el eje Y desde la que se quiere partir. * @param width * Número de columnas del sub laberinto. * @param height * Número de filas del sub Laberinto. * @param orientation * Orientación a seguir para generar el sub laberinto */ private void divide (int x, int y, int width, int height, int orientation) { if (height > 1 && width > 1) { // Inicio del muro del sub laberinto int wx = x, wy = y; wx += (orientation == HORIZONTAL)? 0 : (int) (Math.random() * (width - 1)); wy += (orientation == HORIZONTAL)? (int) (Math.random() * (height - 1)) : 0; // Posicion de la puerta int px = wx, py = wy; px += (orientation == HORIZONTAL)? (int) (Math.random() * width) : 0; py += (orientation == HORIZONTAL)? 0 : (int) (Math.random() * height); // Direccion a la que moverse int dx = (orientation == HORIZONTAL)? 1 : 0; int dy = (orientation == HORIZONTAL)? 0 : 1; // Longitud del muro int length = (orientation == HORIZONTAL)? width : height; // Direccion donde dibujar el muro Direction dir = (orientation == HORIZONTAL)? Direction.DOWN : Direction.RIGHT; for (int i = 0; i < length; i++) { if (wx != px || wy != py) { Pair <Integer, Integer> desp = dir.decompose(); m_maze.get(wy).get(wx).setWall(dir); m_maze.get(wy + desp.second).get(wx + desp.first).setWall(dir.getOpposite()); } wx += dx; wy += dy; } int nx = x, ny = y; int w = (orientation == HORIZONTAL)? width : wx - x + 1; int h = (orientation == HORIZONTAL)? wy - y + 1 : height; divide(nx, ny, w, h, chooseOrientation(w, h)); nx = (orientation == HORIZONTAL)? x : wx + 1; ny = (orientation == HORIZONTAL)? wy + 1 : y; w = (orientation == HORIZONTAL)? width : x + width - wx - 1; h = (orientation == HORIZONTAL)? y + height - wy - 1 : height; divide(nx, ny, w, h, chooseOrientation(w, h)); } } /** * Función auxiliar para elegir la orientación por la que ir dividiendo el * laberinto * * @param width * Número de columnas del Laberinto. * @param height * Número de filas del laberinto. * @return Orientación a seguir para ir dividiendo el laberinto. */ private int chooseOrientation (int width, int height) { if (width < height) return HORIZONTAL; else if (height < width) return VERTICAL; else return (int) (Math.random() * 2); } }