/*
* 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 Agent.java
* @date 21/10/2014
*/
package es.ull.mazesolver.agent;
import java.awt.Color;
import java.awt.Point;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import es.ull.mazesolver.gui.MainWindow;
import es.ull.mazesolver.gui.configuration.AgentConfigurationPanel;
import es.ull.mazesolver.gui.environment.Environment;
import es.ull.mazesolver.maze.MazeCell;
import es.ull.mazesolver.util.Direction;
/**
* Clase que representa un agente abstracto que se encuentra en algún laberinto.
* Sus subclases implementan los distintos algoritmos para resolver laberintos.
* <br><br>
* Cada agente debe implementar los métodos de serialización para poder
* guardarse y cargarse correctamente, en caso de que requiriesen configuración
* adicional a la genérica.
*/
public abstract class Agent implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private static int s_agent_count = 0;
private transient int m_agent_id;
private transient String m_name;
private Color m_color;
/**
* Entorno en el que reside el agente.
*/
protected transient Environment m_env;
/**
* Posición en la que se encuentra el agente.
*/
protected transient Point m_pos;
/**
* Crea un nuevo agente en el entorno. Le asigna un ID único y lo coloca en el
* punto (0,0).
*
* @param env
* Entorno al que va a ser asignado dicho agente.
*/
protected Agent (Environment env) {
m_agent_id = s_agent_count++;
m_name = getAlgorithmName() + " " + String.valueOf(m_agent_id);
m_color = getAlgorithmColor();
m_pos = new Point();
setEnvironment(env);
}
/**
* Establece la posición del agente.
* <br><br>
* Este método se puede sobrecargar en las clases derivadas para mantener
* coherente la memoria de la que disponga el mismo.
*
* @param pos
* Nueva posición del agente.
*/
public void setPosition (Point pos) {
m_pos.x = pos.x;
m_pos.y = pos.y;
}
/**
* Obtiene la posición en el eje X del agente.
*
* @return Posición en el eje X del agente.
*/
public int getX () {
return m_pos.x;
}
/**
* Obtiene la posición en el eje Y del agente.
*
* @return Posición en el eje Y de agente.
*/
public int getY () {
return m_pos.y;
}
/**
* Obtiene la posición del agente.
*
* @return Posición del agente.
*/
public Point getPos () {
return new Point(m_pos);
}
/**
* Cambia el entorno en el que se sitúa el agente.
* <br><br>
* Este método debería sobrecargarse en las clases derivadas que contengan
* información acerca del camino a seguir por el agente (un plan) de forma que
* éste siga siendo coherente tras el cambio de laberinto.
*
* @param env
* Entorno donde colocar el agente.
*/
public void setEnvironment (Environment env) {
if (env != null)
m_env = env;
else
throw new IllegalArgumentException(
MainWindow.getTranslations().exception().invalidEnvironment());
}
/**
* Obtiene el entorno en el que se encuentra el agente.
*
* @return Entorno en el que se encuentra el agente.
*/
public Environment getEnvironment () {
return m_env;
}
/**
* Obtiene la visión que tiene el agente al mirar en la dirección indicada.
*
* @param dir
* Dirección hacia la que mirar.
* @return Lo que vería el agente si mira en la dirección especificada.
*/
public MazeCell.Vision look (Direction dir) {
return m_env.look(m_pos, dir);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals (Object obj) {
return this == obj;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode () {
return m_env.hashCode();
}
/**
* Hace que el agente realice el movimiento especificado, sin comprobar que se
* trata de un movimiento válido.
* <br><br>
* La clase base sólo cambia la posición del agente, si se desea más
* funcionalidad, se debe sobrecargar en las clases derivadas.
*
* @param dir
* Dirección hacia la que mover el agente.
*/
public void doMovement (Direction dir) {
m_pos = dir.movePoint(m_pos);
}
/**
* Cambia el nombre del agente.
*
* @param name
* Nombre del agente.
*/
public void setAgentName (String name) {
if (name != null && !name.isEmpty())
m_name = name;
}
/**
* Pregunta al agente el nombre que le identifica.
*
* @return Nombre identificador del agente. Por defecto incluye el nombre del
* algoritmo que implementa.
*/
public String getAgentName () {
return m_name;
}
/**
* Cambia el color del agente.
*
* @param color
* Nuevo color del agente.
*/
public void setAgentColor (Color color) {
if (color != null)
m_color = color;
}
/**
* Pregunta al agente su color.
*
* @return El color del agente.
*/
public Color getAgentColor () {
return m_color;
}
/**
* Carga la descripción serializada del agente de un fichero, lo crea y lo
* devuelve.
*
* @param filename
* Nombre del fichero de entrada.
* @param env
* Entorno en el que cargar el agente.
* @return El agente creado.
* @throws IOException
* Si no es posible leer el fichero.
*/
public static Agent loadFile (String filename, Environment env) throws IOException {
try {
Agent ag;
FileInputStream file_in = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(file_in);
ag = (Agent) in.readObject();
in.close();
file_in.close();
ag.m_agent_id = s_agent_count++;
ag.m_name = ag.getAlgorithmName() + " " + String.valueOf(ag.m_agent_id);
ag.m_pos = new Point();
ag.setEnvironment(env);
return ag;
}
catch (ClassNotFoundException c) {
throw new IOException(c);
}
}
/**
* Guarda la instancia del agente en un fichero utilizando su serialización.
*
* @param filename
* Nombre del fichero de salida.
* @throws IOException
* Si no es posible guardar el fichero.
*/
public void saveFile (String filename) throws IOException {
FileOutputStream file_out = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(file_out);
out.writeObject(this);
out.close();
file_out.close();
}
/**
* Pregunta al agente el nombre del algoritmo que implementa.
*
* @return Nombre del algoritmo que implementa.
*/
public abstract String getAlgorithmName ();
/**
* Pregunta al agente el color por defecto de los agentes de su tipo.
*
* @return Color por defecto de los agentes que implementan ese algoritmo.
*/
public abstract Color getAlgorithmColor ();
/**
* Obtiene el siguiente movimiento dado el estado actual del agente.
*
* @return La dirección en la que el agente quiere realizar el siguiente
* movimiento.
*/
public abstract Direction getNextMovement ();
/**
* Elimina la memoria que el agente tenga sobre el entorno. No elimina su
* configuración, sino que lo deja en el estado inicial.
*/
public abstract void resetMemory ();
/**
* Obtiene el panel de configuración asociado al agente.
*
* @return Un panel de configuración para el agente.
*/
public abstract AgentConfigurationPanel getConfigurationPanel ();
/*
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
public abstract Object clone ();
}