Package core.simulation

Source Code of core.simulation.Simulation

package core.simulation;

import gui.EasyBotAppException;

import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Vector;

import org.apache.commons.io.FileUtils;
import org.xml.sax.SAXException;

import resources.digesters.ClassManager;
import resources.digesters.Factory;
import resources.digesters.Plugin;
import utils.ColorVectorMap;
import utils.Semaphore;
import utils.defines.Defines;
import utils.images.RecognizedShape;
import utils.logging.Logger;

import components.gps.GPS;
import components.robot.Playable;
import components.robot.Robot;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;

/**
* Esta clase representa una simulaci�n de robots en un escenario. Contiene
* un arreglo con todos los robots que participan en la simulaci�n, como
* tambi�n, informaci�n relacionada al <i>timing</i> de la ejecuci�n.<br><br>
*
* Solo se permite una �nica simulaci�n por vez (no deber�an existir dos o
* m�s instancias simult�neamente). Antes de crear una nueva instancia
* <code>Simulation</code> deber�n liberarse todos los recursos de la
* simulaci�n anterior, invocando al m�todo {@link #dispose() dispose}.
* En cualquier momento podr� obtenerse una referencia a la simulaci�n actual
* mediante la invocaci�n del m�todo {@link #getCurrent() getCurrent}.<br><br>
*
* Implementa la interfaz <code>Playable</code> junto con los controles
* de ejecuci�n.<br><br>
*
* Esta clase no puede ser extendida.
*/
public final class Simulation implements Playable
{
  // Mantiene la instancia actual.
  private static Simulation    simulation;
 
  private Vector           robots;
  private GPS            gps; 
  private int            type;
  private String          baseSimulationDirectory;
  private String          name;
  private String          comment;
  private int[][]         places;
  private int[]          place;
  private int            targetPlace;
  private long          stepTime;
  private boolean          playbackSimualtion;         
  private long          duration;
  private boolean          allOk;
  private ColorVectorMap       colorVectorMap;
  private Semaphore        serialTurn = new Semaphore(1);
  private Semaphore        realRobotTurn = new Semaphore(0);
    private Shell          theShell;
 
  /**
   * Construye una nueva simulaci�n, sin robots, y con un tiempo de paso
   * de {@link Defines#DEFAULT_STEP_TIME Defines.DEFAULT_STEP_TIME}
   * milisegundos.
   */
  public Simulation()
  {
    baseSimulationDirectory    = null;
    robots            = new Vector();
    simulation          = this;
    playbackSimualtion      = true;
    places            = null;
    place            = new int[Defines.MAX_PLACES];
    stepTime          = Defines.DEFAULT_STEP_TIME;
    duration          = 0;
    setAllOk(false);
  }
 
  public Semaphore getSerialTurn() {
    return serialTurn;
  }
 
  public void setShell(Shell shell) {
    theShell = shell;
  }
 
  public Semaphore getRealRobotTurn() {
    return realRobotTurn;
  }
 
  /**
   * Establece el tipo de simulaci�n, que debe pertencer a los definidos
   * en {@link utils.defines.Defines utils.defines.Defines}.
   * @param t  tipo de simulaci�n.
   */
  public void setType(int t)
  {
    type = t;
  }
 
 
  /**
   * Retorna el tipo de simulaci�n.
   * @return  tipo de simulaci�n, definido en
   *       {@link utils.defines.Defines utils.defines.Defines}.
   */
  public int getType()
  {
    return type;
  }
 
 
  /**
   * Agrega un nuevo robot a la simulaci�n.
   * @param robot  robot a agregar.
   */
  public void addRobot(Object robot)
  {
    robots.addElement(robot);
  }
 
 
  /**
   * Retorna la lista de robots que integran la simulaci�n.
   * @return lista de robots.
   */
  public Vector getRobotArray()
  {
    return robots;
  }

 
  /**
   * Retorna una referencia al robot (perteneciente a la simulaci�n) cuyo
   * nombre es <code>name</code>, o <code>null</code> si no existe.
   * @param name  nombre (un�voco) del robot a buscar.
   * @return    referencia al robot, o <code>null</code> si no existe.
   */
  public Robot getRobotByName(String name)
  {
    if (robots!= null)
      for (int i=0; i<robots.size(); i++)
        if (((Robot)robots.get(i)).getName().compareToIgnoreCase(name) == 0)
          return (Robot)robots.get(i);
    return null;
  }

 
  /**
   * Elimina de la simulaci�n el robot indicado por par�metro, y retorna
   * <code>true</code> si tuvo �xito, o <code>false</code> si el robot no
   * exist�a.
   * @param robot    referencia al robot a eliminar.
   * @return      <code>true</code> si tuvo �xito, o <code>false</code>
   *           si no exist�a.
   */
  public boolean removeRobot(Object robot)
  {
    return robots.removeElement(robot);
  }
 
