/* * 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 RecursiveAgent.java * @date Jan 4, 2015 */ package es.ull.mazesolver.agent; import java.awt.Color; import java.awt.Point; import java.io.IOException; import java.io.ObjectInputStream; import java.util.Stack; import es.ull.mazesolver.gui.configuration.AgentConfigurationPanel; import es.ull.mazesolver.gui.configuration.SimpleAgentConfigurationPanel; import es.ull.mazesolver.gui.environment.Environment; import es.ull.mazesolver.maze.Maze; import es.ull.mazesolver.maze.MazeCell; import es.ull.mazesolver.util.Direction; /** * Agente que implementa el comportamiento del algoritmo recursivo con * backtracking. Siempre intenta moverse al lugar que no ha visitado. En el peor * de los casos hace un recorrido por todo el laberinto. */ public class RecursiveAgent extends Agent { private static final long serialVersionUID = 1L; private transient boolean m_backtracking; private transient Stack <Direction> m_stack; private transient boolean [][] m_visited; /** * Crea el agente en el entorno indicado. * * @param env * Entorno en el que se quiere colocar. */ public RecursiveAgent (Environment env) { super(env); m_stack = new Stack <Direction>(); } /* * (non-Javadoc) * * @see agent.Agent#setEnvironment(gui.environment.Environment) */ @Override public void setEnvironment (Environment env) { super.setEnvironment(env); Maze maze = env.getMaze(); m_visited = new boolean [maze.getHeight()] [maze.getWidth()]; } /* * (non-Javadoc) * * @see agent.Agent#getAlgorithmName() */ @Override public String getAlgorithmName () { return "Recursive Backtracking"; } /* * (non-Javadoc) * * @see es.ull.mazesolver.agent.Agent#getAlgorithmColor() */ @Override public Color getAlgorithmColor () { return Color.YELLOW; } /* * (non-Javadoc) * * @see agent.Agent#getNextMovement() */ @Override public Direction getNextMovement () { Direction dir = selectDirection(); if (dir == Direction.NONE && !m_stack.empty()) { Direction head = m_stack.peek().getOpposite(); if (m_env.movementAllowed(m_pos, head)) { m_backtracking = true; dir = m_stack.pop().getOpposite(); } } return dir; } /* * (non-Javadoc) * * @see agent.Agent#doMovement(maze.Direction) */ @Override public void doMovement (Direction dir) { Point prev = m_pos; m_visited[m_pos.y][m_pos.x] = true; super.doMovement(dir); if (!prev.equals(m_pos)) { if (!m_backtracking) m_stack.push(dir); else m_backtracking = false; } } /* * (non-Javadoc) * * @see agent.Agent#setPosition(java.awt.Point) */ @Override public void setPosition (Point pos) { resetMemory(); super.setPosition(pos); }; /* * (non-Javadoc) * * @see agent.Agent#resetMemory() */ @Override public void resetMemory () { m_stack.clear(); for (int i = 0; i < m_visited.length; i++) { for (int j = 0; j < m_visited[i].length; j++) m_visited[i][j] = false; } } /* * (non-Javadoc) * * @see agent.Agent#getConfigurationPanel() */ @Override public AgentConfigurationPanel getConfigurationPanel () { return new SimpleAgentConfigurationPanel(this); } /* * (non-Javadoc) * * @see agent.Agent#clone() */ @Override public Object clone () { RecursiveAgent ag = new RecursiveAgent(m_env); ag.setAgentColor(getAgentColor()); return ag; } /** * Elige la dirección que le lleva a una no visitada que no tiene una pared * delante. * * @return La dirección seleccionada. Devuelve {@code Direction.NONE} si no * hay ninguna celda adyacente accesible no visitada. */ private Direction selectDirection () { Point exit = m_env.getMaze().getExit(); for (int i = 1; i < Direction.MAX_DIRECTIONS; i++) { Direction dir = Direction.fromIndex(i); Point next = dir.movePoint(m_pos); if (next.equals(exit)) return dir; else if (look(dir) == MazeCell.Vision.EMPTY && !m_visited[next.y][next.x]) { return dir; } } return Direction.NONE; } /** * Extrae la información del objeto a partir de una forma serializada del * mismo. * * @param input * Flujo de entrada con la información del objeto. * @throws ClassNotFoundException * Si se trata de un objeto de otra clase. * @throws IOException * Si no se puede leer el flujo de entrada. */ private void readObject (ObjectInputStream input) throws ClassNotFoundException, IOException { input.defaultReadObject(); m_stack = new Stack <Direction>(); } }