/*
* Datei: Simulation.java
* Autor(en): Lukas K�nig
* Java-Version: 6.0
* Erstellt (vor): 08.05.2008
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/
package fmg.fmg8.umgebung2D;
import fmg.fmg8.endlAutomat.OpsFactory;
import fmg.fmg8.endlAutomat.RobCode;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.endlAutomat.rekombination.RekVerfahren;
import fmg.fmg8.gif.SimpleGIF;
import fmg.fmg8.graphVis.Vis;
import fmg.fmg8.sonstiges.DateiFilter;
import fmg.fmg8.sonstiges.SonstMeth;
import fmg.fmg8.statistik.Aufnahme;
import fmg.fmg8.statistik.Parametersatz;
import fmg.fmg8.statistik.PopSnapshot;
import fmg.fmg8.umgebung2D.dynWaende.Dynamik;
import java.awt.Image;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
/**
* Implementiert eine Simulation als initiale Zuordnung einer Menge von
* Robotern zu einer Umgebung und einer anschlie�enden iterierten Ausf�hrung
* von Zustandswechseln der Roboter und evolution�ren Operatoren.
*
* @author Lukas K�nig
*/
public class Simulation implements Observer {
/**
* Abfolge von Bildern des Simulationsfeldes.
*/
private LinkedList<Image> bilder;
/**
* Die Nummer der aktuellen GIF-Datei.
*/
private int gifNum = 0;
/**
* Liste von Robotern (im VisMantel), die verwaltet werden.
*/
private ArrayList<VisMantel> graphen;
/**
* Der Zufallsgenerator.
*/
private Random rand;
/**
* Das Rekombinationsverfahren.
*/
private RekVerfahren rekombArt;
/**
* Die Umgebung, die durch <code>this</code> dargestellt wird.
*/
private Umgebung umgebung;
/**
* Die Anzahl der Zustandswechsel seit der letzten Rekombination.
*/
private int rekZustandswechsel;
/**
* Ob evolviert wird.
*/
private boolean evolution;
/**
* Die Parameter.
*/
private Parametersatz pars;
/**
* Die Aufnahme dieses Evolutionslaufs.
*/
private Aufnahme aufnahme;
/**
* Anzahl der Zyklen seit dem letzten Schnappschuss.
*/
private long schnappZyklen;
/**
* Anzahl der Zyklen seit dem letzten GIF-Schnappschuss.
*/
private long schnappGIFZyklen;
/**
* Die Simulationszyklen.
*/
private long simZyklen;
/**
* Der Observer f�r die Umgebung.
*/
private Observer observer;
/**
* Liste von graphischen Observern der Automaten der Simulation.
*/
private Vis[] visObserver;
/**
* Konstruktor, der die Attribute initialisiert.
*
* @param params Die Parameter.
* @param obs Ein m�glicher Observer f�r die Umgebung.
* @param visObs Die Vis-Observer.
* @param wandDyn Die Wanddynamik f�r diese Umgebung.
*/
public Simulation(final Parametersatz params,
final Observer obs,
final Vis[] visObs,
final Dynamik wandDyn) {
GlobaleVariablen.setCollCount(0);
this.pars = params;
this.observer = obs;
this.visObserver = visObs;
this.aufnahme = new Aufnahme(this.pars);
this.schnappZyklen = this.pars.getSchnInt().longValue();
this.schnappGIFZyklen = this.pars.getSchnappGIF();
this.rand = new Random(this.pars.getSeed().longValue());
this.rekombArt = OpsFactory.getKonstRek(
this.pars.getRekombVerfahren(),
this.pars,
this.rand);
this.umgebung = new Umgebung(this.rand,
this.pars,
this.observer,
this,
wandDyn);
this.graphen = new ArrayList<VisMantel>();
this.ladeGraphen();
this.rekZustandswechsel = 0;
this.simZyklen = 0;
this.evolution = this.pars.getEvol().booleanValue();
this.platziereRoboter();
this.bilder = new LinkedList<Image>();
SonstMeth.log(
SonstMeth.LOG_INFO,
"Roboter in Simulation: "
+ this.getUm().getAkteure().size(),
this.pars);
if (this.pars.getZufallsGenLen() >= 0) {
this.setzeVerhGenZuf(this.pars.getZufallsGenLen());
SonstMeth.log(
SonstMeth.LOG_INFO,
"Verhaltensgenome mit Zufallsgenomen der L�nge "
+ this.pars.getZufallsGenLen() + " �berschrieben.",
this.pars);
}
}
/**
* Konstruktor, der die Attribute initialisiert.
*
* @param params Die Parameter.
* @param obs Ein m�glicher Observer f�r die Umgebung.
* @param visObs Die Vis-Observer.
* @param automaten Die Initialautomaten f�r die simulierten Roboter.
* @param condColl Die Bedingungen.
* @param ids Die Identit�tsnummern der Roboter.
* @param wandDyn Die Wanddynamik f�r diese Umgebung.
*/
public Simulation(final Parametersatz params,
final Observer obs,
final Vis[] visObs,
final String[][] automaten,
final Condition[][] condColl,
final int[] ids,
final Dynamik wandDyn) {
this.pars = params;
this.observer = obs;
this.visObserver = visObs;
this.aufnahme = new Aufnahme(this.pars);
this.schnappZyklen = this.pars.getSchnInt().longValue();
this.schnappGIFZyklen = this.pars.getSchnappGIF();
this.rand = new Random(this.pars.getSeed().longValue());
this.rekombArt = OpsFactory.getKonstRek(
this.pars.getRekombVerfahren(),
this.pars,
this.rand);
this.umgebung = new Umgebung(this.rand,
this.pars,
this.observer,
this,
wandDyn);
this.graphen = new ArrayList<VisMantel>();
this.zuordnen(visObs, automaten, condColl, ids);
this.rekZustandswechsel = 0;
this.simZyklen = 0;
this.evolution = this.pars.getEvol().booleanValue();
this.platziereRoboter();
this.bilder = new LinkedList<Image>();
}
/**
* Setzt die Verhaltensgenome auf zuf�llige Sequenzen anzugebender L�nge.
*
* @param laenge Die L�nge der Genome.
*/
@SuppressWarnings("unchecked")
private void setzeVerhGenZuf(final int laenge) {
LinkedList<Integer>[] sequenzen;
for (Roboter r : this.getUm().getAkteure()) {
sequenzen = new LinkedList[r.getVAut().length];
for (int i = 0; i < r.getVAut().length; i++) {
sequenzen[i] = this.zufallsSequenz(laenge);
}
r.setVerhCodes(sequenzen);
}
}
/**
* Erzeugt eine Zufallssequenz.
*
* @param laenge Die L�nge der Sequenz.
*
* @return Die Zufallssequenz.
*/
private LinkedList<Integer> zufallsSequenz(final int laenge) {
LinkedList<Integer> sequenz = new LinkedList<Integer>();
final int maxNum = 255;
double gauss;
for (int i = 0; i < laenge; i++) {
gauss = Math.min(Math.abs(this.rand.nextGaussian() * 10), maxNum);
sequenz.add((int) gauss);
}
return sequenz;
}
/**
* L�dt gespeicherte Graphen aus dem im Parameterobjekt angegebenen
* Verzeichnis.
*/
private void ladeGraphen() {
File verz = new File(this.pars.getStdPfad());
String endung = fmg.fmg8.graphVis.Konstanten.GRAPH_ENDUNG;
String[] gespGr = verz.list(new DateiFilter(endung));
String grNam;
VisMantel visRob = null;
Vis obs = null;
boolean sel = false;
if (gespGr != null) {
for (int i = 0; i < gespGr.length; i++) {
grNam = gespGr[i].substring(
0,
gespGr[i].length() - endung.length() - 1);
if (this.pars.getGraphisch().booleanValue()) {
for (int j = 0; j < this.visObserver.length; j++) {
if (this.visObserver[j].getGraphName().equals(grNam)) {
obs = this.visObserver[j];
sel = this.visObserver[j].isVisible();
break;
}
}
}
visRob = new VisMantel(grNam,
this.umgebung,
OpsFactory.getKonstMut(
this.pars.getMutArtVerh(),
this.rand,
this.pars),
OpsFactory.getKonstMut(
this.pars.getMutArtTrans(),
this.rand,
this.pars),
this.rand,
this.kleinsteFreieID(),
this.pars,
sel,
obs);
this.graphen.add(visRob);
}
}
}
/**
* Erzeugt aus einer Automatenliste die zugeh�rigen Roboter und
* ordnet sie den entsprechenden Observern zu.
*
* @param visObs Die Vis-Observer.
* @param automaten Die Automaten.
* @param condColl Die Bedingungen.
* @param ids Die Identit�tsnummern der Automaten.
*/
private void zuordnen(final Vis[] visObs,
final String[][] automaten,
final Condition[][] condColl,
final int[] ids) {
String[] auts = new String[1];
Condition[] conds = new Condition[1];
if (visObs.length != automaten.length) {
throw new RuntimeException("Unterschiedliche Anzahl von Automaten "
+ "und Vis-Objekten.");
}
String grNam;
VisMantel visRob = null;
Vis obsVis = null;
boolean sel = false;
for (int i = 0; i < visObs.length; i++) {
grNam = visObs[i].getGraphName();
if (this.pars.getGraphisch().booleanValue()) {
obsVis = this.visObserver[i];
sel = this.visObserver[i].isVisible();
}
auts = automaten[i];
conds = condColl[i];
visRob = new VisMantel(auts,
conds,
grNam,
this.umgebung,
this.rand,
ids[i],
this.pars,
sel,
obsVis);
this.graphen.add(visRob);
}
}
/**
* Speichert alle Graphen in der Liste <code>this.graphen</code>.
*/
public void speichereAlleGraphen() {
Iterator<VisMantel> it = this.graphen.iterator();
VisMantel aktGr;
while (it.hasNext()) {
aktGr = (VisMantel) it.next();
aktGr.speichereGraph();
}
}
/**
* Gibt die kleinste noch nicht von einem der aktuellen Graphen verwendete
* ID zur�ck.
*
* @return Die kleinste noch nicht verwendete ID.
*/
public int kleinsteFreieID() {
int kleinste = 0;
Iterator<VisMantel> it = this.graphen.iterator();
VisMantel aktGr;
while (it.hasNext()) {
aktGr = (VisMantel) it.next();
if (kleinste <= aktGr.getRob().getId()) {
kleinste = aktGr.getRob().getId() + 1;
}
}
return kleinste;
}
/**
* Endlosz�hler der Schnappsch�sse f�r die Automatenspeicherung.
*/
private long schnappAuts = 0;
/**
* F�hrt einen einzelnen Simulationsschritt aus, der einem Zeitzyklus
* entspricht.
*/
private void step() {
ArrayList<Roboter> akteure;
Iterator<Roboter> it;
ArrayList<RobCode> kindAkteure;
boolean automatSp;
String[] infos;
this.rekZustandswechsel++;
akteure = this.umgebung.getAkteure();
it = akteure.iterator();
while (it.hasNext()) {
it.next().naechsterZustand();
}
if (this.evolution
&& this.rekZustandswechsel
>= this.pars.getRekZyklen().longValue()) {
kindAkteure = this.rekombArt.rekombiniere(akteure);
this.umgebung.uebernimmPop(kindAkteure);
this.rekZustandswechsel = 0;
}
if (this.schnappZyklen >= this.pars.getSchnInt().longValue()) {
if (this.pars.getAufnSp().booleanValue()) {
if (this.schnappAuts % this.pars.getSchnappAut() == 0) {
automatSp = true;
} else {
automatSp = false;
}
this.schnappAuts++;
this.aufnahme.addPopSn(new PopSnapshot(
this.umgebung.getAkteure(),
this.umgebung.getGegVerschieb(),
this.simZyklen,
automatSp,
this.umgebung.getAktDynPixel()));
}
this.schnappZyklen = 0;
}
if (this.schnappGIFZyklen >= this.pars.getSchnappGIF()) {
infos = new String[3];
infos[0] = "Zyklen: " + this.simZyklen;
infos[1] = "Koll %: " + GlobaleVariablen.getCollCount();
infos[2] = "GP %: " + GlobaleVariablen.getGateCount();
if (this.pars.getGIFDatei() != null) {
this.bilder.add(this.umgebung.erzeugeBild(infos));
}
this.schnappGIFZyklen = 0;
}
this.schnappZyklen++;
this.schnappGIFZyklen++;
this.simZyklen++;
this.umgebung.beendeZeichenSession();
// System.gc();
}
/**
* Speichert die Bilderfolge der Simulation als GIF-Datei.
*
* @param datNam Der Dateiname.
*/
private void gifSpeichern(final String datNam) {
String pfad = this.pars.getStdPfad() + File.separator;
String datei =
pfad
+ datNam
+ SonstMeth.normZahl(this.gifNum, 6)
+ ".gif";
FileOutputStream fs;
Image[] imgs = new Image[this.bilder.size()];
int i = 0;
double bilderProSek
= (double) 50 / (double) this.pars.getSchnappGIF();
for (Image img : this.bilder) {
imgs[i] = img;
i++;
}
try {
fs = new FileOutputStream(datei);
SimpleGIF.writeAnimatedGIF(
imgs,
"",
false,
bilderProSek,
fs);
} catch (final Exception e) {
throw new RuntimeException("GIF nicht gespeichert.");
}
SonstMeth.log(
SonstMeth.LOG_INFO,
"GIF-Datei gespeichert: " + datei,
this.pars);
}
/**
* Beendet die Simulation: speichert die Aufnahme.
*/
public void simulationEnde() {
if (this.pars.getAufnSp().booleanValue()) {
this.umgebung.beendeSimulation();
}
this.aufnahmeSpeichern();
if (this.pars.getGraphisch().booleanValue()) {
Iterator<VisMantel> it = this.graphen.iterator();
while (it.hasNext()) {
((VisMantel) it.next()).getRob().simBeendet();
}
}
this.gifNum = 0;
}
/**
* Speichert die Aufnahme.
*/
public void aufnahmeSpeichern() {
if (this.pars.getAufnSp().booleanValue()) {
this.aufnahme.speichern();
}
if (this.pars.getGIFDatei() != null) {
this.gifSpeichern(this.pars.getGIFDatei());
this.bilder.clear();
this.gifNum++;
}
}
/**
* Platziert die Roboter.
*/
public void platziereRoboter() {
Iterator<VisMantel> it;
Roboter rob;
it = this.graphen.iterator();
while (it.hasNext()) {
rob = ((VisMantel) it.next()).getRob();
rob.zuruecksetzen();
this.umgebung.hinzuRobotRand(rob);
}
}
/**
* Die Update-Methode der beobachtenden Klasse.
*
* @param o Das beobachtete Objekt, von dem die Meldung ausging.
* @param arg Argument.
*/
public void update(final Observable o, final Object arg) {
this.step();
}
/**
* @return Returns the umgebung.
*/
public Umgebung getUm() {
return this.umgebung;
}
/**
* @return Returns the evolution.
*/
public boolean isEvolution() {
return this.evolution;
}
/**
* @param evol The evolution to set.
*/
public void setEvolution(final boolean evol) {
this.evolution = evol;
}
}