  public void removeAllRobots()
  {
    robots.removeAllElements();
  }
  /**
   * Retorna una referencia a la simulaci�n actual.
   * @return  referencia a la simulaci�n actual, o <code>null</code> si no
   *       existe una simulaci�n creada.
   */
  public static Simulation getCurrent()
  {
    return simulation;
  }
 
 
  /**
   * Libera los recursos de la simulaci�n. Este m�todo deber� invocarse
   * antes de crear una nueva simulaci�n.
   */
  public void dispose()
  {
    for (int i=0; robots != null  && i<robots.size(); i++)
      if ( ! ((Robot)robots.get(i)).isDisposed() )
        ((Robot)robots.get(i)).dispose();
   
    if ( gps != null  && !gps.isDisposed() )
      gps.dispose();
   
    simulation = null;
  }
 
 
  public boolean isDisposed()
  {
    return ( simulation == null );
  }


  /**
   * Establece el <i>tiempo de paso</code>, que es el per�odo que insume
   * la simulaci�n para pasar de un estado al siguiente. Cambios en este
   * valor permiten ejecutar la simulaci�n a diferentes velocidades (a
   * menor <i>tiempo de paso</code>, mayor velocidad de ejecuci�n).
   * @param sT  tiempo de paso en milisegundos.
   */
  public void setStepTime(long sT)
  {
    stepTime = sT;
  }

 
  /**
   * Retorna el <i>tiempo de paso</code> de la simulaci�n.
   * @return tiempo de paso en milisegundos.
   */
  public long getStepTime()
  {
    return stepTime;
  }
 
 
  /**
   * Permite establecer cu�l es el <i>lugar objetivo</i> de la simulaci�n.
   * Los robots pertenecientes a la simulaci�n deber�n navegar el escenario
   * hasta alcanzar un destino, que est� identificado por el par�metro
   * <code>targetPlace</code>.<br><br>
   * Esto aplica, principalmente, a la exploraci�n de laberintos.
   * @param targetPlace  id del lugar objetivo.
   */
  public void setTargetPlace(int targetPlace)
  {
    this.targetPlace = targetPlace;
  }
 
 
  /**
   * Retorna el <i>lugar objetivo</i> de la simulaci�n.
   * @return id del lugar objetivo.
   */
  public int getTargetPlace()
  {
    return targetPlace;
  }
 
 
  /**
   * Define un posible <i>camino</i> (bidireccional) entre los lugares
   * <code>fromPlace</code> y <code>toPlace</code>. Esto significa que,
   * en un escenario, los robots podr�n desplazarse entre esos lugares,
   * en cualquier sentido.<br><br>
   * Esto aplica, principalmente, a la exploraci�n de laberintos.
   * @param fromPlace  lugar desde donde puede alcanzarse <code>toPlace</code>.
   * @param toPlace  lugar desde donde puede alcanzarse <code>fromPlace</code>.
   */
  public void setPlace(int fromPlace, int toPlace)
  {
    if ( places == null )
    {
      int nPlaces  =Simulation.getCurrent().getGps().getMazeItems().recognizedColoredIcons.length;
      places = new int[nPlaces][nPlaces];
     
      for (int i=0; i<nPlaces; i++)
        for (int j=0; j<nPlaces; j++)
          places[i][j] = 0;
    }
   
    if ( places[fromPlace-1][toPlace-1] == 0 )
    {
      places[fromPlace-1][toPlace-1] = 1;
    }
  }
  public void setPlaces(Places places)
  {
    this.places = places.getPlaces();
  }
 
  /**
   * Retorna la matriz de caminos (conexiones) entre los lugares que conforman
   * el escenario. Esta matriz es cuadrada, de N por N (siendo N la cantidad
   * de lugares), con valores 0 � 1. Si el elemento (i,j) es 0, significa que
   * no se puede transitar directamente entre los lugares i y j. Si el
   * elemento (i,j) es 1, entonces existe un camino directo entre ambos
   * lugares.<br><br>
   * Esto aplica, principalmente, a la exploraci�n de laberintos.
   * @return matriz de conexiones.
   */
  public int[][] getPlaces()
  {
    return places;
  }


  /**
   * Determina el lugar actual en que se haya un robot, en base a los colores
   * que se perciben desde all�.<br><br>
   * Esto aplica, principalmente, a la exploraci�n de laberintos.
   * @param identifiers    colores percibidoes desde el lugar actual.
   * @return          id del lugar actual o <code>ERROR</code> si
   *               no se pudo resolver.
   */
  public int getPlace(Color[] identifiers)
  {
    int i, j, placeId;
    boolean encontrado;
   
    if ( identifiers == null )
    {
      Logger.error( "Error resolviendo el lugar en getPlace(): identificadores nulos." );
      return Defines.ERROR;
    }

    if (Simulation.getCurrent().getGps().getMazeItems() == null  ||   Simulation.getCurrent().getGps().getMazeItems().recognizedColoredIcons == null )
    {
      Logger.error( "No se pudieron obtener los �conos coloreados del GPS." );
      return Defines.ERROR;
    }

    RecognizedShape[] icons = Simulation.getCurrent().getGps().getMazeItems().recognizedColoredIcons;
   
    for (i=0; i<icons.length; i++)
    {
      placeId = Integer.valueOf( icons[i].shapeId ).intValue();
     
      encontrado = false;
      for (j=0; !encontrado  &&  j<identifiers.length; j++)
        if ( icons[i].color.equals( identifiers[j] ) )
          encontrado = true;
     
      if ( encontrado )
        place[placeId-1] = 1;
      else
        place[placeId-1] = 0;
    }
   
   
    encontrado = false;
    for (i=0; !encontrado  &&  i<places.length; i++)
    {
      for (j=0; j<places[i].length; j++)
        if ( i != j  &&  places[i][j] != place[j] )
          break;
         
      if ( j == places[i].length)
        encontrado = true;
    }

    if ( encontrado )
      return i;
    else
      return Defines.ERROR;
  }

 
  /**
   * Elimina de la simulaci�n todos los lugares y conexiones entre ellos.
   */
  public void removePlaces()
  {
    places = null;
  }
 

  public synchronized void play()
  {
    for (int i=0; i<robots.size(); i++)
      ((Robot)robots.get(i)).play();
  }


  public synchronized void pause()
  {
    for (int i=0; i<robots.size(); i++)
      ((Robot)robots.get(i)).pause();
  }

    public void infoMessage(String message) {
      MessageBox messageBox = new MessageBox(this.theShell, SWT.OK
      | SWT.ICON_INFORMATION);
    messageBox.setMessage(message);
    messageBox.setText("Informacion de EasyBot");
    messageBox.open();
    return;
    }
     
  public synchronized void stop()
  {
    for (int i=0; i<robots.size(); i++)
      ((Robot)robots.get(i)).stop();
   
    for (int i=0; i<robots.size(); i++)
      ((Robot)robots.get(i)).join();
  }


  public synchronized boolean canPlay()
  {
    // TODO Auto-generated method stub
    return false;
  }


  public synchronized boolean isPlaying()
  {
    // TODO Auto-generated method stub
    return false;
  }


  /**
   * Establece la ubicaci�n en la cual se almacenar�n todos los datos
   * persistentes y de configuraci�n de la simulaci�n.
   * @param dir ruta en donde se almacenar� la simulaci�n.
   */
  public void setBaseSimulationDirectory(String dir)
  {
    // TODO: qu� pasa si el directorio no existe ???
    baseSimulationDirectory = new String( dir + "\\" );
  }


  /**
   * Retorna la ruta en donde se almacena la simulaci�n.
   * @return ruta.
   */
  public String getBaseSimulationDirectory()
  {
    return baseSimulationDirectory;
  }
 
 
  /**
   * Almacena la configuraci�n de la simulaci�n, en la ubicaci�n indicada
   * por {@link #setBaseSimulationDirectory(String) setBaseSimulationDirectory}.
   * @throws EasyBotAppException
   */
  public void saveSimulationConfig() throws EasyBotAppException
  {

    try
    {
      File xmlFile  = new File( Simulation.getCurrent().getBaseSimulationDirectory() + "/simulation.xml" );
      File rulesFile  = new File( "src/core/simulation/simulation-rules.xml" );
      File simDir   = new File( Simulation.getCurrent().getBaseSimulationDirectory() );
     
      //PrintWriter xmlWriter = new PrintWriter(new FileOutputStream(Simulation.getCurrent().getBaseSimulationDirectory()+ "/simulation.xml"));
      PrintWriter xmlWriter = new PrintWriter( new FileOutputStream(xmlFile) );
     
      xmlWriter.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
      xmlWriter.println("<simulation name=\""+this.getName()+"\" >");
      xmlWriter.println("\t<path>"+ this.getBaseSimulationDirectory()+"</path>");
      xmlWriter.println("\t<type>"+this.getType()+"</type>");
      xmlWriter.println("\t<comment>"+this.getComment()+"</comment>");
      xmlWriter.println("\t<steptime>"+this.getStepTime()+"</steptime>");
     
      // Bloques XML correspondientes a los robots y GPS.
      for (int i=0; i<this.getRobotArray().size();i++)
      {
        String file =((Robot)this.getRobotArray().get(i)).getXMLConfigFile();
        xmlWriter.println("\t<robot>");
        xmlWriter.println("\t\t<xmlfile>"+this.getBaseSimulationDirectory()+"\\components\\"+file+"</xmlfile>");
        Plugin robot = ClassManager.getInstance().getPluginByName(((Robot)this.getRobotArray().get(i)).getClass().getCanonicalName());
        xmlWriter.println("\t\t<xml-rules>"+robot.getContext().getPath()+robot.getXmlRulesFile()+"</xml-rules>");
        xmlWriter.println("\t</robot>");
      }
     
      xmlWriter.println("\t<gps>");
      xmlWriter.println("\t\t<xmlfile>"+this.getBaseSimulationDirectory()+"\\components\\gps.xml</xmlfile>");
      Plugin gps = ClassManager.getInstance().getPluginByName(Simulation.getCurrent().getGps().getClass().getCanonicalName());
      xmlWriter.println("\t\t<xml-rules>"+gps.getContext().getPath()+gps.getXmlRulesFile()+"</xml-rules>");
      xmlWriter.println("\t</gps>");
     
      // Bloques XML correspondientes a los lugares ("places").
      xmlWriter.println("\t<places>");
      for (int i=0;i<places.length;i++)
      {
        String row= new String();
        for (int j=0;j<places[i].length;j++)
          row = row.concat(places[i][j] + Places.COLUMN_DELIMITER);
        xmlWriter.println("\t\t<place>" + row + "</place>");
      }
      xmlWriter.println("\t</places>");
      xmlWriter.println("</simulation>");
      xmlWriter.close();
     
      // Guarda el archivo de reglas en el directorio de la simulaci�n
      FileUtils.copyFileToDirectory( rulesFile , simDir );

    }
    catch (Exception e)
    {
      throw new EasyBotAppException( e.getMessage() );
    }
  }


  /**
   * Establece el nombre de la simulaci�n. No hay restricciones de univocidad
   * en este dato.
   * @param n  nombre (no necesariamente un�voco) de la simulaci�n.
   */
  public void setName(String n)
  {
    name = new String(n);
  }


  /**
   * Retorna el nombre de la simulaci�n.
   * @return nombre (no necesariamente un�voco).
   */
  public String getName()
  {
    return name;
  }


  /**
   * Permite establecer un comentario descriptivo de la simulaci�n.
   * @param c  comentario.
   */
  public void setComment(String c)
  {
    comment = new String(c);
  }


  /**
   * Retorna la descripci�n establecida con
   * {@link #setComment(String) setComment}.
   * @return comentario descriptivo de la simulaci�n.
   */
  public String getComment()
  {
    return comment;
  }


  public void setPlaybackSimualtion(boolean playbackSimualtion)
  {
    this.playbackSimualtion = playbackSimualtion;
  }


  public boolean isPlaybackSimualtion()
  {
    return playbackSimualtion;
  }

 
  private long getRobotSleepCounts()
  {
    long counts = 0;
    Vector robots = getRobotArray();
    for (int i=0; i< robots.size();i++)
      counts += ((Robot)robots.get(i)).getSleepCounts();
   
    if ( robots.size() > 0 )
      return counts/robots.size();
    else
      return 0;
  }
 
 
  /**
   * La duraci�n de la simulaci�n se calcula en base a la cantidad
   * de veces promedio que se durmieron los robots, multiplicado
   * por el tiempo <code>stepTime</code> por defecto. Si bien no es
   * el tiempo real, es una muy buena aproximaci�n.
   * @return duraci�n en milisegundos.
   */
  public long getDuration()
  {
    // Se multiplica por el default porque el de la simulaci�n
    // var�a se modifica la velocidad.
    duration = getRobotSleepCounts() * Defines.DEFAULT_STEP_TIME;
    return duration;
  }
 
 
  public String getFormattedDuration()
  {
    long hours, minutes, seconds, millis;
    long duration = this.getDuration();
    hours = duration/3600000;
    minutes =(duration - (hours * 3600000))/60000;
    seconds =(duration-(hours*3600000+minutes*60000)) / 1000;
    millis =duration -(hours*3600000+minutes*60000+seconds*1000);
    DecimalFormat formatter = new DecimalFormat("##00");
       
    return formatter.format(hours)+":"+formatter.format(minutes)+":"+formatter.format(seconds)+":"+formatter.format(millis);
  }
  
  
  public void unLoad()
  {
    simulation.dispose();
  }

 
  public static void load(String rootDir) throws SimulationException
  {
    try
    {
      Factory factory = new FactoryrootDir + File.separator + "simulation.xml",
                      rootDir + File.separator + "simulation-rules.xml");
      if ( factory == null )
        throw new SimulationException"No pudo crearse la factor�a para " +
                        "levantar la simulaci�n." );
 
      simulation = (Simulation)factory.digest();     
     
      if (simulation == null)
        throw new SimulationException( "No pudo cargarse la simulaci�n." );
    }
    catch (IOException e)
    {
      throw new SimulationException( e.getMessage() );
    }
    catch (SAXException e)
    {
      throw new SimulationException( e.getMessage() );
    }
  }

 
  public void digestRobots(String xmlFile, String xmlRulesFile) throws SimulationException
  {
    try
    {
      Factory factory = new Factory(xmlFile, xmlRulesFile);
      if ( factory == null )
        throw new SimulationException"No pudo crearse la factor�a para " +
                        "levantar los robots." );
 
      Robot robot = (Robot)factory.digest();
      if (robot == null)
        throw new SimulationException( "No pudo cargarse el robot." );
     
      simulation.addRobot(robot);
    }
    catch (IOException e)
    {
      throw new SimulationException( e.getMessage() );
    }
    catch (SAXException e)
    {
      throw new SimulationException( e.getMessage() );
    }
  }
 
 
  public void digestGPS(String xmlFile,String xmlRulesFile) throws SimulationException
  {
    try
    {
      Factory factory = new Factory(xmlFile, xmlRulesFile);
      if ( factory == null )
        throw new SimulationException"No pudo crearse la factor�a para " +
                        "levantar el GPS." );
 
      GPS gps = (GPS)factory.digest();
      if (gps == null)
        throw new SimulationException( "No pudo cargarse el GPS." );
     
      simulation.setGps(gps);
    }
    catch (IOException e)
    {
      throw new SimulationException( e.getMessage() );
    }
    catch (SAXException e)
    {
      throw new SimulationException( e.getMessage() );
    }
  }
 
 
  public void setAllOk(boolean allOk)
  {
    this.allOk = allOk;
  }


  public boolean isAllOk()
  {
    return allOk;
  }


  public GPS getGps()
  {
    return gps;
  }


  public void setGps(GPS gps)
  {
    this.gps = gps;
  }

}
TOP

Related Classes of core.simulation.Simulation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.