/*
* Datei: Umgebung.java
* Autor(en): Lukas König
* Java-Version: 6.0
* Erstellt (vor): 05.05.2007
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.startSetup.marbBuilder.traceBetrachter;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.Set;
import eas.math.geometry.Pixel2D_08Bit;
import eas.math.geometry.Polygon2D;
import eas.math.geometry.Vector2D;
import eas.miscellaneous.StaticMethods;
import eas.plugins.Plugin;
import eas.plugins.standard.eaPlugin.xmlRecording.XMLAufnLesen;
import eas.simulation.ConstantsSimulation;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.GenericState;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.RobCode;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.conditions.Condition;
import eas.simulation.spatial.sim2D.marbSimulation.translator.ConstantsTranslator;
import eas.simulation.spatial.sim2D.marbSimulation.translator.Translator;
import eas.simulation.spatial.sim2D.marbSimulation.translator.versionOhneErgKante.ConstantsTranslatorWOC;
import eas.startSetup.ParCollection;
/**
* Repräsentiert ein Feld, auf dem Roboter fahren können.
*
* @author Lukas König
*/
public class Umgebung extends Observable {
/**
* Das Feld. <code>false</code> bedeutet, dass kein Hindernis auf dem
* Koordinatenpunkt ist, <code>true</code> ist ein normales Hindernis.
*/
private byte[][] feld;
/**
* Die Roboter auf dem Feld.
*/
private ArrayList<Roboter> akteure;
/**
* Für jeden Akteur eine Liste von Pixeln, die seine letzte Position
* bezeichnen.
*/
private ArrayList<Vector2D[]> akteurPunkte;
/**
* Die aktuell zu den Robotern dargestellten Informationstexte.
*/
private ArrayList<String> akteurTexte;
/**
* Der Zufallsgenerator.
*/
private Random rand;
/**
* Die Parameter.
*/
private ParCollection pars;
/**
* @return Returns the pars.
*/
public ParCollection getPars() {
return this.pars;
}
/**
* Der neu gesetzte Pixel.
*/
private Pixel2D_08Bit neuerPixel2D;
/**
* Flag, ob Simulation läuft.
*/
private boolean simLaeuft;
/**
* Liste von Gegenst�nden.
*/
private ArrayList<HashMap<Vector2D, Object>> gegenstaende;
/**
* Die Verschiebung der Gegenst�nde.
*/
private ArrayList<Vector2D> gegVerschieb;
/**
* Die Liste der dynamischen Wände, sortiert nach Farben der Wände.
*/
private Polygon2D[] dynWaende;
/**
* Die tatsächlichen aktuellen Verschiebungen der Wände.
*/
private Vector2D[] tatdynVersch;
/**
* Die Liste der zu den dynamischen Wänden gehörenden
* Verschiebungsvektoren. (Diese können noch unaktuell sein, falls
* die entsprechende Verschiebung aufgrund von Kollision nicht möglich
* war.)
*/
private Vector2D[] dynVersch;
/**
* Die Liste der alten Verschiebungen.
*/
private Vector2D[] dynOldVersch;
/**
* Ob die dynamischen Wände gesetzt sind.
*/
private boolean[] dynGesetzt;
/**
* Die tatsächlichen Drehwinkel.
*/
private double[] tatdynDrehWinkel;
/**
* Drehwinkel der Objekte.
*/
private double[] dynDrehWinkel;
/**
* Drehwinkel der Objekte.
*/
private double[] dynDrehWinkelOld;
/**
*(tatsächliche) Drehmittelpunkte relativ zum Zentrum der Objekte.
*/
private Vector2D[] tatdynDrehMittPkt;
/**
* tatsächlicher horizontaler Verzerrungsfaktor.
*/
private double[] tatdynHorFaktor;
/**
* Horizontaler Verzerrungsfaktor.
*/
private double[] dynHorFaktor;
/**
* Alter horizontaler Verzerrungsfaktor.
*/
private double[] dynHorFaktorOld;
/**
* tatsächlicher vertikaler Verzerrungsfaktor.
*/
private double[] tatdynVertFaktor;
/**
* @return Returns the tatdynVersch.
*/
public Vector2D[] getTatdynVersch() {
return this.tatdynVersch;
}
/**
* @return Returns the tatdynDrehWinkel.
*/
public double[] getTatdynDrehWinkel() {
return this.tatdynDrehWinkel;
}
/**
* @return Returns the tatdynDrehMittPkt.
*/
public Vector2D[] getTatdynDrehMittPkt() {
return this.tatdynDrehMittPkt;
}
/**
* @return Returns the tatdynHorFaktor.
*/
public double[] getTatdynHorFaktor() {
return this.tatdynHorFaktor;
}
/**
* @return Returns the tatdynVertFaktor.
*/
public double[] getTatdynVertFaktor() {
return this.tatdynVertFaktor;
}
/**
* Vertikaler Verzerrungsfaktor.
*/
private double[] dynVertFaktor;
/**
* Alter vertikaler Verzerrungsfaktor.
*/
private double[] dynVertFaktorOld;
/**
* Die aktuellen Pixellisten für alle dynamischen Wände.
*/
private ArrayList<LinkedList<Point>> aktDynPixel;
/**
* Gibt die Koordinate einer Kollision mit einem Gegenstand an, falls eine
* solche stattgefunden hat, <code>null</code> sonst.
*/
private Vector2D gegKoll;
// /**
// * Ob die dynamischen Wände NICHT gezeichnet werden sollen.
// */
// private boolean dynWaendeIgnor;
// /**
// * Die alternativ als Pixelliste gegebenen dynamischen Wände (wird im
// * TraceBetrachter-Modus verwendet).
// */
// private List<Point> altDynWaende;
/**
* Die Simulation, die zu dieser Umgebung gehört.
*/
private Simulation simulation;
/**
* Plugins für diesen Lauf.
*/
private Plugin<?>[] plugins;
/**
* @return Returns the simulation.
*/
public Simulation getSimulation() {
return this.simulation;
}
/**
* Die gelesene XML-Aufnahme.
*/
private XMLAufnLesen xmlAufnahme;
/**
* Initialisiert die Umgebung.
*
* @param zufall Der Zufallsgenerator.
* @param params Die Parameter.
* @param obs Der Observer dieser Klasse.
* @param sim Die Simulation, die zu dieser Umgebung gehört.
* @param wandDyn Die Plugins für diese Umgebung.
* @param aufnahme Die gelesene XML-Aufnahme.
*/
public Umgebung(final Random zufall,
final ParCollection params,
final Observer obs,
final Simulation sim,
final Plugin<?>[] wandDyn,
final XMLAufnLesen aufnahme) {
int arrGroesse = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
this.xmlAufnahme = aufnahme;
this.pars = params;
if (obs != null) {
this.addObserver(obs);
}
this.plugins = wandDyn;
this.simulation = sim;
// this.dynWaendeIgnor = false;
this.simLaeuft = true;
this.gegKoll = null;
byte[][] feldPix = aufnahme.getInputField();
this.aktDynPixel = new ArrayList<LinkedList<Point>>(arrGroesse);
for (int i = 0; i < arrGroesse; i++) {
this.aktDynPixel.add(null);
}
this.rand = zufall;
this.feld = new byte[feldPix.length][feldPix[0].length];
this.akteure = new ArrayList<Roboter>();
this.akteurPunkte = new ArrayList<Vector2D[]>();
this.akteurTexte = new ArrayList<String>();
this.gegenstaende = new ArrayList<HashMap<Vector2D, Object>>();
this.gegVerschieb = new ArrayList<Vector2D>();
this.erzeugeDynWaende(feldPix);
this.setzeDynWaende();
this.setzeFeld(ConstantsSimulation.FARBE_RAHMEN);
this.holeGegenstaende();
this.setzeGgste(ConstantsSimulation.FARBE_GGSTD);
if (this.gegenstaende.size() > 0) {
StaticMethods.log(
StaticMethods.LOG_INFO,
"Gegenstaende: " + this.gegenstaende.size(),
this.pars);
}
}
/**
* Setzt die dynamischen Wände mit ihren aktuellen Verschiebungen in das
* Feld, falls dabei keine Kollision auftritt. Falls dynamische Wände
* ignoriert werden sollen, wird stattdessen die Pixelliste altDynWaende
* gesetzt.
*/
private void setzeDynWaende() {
// if (!this.dynWaendeIgnor) {
for (int i = 0; i < this.dynWaende.length; i++) {
if (this.setzeDynWand(i) == null) { // Konnte gesetzt werden.
this.tatdynDrehWinkel[i] = this.dynDrehWinkel[i];
this.tatdynHorFaktor[i] = this.dynHorFaktor[i];
this.tatdynVertFaktor[i] = this.dynVertFaktor[i];
if (this.dynVersch[i] != null) {
this.tatdynVersch[i] = new Vector2D(this.dynVersch[i]);
}
}
}
// } else {
// this.setzePixelliste(this.altDynWaende);
// }
}
/**
* Setzt die wandNum-te dynamische Wand.
*
* @param wandNum Die Nummer der zu setzenden Wand.
*
* @return Ob die Wand gesetzt werden konnte (null = gesetzt,
* sonst das erste Pixel, das kollidiert).
*/
private Point setzeDynWand(final int wandNum) {
Point alleFrei = null;
if (this.dynWaende[wandNum] != null) {
// Falls Wand noch nicht gesetzt ist...
if (!this.dynGesetzt[wandNum]) {
alleFrei = this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynVersch[wandNum],
this.dynHorFaktor[wandNum],
this.dynVertFaktor[wandNum],
this.tatdynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
ConstantsSimulation.FARBE_RAHMEN,
true,
true,
false);
if (alleFrei == null) {
this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynVersch[wandNum],
this.dynHorFaktor[wandNum],
this.dynVertFaktor[wandNum],
this.tatdynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
ConstantsSimulation.FARBE_RAHMEN,
true,
false,
true);
this.dynGesetzt[wandNum] = true;
}
} else { // Falls Wand schon gesetzt ist...
// Alte Position temporär löschen.
// this.setzeDynWand(
// wandNum,
// this.dynWaende[wandNum],
// this.dynOldVersch[wandNum],
// this.dynHorFaktorOld[wandNum],
// this.dynVertFaktorOld[wandNum],
// this.dynDrehMittPkt[wandNum],
// this.dynDrehWinkelOld[wandNum],
// Konstanten.FARBE_HGND,
// true,
// false,
// false);
this.setzePixelliste(
this.aktDynPixel.get(wandNum),
ConstantsSimulation.FARBE_HGND,
true,
false,
false,
false);
// Wenn neue Position kollisionsfrei möglich...
alleFrei = this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynVersch[wandNum],
this.dynHorFaktor[wandNum],
this.dynVertFaktor[wandNum],
this.tatdynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
ConstantsSimulation.FARBE_RAHMEN,
false,
true,
false);
if (alleFrei == null) {
// Setze neue Position fest und aktualisiere Versch.
this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynVersch[wandNum],
this.dynHorFaktor[wandNum],
this.dynVertFaktor[wandNum],
this.tatdynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
ConstantsSimulation.FARBE_RAHMEN,
true,
false,
false);
this.dynOldVersch[wandNum]
= new Vector2D(this.dynVersch[wandNum]);
this.dynHorFaktorOld[wandNum] = dynHorFaktor[wandNum];
this.dynVertFaktorOld[wandNum] = dynVertFaktor[wandNum];
this.dynDrehWinkelOld[wandNum] = dynDrehWinkel[wandNum];
} else {
// Setze alte Position fest.
this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynOldVersch[wandNum],
this.dynHorFaktorOld[wandNum],
this.dynVertFaktorOld[wandNum],
this.tatdynDrehMittPkt[wandNum],
this.dynDrehWinkelOld[wandNum],
ConstantsSimulation.FARBE_RAHMEN,
true,
false,
false);
}
}
}
return alleFrei;
}
/**
* Setzt eine dynamische Wand mit der übergebenen Verschiebung in das
* Feld. Gibt zurück, ob die Wand kollisionsfrei gesetzt werden konnte.
*
* @param wandNum Die Nummer der zu setzenden Wand.
* @param wand Das Wandobjekt, das gesetzt werden soll.
* @param versch Die Verschiebung des Objekts.
* @param farbe Die Farbe, auf die der Pixel gesetzt werden soll.
* @param horzFakt Horizontaler Faktor.
* @param vertFakt Vertikaler Faktor.
* @param drehMittPkt Drehmittelpunkt.
* @param drehWinkel Der Winkel, um den das Objekt gedreht ist.
* @param setzen Ob das Pixel in das Feld gesetzt werden soll und
* die Observer informiert werden sollen.
* @param temp Ob das Pixel NICHT in die Liste der zu zeichnenden
* Pixel übernommen werden soll.
* @param unbed Wenn setzen true ist und dieser Parameter true ist,
* dann wird das Pixel gesetzt, auch wenn es vorher
* schon dieselbe Farbe hatte.
*
* @return Ob die Wand kollisionsfrei gesetzt werden konnte
* (null = gesetzt, sonst das erste Pixel, das kollidiert).
*/
private Point setzeDynWand(
final int wandNum,
final Polygon2D wand,
final Vector2D versch,
final double horzFakt,
final double vertFakt,
final Vector2D drehMittPkt,
final double drehWinkel,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
Point nichtFrei = null;
Vector2D aktPkt;
Iterator<Vector2D> it = wand.iterator();
Vector2D m = new Vector2D(
wand.centerPoint().x + versch.x + drehMittPkt.x,
wand.centerPoint().y + versch.y + drehMittPkt.y);
HashMap<Point, Object> gesetzte = new HashMap<Point, Object>();
double xAnf, xEnd, yAnf, yEnd;
double echtXdreh, echtYdreh;
double cAlpha, sAlpha;
double xLen, yLen;
double zwischX, zwischY;
int zwisch;
while (it.hasNext()) {
aktPkt = it.next();
xAnf = m.x + versch.x
- horzFakt * (m.x - aktPkt.x)
- horzFakt / 2;
xEnd = xAnf + horzFakt;
for (double echtX = xAnf; echtX < xEnd; echtX++) {
yAnf = m.y + versch.y
- vertFakt * (m.y - aktPkt.y)
- vertFakt / 2;
yEnd = yAnf + vertFakt;
for (double echtY = yAnf; echtY < yEnd; echtY++) {
cAlpha = Math.cos(drehWinkel);
sAlpha = Math.sin(drehWinkel);
xLen = echtX - m.x;
yLen = echtY - m.y;
echtXdreh = cAlpha * xLen - sAlpha * yLen + m.x;
echtYdreh = sAlpha * xLen + cAlpha * yLen + m.y;
zwisch = 0;
while (zwisch < 4) {
zwischX = 0;
zwischY = 0;
if (zwisch == 0) {
zwischX = Math.ceil(echtXdreh);
zwischY = Math.ceil(echtYdreh);
} else if (zwisch == 1) {
zwischX = Math.floor(echtXdreh);
zwischY = Math.floor(echtYdreh);
} else if (zwisch == 2) {
zwischX = Math.ceil(echtXdreh);
zwischY = Math.floor(echtYdreh);
} else { // if (zwisch == 3) {
zwischX = Math.floor(echtXdreh);
zwischY = Math.ceil(echtYdreh);
}
if (!gesetzte.containsKey(new Point(
(int) zwischX,
(int) zwischY))) {
if (!this.setzePixel(
(int) zwischX,
(int) zwischY,
farbe,
setzen,
temp,
unbed,
false)) {
nichtFrei = new Point(
(int) zwischX,
(int) zwischY);
}
gesetzte.put(
new Point((int) zwischX, (int) zwischY),
null);
}
zwisch++;
}
}
}
}
// Wenn das Aufnahme-Plugin aktiviert ist und...
if (nichtFrei == null
&& (farbe == ConstantsSimulation.FARBE_RAHMEN)) {
this.aktDynPixel.set(
wandNum,
new LinkedList<Point>(gesetzte.keySet()));
}
return nichtFrei;
}
/**
* Erzeugt alle dynamischen Wandelemente. Dabei wird für jede vorkommende
* dynamische Farbe eine Liste mit Pixeln angelegt, die als gemeinsam
* verschiebbare Wand interpretiert wird. Die Wände müssen danach mit der
* Methode <code>setzeDynWaende</code> gesetzt werden.
*
* @param feldPix Das Feld, das als Bitmap eingelesen wurde.
*/
private void erzeugeDynWaende(final byte[][] feldPix) {
int arrGroesse = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
this.dynWaende = new Polygon2D[arrGroesse];
this.dynVersch = new Vector2D[arrGroesse];
this.tatdynDrehMittPkt = new Vector2D[arrGroesse];
this.tatdynDrehWinkel = new double[arrGroesse];
this.tatdynHorFaktor = new double[arrGroesse];
this.tatdynVersch = new Vector2D[arrGroesse];
this.tatdynVertFaktor = new double[arrGroesse];
this.dynGesetzt = new boolean[arrGroesse];
this.dynOldVersch = new Vector2D[arrGroesse];
this.dynDrehWinkel = new double[arrGroesse];
this.dynDrehWinkelOld = new double[arrGroesse];
this.dynHorFaktor = new double[arrGroesse];
this.dynVertFaktor = new double[arrGroesse];
this.dynHorFaktorOld = new double[arrGroesse];
this.dynVertFaktorOld = new double[arrGroesse];
int dynFarbe;
// Für (fast) alle Farben ordne Pixel in Liste mit der Farbnummer an.
for (int i = 0; i < feldPix.length; i++) {
for (int j = 0; j < feldPix[0].length; j++) {
if (feldPix[i][j] != ConstantsSimulation.FARBE_HGND
&& feldPix[i][j] != ConstantsSimulation.FARBE_HGND_INP
&& feldPix[i][j] != ConstantsSimulation.FARBE_RAHMEN
&& feldPix[i][j] != ConstantsSimulation.FARBE_INP_GEG
&& feldPix[i][j] != ConstantsSimulation.FARBE_INP_TABU) {
dynFarbe = feldPix[i][j] - Byte.MIN_VALUE;
if (this.dynWaende[dynFarbe] == null) {
this.dynWaende[dynFarbe] = new Polygon2D();
this.dynVersch[dynFarbe] = new Vector2D(0, 0);
this.dynOldVersch[dynFarbe] = new Vector2D(0, 0);
this.dynGesetzt[dynFarbe] = false;
this.tatdynDrehMittPkt[dynFarbe]
= new Vector2D(Vector2D.NULL_VECTOR);
this.dynDrehWinkel[dynFarbe] = 0;
this.dynHorFaktor[dynFarbe] = 1;
this.dynVertFaktor[dynFarbe] = 1;
this.dynHorFaktorOld[dynFarbe] = 1;
this.dynVertFaktorOld[dynFarbe] = 1;
}
this.dynWaende[dynFarbe].add(new Vector2D(i, j));
}
}
}
// L�sche Farben, die schon eine andere explizite Verwendung haben.
for (int i = 0; i < ConstantsSimulation.BENUTZTE_FARBEN.length; i++) {
this.dynWaende[ConstantsSimulation.BENUTZTE_FARBEN[i] - Byte.MIN_VALUE]
= null;
this.dynVersch[ConstantsSimulation.BENUTZTE_FARBEN[i] - Byte.MIN_VALUE]
= null;
}
int j = 0;
// Gibt die Nummern der dynamischen Wände aus.
for (int i = 0; i < this.dynWaende.length; i++) {
if (this.dynWaende[i] != null) {
StaticMethods.log(
StaticMethods.LOG_INFO,
"Dynamische Wand " + j + " gefunden: " + i,
this.pars);
j++;
}
}
}
/**
* Verschiebt eine dynamische Wand auf die angegebene Position.
*
* @param wandNum Die zu verschiebende Wand.
* @param versch Die Verschiebung.
*
* @return Ob die Wand kollisionsfrei gesetzt werden konnte
* (null = gesetzt, sonst das erste Pixel, das kollidiert).
*/
public Point verschWand(
final int wandNum,
final Vector2D versch) {
Point nichtFrei;
if (this.dynVersch == null) {
this.erzeugeDynWaende(this.xmlAufnahme.getInputField());
}
if (this.dynVersch[wandNum] == null) {
this.dynVersch[wandNum] = new Vector2D(Vector2D.NULL_VECTOR);
}
this.dynVersch[wandNum].setzeKoord(versch.x, versch.y);
nichtFrei = this.setzeDynWand(wandNum);
if (nichtFrei == null) {
this.tatdynVersch[wandNum] = new Vector2D(this.dynVersch[wandNum]);
}
return nichtFrei;
}
/**
* Setzt Verzerrungsfaktoren für eine dynamische Wand.
*
* @param wandNum Die Nummer der zu verzerrenden Wand.
* @param x Die Verzerrung in X-Richtung.
* @param y Die Verzerrung in Y-Richtung.
*
* @return Ob die Wand kollisionsfrei gesetzt werden konnte
* (null = gesetzt, sonst das erste Pixel, das kollidiert).
*/
public Point verzerrWand(
final int wandNum,
final double x,
final double y) {
Point nichtFrei;
if (this.dynHorFaktor == null || this.dynVertFaktor == null) {
this.erzeugeDynWaende(this.xmlAufnahme.getInputField());
}
if (x < 0 || y < 0) {
throw new RuntimeException("Verzerrung darf nicht negativ sein: "
+ new Vector2D(x, y));
}
this.dynHorFaktor[wandNum] = x;
this.dynVertFaktor[wandNum] = y;
nichtFrei = this.setzeDynWand(wandNum);
if (nichtFrei == null) {
this.tatdynHorFaktor[wandNum] = this.dynHorFaktor[wandNum];
this.tatdynVertFaktor[wandNum] = this.dynVertFaktor[wandNum];
}
return nichtFrei;
}
/**
* Setze Winkel.
*
* @param wandNum Die Nummer der zu drehenden Wand.
* @param winkel Der Drehwinkel in Grad.
*
* @return Ob die Wand kollisionsfrei gesetzt werden konnte
* (null = gesetzt, sonst das erste Pixel, das kollidiert).
*/
public Point dreheWand(
final int wandNum,
final double winkel) {
Point gesetzt;
if (this.dynDrehWinkel == null) {
this.erzeugeDynWaende(this.xmlAufnahme.getInputField());
}
this.dynDrehWinkel[wandNum] = winkel * Math.PI / 180;
gesetzt = this.setzeDynWand(wandNum);
if (gesetzt == null) {
this.tatdynDrehWinkel[wandNum] = this.dynDrehWinkel[wandNum];
}
return gesetzt;
}
/**
* Findet alle zusammenh�ngenden Pixel von einem bestimmten Pixel
* ausgehend, die die Gegenstandfarbe haben, im übergebenen Feld. Die
* gefundenen Pixel werden zu der Hashtabelle <code>gegenstand</code>
* hinzugefügt.
*
* @param x Startkoordinate x.
* @param y Startkoordinate y.
* @param gegenstand Die Hashtabelle, in die die Pixel eingefügt werden.
* @param feldPix Das Feld.
*/
private void findeGgstd(final int x,
final int y,
final HashMap<Vector2D, Object> gegenstand,
final byte[][] feldPix) {
if (x < 0 || y < 0 || x >= feldPix.length || y >= feldPix[0].length) {
return;
}
if (feldPix[x][y] != ConstantsSimulation.FARBE_INP_GEG) {
return;
}
if (gegenstand.containsKey(new Vector2D(x, y))) {
return;
}
gegenstand.put(new Vector2D(x, y), null);
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
if (i != x || j != y) {
findeGgstd(i, j, gegenstand, feldPix);
}
}
}
}
/**
* Sucht die Gegenst�nde im Feld und erzeugt entsprechende Objekte.
*/
private void holeGegenstaende() {
HashMap<Vector2D, Object> gegenstand;
Vector2D neuVek;
Iterator<HashMap<Vector2D, Object>> it;
byte[][] feldPix = this.xmlAufnahme.getInputField();
boolean gefunden;
Vector2D verschiebung;
for (int j = 0; j < feldPix[0].length; j++) {
for (int i = 0; i < feldPix.length; i++) {
if (feldPix[i][j] == ConstantsSimulation.FARBE_INP_GEG) {
neuVek = new Vector2D(i, j);
gefunden = false;
it = this.gegenstaende.iterator();
while (it.hasNext()) {
gegenstand = it.next();
if (gegenstand.containsKey(neuVek)) {
gefunden = true;
break;
}
}
if (!gefunden) {
gegenstand = new HashMap<Vector2D, Object>();
this.findeGgstd(i, j, gegenstand, feldPix);
this.gegenstaende.add(gegenstand);
verschiebung = new Vector2D(0, 0);
this.gegVerschieb.add(verschiebung);
}
}
}
}
}
/**
* Setzt die Gegenst�nde in das Feld.
*
* @param farbe Die Farbe, in der die Gegenst�nde gesetzt werden sollen.
*/
private void setzeGgste(final byte farbe) {
Iterator<HashMap<Vector2D, Object>> it = this.gegenstaende.iterator();
HashMap<Vector2D, Object> gegenstand;
while (it.hasNext()) {
gegenstand = it.next();
this.setzeGgst(gegenstand, farbe, true, false, false);
}
}
/**
* Setzt einen einzelnen Gegenstand in das Feld.
*
* @param ggst Der zu setzende Gegenstand.
* @param farbe Die Farbe des Gegenstands.
* @param setzen Ob der Gegenstand in das Feld gesetzt werden soll.
* @param temp Ob temporär gesetzt werden soll.
* @param unbed Ob unbedingt gesetzt werden soll.
*
* @return Ob der Gegenstand ohne Kollision gesetzt werden kann.
*/
private boolean setzeGgst(final HashMap<Vector2D, Object> ggst,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
boolean alleFrei = true;
Vector2D aktVek;
Iterator<Vector2D> it = ggst.keySet().iterator();
while (it.hasNext()) {
aktVek = it.next();
alleFrei = alleFrei & this.setzePixel((int) aktVek.x,
(int) aktVek.y,
farbe,
setzen,
temp,
unbed,
false);
}
return alleFrei;
}
/**
* Setzt die Pixel des Feldes.
*
* @param farbe Die zu setzende Farbe für Rahmenpixel.
*/
private void setzeFeld(final byte farbe) {
byte[][] feldPix = this.xmlAufnahme.getInputField();
for (int j = 0; j < feldPix[0].length; j++) {
for (int i = 0; i < feldPix.length; i++) {
if (feldPix[i][j] == 0) {
this.setzePixel(i, j, farbe, true, false, false, false);
}
}
}
}
/**
* fügt einen Roboter zur Liste der Roboter hinzu, wenn er nicht
* kollidiert.
*
* @param roboter Der hinzuzufügende Roboter.
*
* @return Ob der Roboter hinzugefügt wurde.
*/
public boolean hinzuRobot(final Roboter roboter) {
byte farbe;
String text = "";
if (this.xmlAufnahme.getInputField()
[(int) roboter.getPosition().x]
[(int) roboter.getPosition().y]
== ConstantsSimulation.FARBE_INP_TABU) {
return false;
}
if (roboter.isSelektiert()) {
farbe = ConstantsSimulation.FARBE_SEL;
} else {
farbe = ConstantsSimulation.FARBE_ROB;
}
Vector2D[] eckpunkte = new Vector2D[roboter.getEckPunkte().length];
for (int i = 0; i < eckpunkte.length; i++) {
eckpunkte[i] = new Vector2D(50, 50);
}
this.akteure.add(roboter);
this.akteurPunkte.add(eckpunkte);
this.akteurTexte.add(text);
if (this.setzeRobWennMoegl(roboter, true, farbe, text)) {
return true;
} else {
this.akteure.remove(roboter);
this.akteurPunkte.remove(eckpunkte);
this.akteurTexte.remove(text);
return false;
}
}
/**
* fügt einen Roboter an eine zufällige Stelle in der Umgebung ein.
*
* @param rob Der einzufügende Roboter.
*/
public void hinzuRobotRand(final Roboter rob) {
rob.setPosition(new Vector2D(this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY()));
rob.setBlickRicht(this.rand.nextDouble() * 360);
while (!this.hinzuRobot(rob)) {
rob.setPosition(new Vector2D(this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY()));
rob.setBlickRicht(this.rand.nextDouble() * 360);
}
}
/**
* Versetzt einen Roboter zufällig im Feld. Tabu-Felder werden nicht
* besetzt.
*
* @param rob Der zu versetzende Roboter.
*/
public void setzeRobotRand(final Roboter rob) {
boolean gesetzt = false;
Vector2D vek;
while (!gesetzt) {
vek = new Vector2D(
this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY());
if (this.xmlAufnahme.getInputField()[(int) vek.x][(int) vek.y]
!= ConstantsSimulation.FARBE_INP_TABU) {
gesetzt = rob.setPos(
vek.x,
vek.y,
false);
} else {
gesetzt = false;
}
gesetzt = gesetzt && rob.setBlck(this.rand.nextDouble() * 360);
}
}
/**
* Leert das aktuelle Feld.
*/
public void leereFeld() {
for (int i = 0; i < this.feld.length; i++) {
for (int j = 0; j < this.feld[0].length; j++) {
this.setzePixel(i,
j,
ConstantsSimulation.FARBE_HGND,
true,
false,
false,
false);
}
}
this.setzeFeld(ConstantsSimulation.FARBE_RAHMEN);
}
/**
* Entfernt den Roboter, falls er bereits gezeichnet war, NUR aus der
* graphischen Darstellung.
*
* @param robot Der zu entfernende Roboter.
*/
public void entferneRoboter(final Roboter robot) {
if (this.akteure.contains(robot)) {
this.setzeRobWennMoegl(robot, true, ConstantsSimulation.FARBE_HGND, "");
}
}
/**
* Entfernt den Roboter, falls er bereits gezeichnet war, aus der
* graphischen Darstellung UND aus der Liste der darzustellenden Roboter.
*
* @param robot Der zu entfernende Roboter.
*
* @return Ob der Roboter gelöscht wurde oder nicht vorhanden war.
*/
public boolean loescheRoboter(final Roboter robot) {
if (this.akteure.contains(robot)) {
this.entferneRoboter(robot);
this.akteure.remove(robot);
return true;
} else {
return false;
}
}
/**
* |=| 1 2 3
* = 4
* |=| 5 6 7.
*
* @param nummer Segnum.
* @param lu Koordinate des linken unteren Punkts.
* @param ro Koordinate des rechten oberen Punkts.
* @param setzen Ob gesetzt (oder gelöscht) werden soll.
*/
private void setzeSegment(final int nummer,
final Vector2D lu,
final Vector2D ro,
final boolean setzen) {
Vector2D lu2 = new Vector2D(lu.x, ro.y);
Vector2D ro2 = new Vector2D(ro.x, lu.y);
byte farbe;
if (setzen) {
farbe = ConstantsSimulation.FARBE_DURCHLAESSIG;
} else {
farbe = ConstantsSimulation.FARBE_HGND;
}
if (nummer == 1) {
this.setzeLinie(lu2.x, (ro2.y + lu2.y) / 2, lu2.x, ro2.y,
farbe, true, false, false, true);
} else if (nummer == 2) {
this.setzeLinie(lu2.x, ro2.y, ro2.x, ro2.y,
farbe, true, false, false, true);
} else if (nummer == 3) {
this.setzeLinie(ro2.x, (ro2.y + lu2.y) / 2, ro2.x, ro2.y,
farbe, true, false, false, true);
} else if (nummer == 4) {
this.setzeLinie(lu2.x, (lu2.y + ro2.y) / 2,
ro2.x, (lu2.y + ro2.y) / 2,
farbe, true, false, false, true);
} else if (nummer == 5) {
this.setzeLinie(lu2.x, (lu2.y + ro2.y) / 2, lu2.x, lu2.y,
farbe, true, false, false, true);
} else if (nummer == 6) {
this.setzeLinie(lu2.x, lu2.y, ro2.x, lu2.y,
farbe, true, false, false, true);
} else if (nummer == 7) {
this.setzeLinie(ro2.x, (lu2.y + ro2.y) / 2, ro2.x, lu2.y,
farbe, true, false, false, true);
}
}
/**
* Setzt oder löscht einen Buchstaben im Feld.
*
* @param buchstabe Der zu setzende Buchstabe.
* @param lu Koordinate des linken unteren Punkts.
* @param ro Koordinate des rechten oberen Punkts.
* @param setzen Ob der Buchstabe gesetzt (true) oder gelöscht
* (false) werden soll.
*/
private void setzeBuchstabe(final char buchstabe,
final Vector2D lu,
final Vector2D ro,
final boolean setzen) {
if (buchstabe == '0') {
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(5, lu, ro, setzen);
} else if (buchstabe == '1') {
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '2') {
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(5, lu, ro, setzen);
} else if (buchstabe == '3') {
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '4') {
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '5') {
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '6') {
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(5, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '7') {
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '8') {
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(5, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '9') {
this.setzeSegment(1, lu, ro, setzen);
this.setzeSegment(2, lu, ro, setzen);
this.setzeSegment(3, lu, ro, setzen);
this.setzeSegment(4, lu, ro, setzen);
this.setzeSegment(6, lu, ro, setzen);
this.setzeSegment(7, lu, ro, setzen);
} else if (buchstabe == '-') {
this.setzeSegment(4, lu, ro, setzen);
} else if (buchstabe == ',') {
this.setzeSegment(6, lu, ro, setzen);
}
}
/**
* Setzt einen Text in das Feld.
*
* @param text Der zu setzende Text.
* @param linksUnten Die linke untere Koordinate.
* @param setzen Ob gesetzt (oder gelöscht) werden soll.
*/
public void setzeText(final String text,
final Vector2D linksUnten,
final boolean setzen) {
Vector2D lu = new Vector2D(linksUnten);
Vector2D ro = new Vector2D(linksUnten.x + ConstantsSimulation.TEXT_AUSDEHNUNG.x,
linksUnten.y + ConstantsSimulation.TEXT_AUSDEHNUNG.y);
Vector2D verschiebung = new Vector2D(ConstantsSimulation.TEXT_AUSDEHNUNG.x
+ ConstantsSimulation.TEXT_AUSDEHNUNG.x / 3,
0);
for (int i = 0; i < text.length(); i++) {
this.setzeBuchstabe(text.charAt(i), lu, ro, setzen);
lu.x += verschiebung.x;
lu.y += verschiebung.y;
ro.x += verschiebung.x;
ro.y += verschiebung.y;
}
}
/**
* Setzt einen Roboter und gibt zurück, ob eine Kollision aufgetreten ist.
*
* @param eckP Die Eckpunkte des Roboters.
* @param farbe Die Farbe des Roboters.
* @param setzen Ob der Roboter ins normFeld gesetzt werden soll.
* @param temp Ob der Roboter nur temporär gesetzt, also nicht in die
* Liste der zu zeichnenden Pixel aufgenommen werden soll.
* @param unbed Ob auch die Pixel gesetzt werden sollen, die schon die
* gleiche Farbe haben.
*
* @return Ob der Roboter ohne Kollision gesetzt werden konnte.
*/
public boolean setzeRob(final Vector2D[] eckP,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
final Vector2D mitte = new Vector2D((eckP[0].x + eckP[3].x) / 2,
(eckP[0].y + eckP[3].y) / 2);
boolean alleOk = true;
alleOk = alleOk
& this.setzeLinie(eckP[0].x, eckP[0].y, eckP[2].x, eckP[2].y,
farbe,
setzen,
temp,
unbed,
false);
alleOk = alleOk
& this.setzeLinie(eckP[2].x, eckP[2].y, eckP[3].x, eckP[3].y,
farbe,
setzen,
temp,
unbed,
false);
alleOk = alleOk
& this.setzeLinie(eckP[3].x, eckP[3].y, eckP[1].x, eckP[1].y,
farbe,
setzen,
temp,
unbed,
false);
alleOk = alleOk
& this.setzeLinie(eckP[1].x, eckP[1].y, eckP[0].x, eckP[0].y,
farbe,
setzen,
temp,
unbed,
false);
alleOk = alleOk
& this.setzeLinie(mitte.x, mitte.y, eckP[0].x, eckP[0].y,
farbe,
setzen,
temp,
unbed,
false);
alleOk = alleOk
& this.setzeLinie(mitte.x, mitte.y, eckP[1].x, eckP[1].y,
farbe,
setzen,
temp,
unbed,
false);
return alleOk;
}
/**
* Verschiebt einen Gegenstand in die angegebene Richtung, falls möglich.
*
* @param xRicht X-Richtung.
* @param yRicht Y-Richtung.
* @param ggstID Identifizierung des Gegenstands.
*
* @return Ob der Gegenstand verschoben werden konnte.
*/
public boolean verschGgstWennMoegl(final double xRicht,
final double yRicht,
final int ggstID) {
boolean alleFrei = false;
HashMap<Vector2D, Object> altGgst = this.gegenstaende.get(ggstID);
HashMap<Vector2D, Object> neuGgst = new HashMap<Vector2D, Object>();
Set<Vector2D> ggst = altGgst.keySet();
Iterator<Vector2D> it = ggst.iterator();
Vector2D aktVek;
Vector2D neuVek;
Vector2D altVersch = this.gegVerschieb.get(ggstID);
Vector2D neuVersch;
while (it.hasNext()) {
aktVek = it.next();
neuVek = new Vector2D(aktVek.x + xRicht,
aktVek.y + yRicht);
neuGgst.put(neuVek, null);
}
this.setzeGgst(altGgst, ConstantsSimulation.FARBE_HGND, true, true, false);
alleFrei = this.setzeGgst(neuGgst,
ConstantsSimulation.FARBE_GGSTD,
false,
true,
false);
if (alleFrei) { // Alte Punkte endg. löschen.
this.setzeGgst(altGgst, ConstantsSimulation.FARBE_HGND, true, false, true);
}
if (alleFrei) { // Neue Punkte endgültig setzen.
this.setzeGgst(neuGgst, ConstantsSimulation.FARBE_GGSTD, true, false, false);
neuVersch
= new Vector2D(altVersch.x + xRicht, altVersch.y + yRicht);
this.gegenstaende.remove(ggstID);
this.gegVerschieb.remove(ggstID);
this.gegenstaende.add(ggstID, neuGgst);
this.gegVerschieb.add(ggstID, neuVersch);
return true;
} else { // Alte Punkte endgültig setzen.
this.setzeGgst(altGgst, ConstantsSimulation.FARBE_GGSTD, true, true, false);
return false;
}
}
/**
* Setzt einen Roboter ins Spielfeld.
*
* @param robot Der zu setzende Roboter.
* @param gegKollIgnore Ob Kollisionen mit Gegenst�nden ignoriert werden
* sollen.
* @param farbe Ob <code>true</code> oder <code>false</code>
* gesetzt werden soll. Pixel übernommen werden soll.
* @param text Ein Informationstext über den Roboter.
*
* @return Ob der Roboter ohne Kollision gesetzt werden konnte (alle
* Felder müssen vorher != farbe gewesen sein; bei diesem
* Vergleich ist FarbeTRUE = FarbeSPEZIAL).
*/
public boolean setzeRobWennMoegl(final Roboter robot,
final boolean gegKollIgnore,
final byte farbe,
final String text) {
boolean alleFrei = true;
Vector2D[] neueEcken = robot.getEckPunkte();
Vector2D[] zwischenEcken = new Vector2D[4];
int indexRob = this.akteure.indexOf(robot);
Vector2D[] alteEcken = this.akteurPunkte.get(indexRob);
String alterText = this.akteurTexte.get(indexRob);
byte falseFarb = ConstantsSimulation.FARBE_HGND;
Vector2D ecke = null;
if (alteEcken != null && alteEcken[0] != null) {
ecke = new Vector2D(alteEcken[0]);
}
if (alteEcken[0] != null) { // Alte Punkte temporär löschen.
this.setzeRob(alteEcken, falseFarb, true, true, false);
}
this.gegKoll = null;
// Neue Punkte probehalber setzen.
alleFrei = this.setzeRob(neueEcken, farbe, false, true, false);
/*
* Kollision mit einem Gegenstand hat stattgefunden und Roboter war
* bereits gesetzt.
*/
if (!gegKollIgnore && this.gegKoll != null && alteEcken[0] != null) {
double verschX = (neueEcken[0].x - alteEcken[0].x);
double verschY = (neueEcken[0].y - alteEcken[0].y);
int gegID = 0;
Iterator<HashMap<Vector2D, Object>> it
= this.gegenstaende.iterator();
while (it.hasNext()) {
if (it.next().containsKey(this.gegKoll)) {
break;
}
gegID++;
}
if (this.verschGgstWennMoegl(verschX, verschY, gegID)) {
for (int i = 0; i < neueEcken.length; i++) {
zwischenEcken[i] = alteEcken[i];
alteEcken[i] = new Vector2D(neueEcken[i]);
}
alleFrei = this.setzeRobWennMoegl(robot,
gegKollIgnore,
farbe,
text);
for (int i = 0; i < neueEcken.length; i++) {
alteEcken[i] = zwischenEcken[i];
}
}
}
if (alleFrei && alteEcken[0] != null) { // Alte Punkte endg. löschen.
this.setzeRob(alteEcken, falseFarb, true, false, true);
}
if (alleFrei) { // Neue Punkte endgültig setzen.
this.setzeRob(neueEcken, farbe, true, false, false);
if (alteEcken[0] != null) {
this.setzeText(alterText, ecke, false);
this.setzeText(text, new Vector2D(neueEcken[0]), true);
this.akteurTexte.remove(indexRob);
this.akteurTexte.add(indexRob, text);
}
for (int i = 0; i < neueEcken.length; i++) {
alteEcken[i] = new Vector2D(neueEcken[i]);
}
return true;
} else if (alteEcken[0] != null) { // Alte Punkte endgültig setzen.
this.setzeRob(alteEcken, farbe, true, true, false);
this.setzeText(alterText, ecke, true);
return false;
} else { // Keine alten Punkte vorhanden - Roboter war nicht gesetzt.
return false;
}
}
/**
* Setzt im Feld eine Linie von (x1, y1) nach (x2, y2).<BR>
* <BR>
* Seiteneffekte: Falls (mind.) eine Kollision mit einem Gegenstand
* stattfindet, werden die Koordinaten des ersten Pixels,
* bei dem eine Kollision stattgefunden hat in
* <code>this.gegKoll</code> geschrieben.
*
* @param x1 X-Koordinate1.
* @param x2 Y-Koordinate1.
* @param y1 X-Koordinate2.
* @param y2 Y-Koordinate2.
* @param setzen Gibt an, ob die Linie tatsächlich gesetzt werden soll.
* @param farbe Welche Farbe gesetzt werden soll.
* @param temp Ob das Pixel NICHT in die Liste der zu zeichnenden
* Pixel übernommen werden soll.
* @param unbed Wenn setzen true ist und dieser Parameter true ist,
* dann werden die Pixel gesetzt, auch wenn sie vorher
* schon dieselbe Farbe hatten.
* @param passiv Ob das Pixel nur gesetzt werden soll, wenn das Feld
* die Hintergrundfarbe oder die durchl�ssige Farbe hat.
*
* @return Ob ALLE Pixel neu gesetzt wurden, dh. vorher != farbe waren
* (bei diesem Vergleich ist FarbeTRUE = FarbeSPEZIAL).
*/
public boolean setzeLinie(final double x1,
final double y1,
final double x2,
final double y2,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed,
final boolean passiv) {
boolean alleFrei = true;
final int xx1;
final int yy1;
final int xx2;
final int yy2;
double aktX;
double aktY;
int aktXi;
int aktYi;
double schrittY;
double schrittX;
if (Math.abs(x2 - x1) > Math.abs(y2 - y1)) {
if (x1 < x2) {
xx1 = (int) Math.round(x1);
yy1 = (int) Math.round(y1);
xx2 = (int) Math.round(x2);
yy2 = (int) Math.round(y2);
} else {
xx1 = (int) Math.round(x2);
yy1 = (int) Math.round(y2);
xx2 = (int) Math.round(x1);
yy2 = (int) Math.round(y1);
}
schrittY = ((double) yy2 - (double) yy1)
/ ((double) xx2 - (double) xx1);
aktY = yy1;
for (aktX = xx1; aktX <= xx2; aktX++) {
aktXi = (int) Math.round(aktX);
aktYi = (int) Math.round(aktY);
alleFrei = alleFrei & this.setzePixel(aktXi,
aktYi,
farbe,
setzen,
temp,
unbed,
passiv);
aktY = aktY + schrittY;
}
} else {
if (y1 < y2) {
xx1 = (int) Math.round(x1);
yy1 = (int) Math.round(y1);
xx2 = (int) Math.round(x2);
yy2 = (int) Math.round(y2);
} else {
xx1 = (int) Math.round(x2);
yy1 = (int) Math.round(y2);
xx2 = (int) Math.round(x1);
yy2 = (int) Math.round(y1);
}
schrittX = ((double) xx2 - (double) xx1)
/ ((double) yy2 - (double) yy1);
aktX = xx1;
for (aktY = yy1; aktY <= yy2; aktY++) {
aktXi = (int) Math.round(aktX);
aktYi = (int) Math.round(aktY);
alleFrei = alleFrei & this.setzePixel(aktXi,
aktYi,
farbe,
setzen,
temp,
unbed,
passiv);
aktX = aktX + schrittX;
}
}
return alleFrei;
}
/**
* Setzt ein Pixel in das interne Feld.
*
* @param x Die X-Koordinate des zu setzenden Pixel.
* @param y Die Y-Koordinate des zu setzenden Pixel.
* @param farbe Die Farbe, auf die der Pixel gesetzt werden soll.
* @param setzen Ob das Pixel in das Feld gesetzt werden soll und die
* Observer informiert werden sollen.
* @param temp Ob das Pixel NICHT in die Liste der zu zeichnenden
* Pixel übernommen werden soll.
* @param unbed Wenn setzen true ist und dieser Parameter true ist,
* dann wird das Pixel gesetzt, auch wenn es vorher schon
* dieselbe Farbe hatte.
* @param passiv Ob das Pixel nur gesetzt werden soll, wenn das Feld
* die Hintergrundfarbe oder die durchl�ssige Farbe hat.
*
* @return Ob das Pixel ohne Kollision gesetzt werden kann.
*/
private boolean setzePixel(
final int x,
final int y,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed,
final boolean passiv) {
boolean frei = true;
if (x < 0 || x >= this.feld.length
|| y < 0 || y >= this.feld[0].length
|| (passiv && this.feld[x][y] != ConstantsSimulation.FARBE_HGND
&& this.feld[x][y] != ConstantsSimulation.FARBE_DURCHLAESSIG)) {
return false;
} else {
if (((farbe == ConstantsSimulation.FARBE_HGND
|| farbe == ConstantsSimulation.FARBE_DURCHLAESSIG)
&& this.feld[x][y] == farbe)
|| ((farbe != ConstantsSimulation.FARBE_HGND
&& farbe != ConstantsSimulation.FARBE_DURCHLAESSIG)
&& (this.feld[x][y] == ConstantsSimulation.FARBE_ROB
|| this.feld[x][y] == ConstantsSimulation.FARBE_SEL
|| this.feld[x][y] == ConstantsSimulation.FARBE_RAHMEN
|| this.feld[x][y] == ConstantsSimulation.FARBE_GGSTD))) {
if (this.feld[x][y] == ConstantsSimulation.FARBE_GGSTD
&& this.gegKoll == null) {
this.gegKoll = new Vector2D(x, y);
}
frei = false;
}
}
if (setzen) {
if (this.feld[x][y] != farbe || unbed) {
this.feld[x][y] = farbe;
if (!temp) {
this.neuerPixel2D = new Pixel2D_08Bit(x, y, farbe);
this.setChanged();
this.notifyObservers();
}
}
}
return frei;
}
// /**
// * Setzt eine Pixelliste als alternative dynamische Wände. Die Pixel
// * werden gleich und beim Aufruf der Methode alleFelderNeu gezeichnet.
// *
// * @param liste Die zu setzende Pixelliste.
// */
// public void setAltDynWaende(final List<Point> liste) {
// this.altDynWaende = liste;
// this.alleFelderNeu();
// }
/**
* Setzt das neue Pixel auf <code>null</code> als Zeichen für die GUI,
* dass die aktuelle Zeichensession beendet ist.
*/
public void beendeZeichenSession() {
this.neuerPixel2D = null;
this.setChanged();
this.notifyObservers();
}
/**
* Erzeugt eine Textausgabe des Feldes.
*
* @return Testausgabe.
*/
@Override
public String toString() {
String s = "";
s += "Umgebungsgroesse : "
+ this.xmlAufnahme.getInputField().length + " x "
+ this.xmlAufnahme.getInputField()[0].length
+ " Pixel\n";
s += "\n" + StaticMethods.feldAusgabe(
this.xmlAufnahme.getInputField(),
8,
14,
StaticMethods.ZEICHEN_INPUT,
StaticMethods.PRIORITAET_INPUT);
return s;
}
/**
* Misst im aktuellen Feld den Wert für den durch seine Richtung
* angegebenen Sensor des angegebenen Roboters.
*
* @param robot Der Roboter, dessen Sensoren berechnet werden.
* @param sensor Die Nummer des Sensors, der berechnet werden soll.
*
* @return Der Wert des Sensors.
*/
public int berSensWerte(final Roboter robot, final int sensor) {
final Vector2D[][] sensRichtungen = robot.getAlleAbsSensRicht();
double entfernung = 0;
double minEntfernung;
final int xAlti = (int) Math.round(robot.getPosition().x);
final int yAlti = (int) Math.round(robot.getPosition().y);
double x;
double y;
int xi;
int yi;
double verzerr = this.pars.getParValueDouble(eas.statistics.ConstantsStatistics.VERZERR_ATTR);
double konst1 = 1.0 / Math.pow(51.0, 1 / 150.0);
double konst2 = 255.0 * Math.pow(konst1,
-ConstantsSimulation.ROB_AUSDEHNUNG_X / 2.0);
byte farbe;
byte letztFarbe;
if (robot.isSelektiert()) {
farbe = ConstantsSimulation.FARBE_SEL;
} else {
farbe = ConstantsSimulation.FARBE_ROB;
}
this.entferneRoboter(robot);
int i = sensor;
minEntfernung = Double.MAX_VALUE;
for (int j = 0; j < sensRichtungen.length; j++) {
x = robot.getPosition().x;
y = robot.getPosition().y;
xi = (int) Math.round(x);
yi = (int) Math.round(y);
letztFarbe = ConstantsSimulation.FARBE_HGND;
while (xi >= 0 && xi < this.feld.length
&& yi >= 0 && yi < this.feld[0].length
&& feld[xi][yi] != ConstantsSimulation.FARBE_ROB
&& feld[xi][yi] != ConstantsSimulation.FARBE_SEL
&& feld[xi][yi] != ConstantsSimulation.FARBE_RAHMEN) {
x = x + sensRichtungen[j][i].x;
y = y + sensRichtungen[j][i].y;
xi = (int) Math.round(x);
yi = (int) Math.round(y);
if (xi >= 0 && xi < this.feld.length
&& yi >= 0 && yi < this.feld[0].length) {
letztFarbe = feld[xi][yi];
}
}
if (xi < 0 || xi >= this.feld.length
|| yi < 0 || yi >= this.feld[0].length) {
entfernung = Double.MAX_VALUE;
} else {
entfernung = this.entfernung(xi, yi, xAlti, yAlti);
if (letztFarbe == ConstantsSimulation.FARBE_SEL
|| letztFarbe == ConstantsSimulation.FARBE_ROB) {
entfernung = entfernung * ConstantsSimulation.ROBOTER_KONST;
}
if (i == ConstantsSimulation.BEAMER - 1) {
entfernung = entfernung * ConstantsSimulation.BEAMER_KONST;
}
}
if (entfernung < minEntfernung) {
minEntfernung = entfernung;
}
}
int indexRob = this.akteure.indexOf(robot);
this.setzeRobWennMoegl(robot,
true,
farbe,
this.akteurTexte.get(indexRob));
return (int) Math.round(konst2
* Math.pow(konst1,
minEntfernung
/ verzerr));
}
/**
* Berechnet die Entfernung zwischen zwei Punkten.
*
* @param x1 Punkt1, X.
* @param y1 Punkt1, Y.
* @param x2 Punkt2, X.
* @param y2 Punkt2, Y.
*
* @return Die Entfernung zwischen den Punkten.
*/
private double entfernung(final double x1, final double y1,
final double x2, final double y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
/**
* @return Returns the akteure.
*/
public ArrayList<Roboter> getAgenten() {
return this.akteure;
}
/**
* Gibt die Ausdehnung des Feldes in X-Richtung zurück.
*
* @return Die Ausdehnung des Feldes in X-Richtung.
*/
public int ausdX() {
return this.feld.length;
}
/**
* Gibt die Ausdehnung des Feldes in Y-Richtung zurück.
*
* @return Die Ausdehnung des Feldes in Y-Richtung.
*/
public int ausdY() {
return this.feld[0].length;
}
/**
* Gibt eine Liste von Robotern zurück, die sich am nächsten zum
* angegebenen Punkt befinden. Insbesondere enthält die Liste einen
* Roboter, wenn er sich genau auf dem Punkt befindet.
* Die Koordinate bezieht sich dabei auf das NORMIERTE Feld.
* Die Liste ist sortiert bezüglich der Entfernung zum Punkt. Der nächste
* Roboter hat Index 0 -- Im Fall, dass ein Roboter direkt auf dem Punkt
* steht, hat er also den Index 0.
*
* @param x X-Koordinate
* @param y Y-Koordinate
* @param anzahl Wie viele Roboter zurückgegeben werden sollen.
*
* @return Die Roboter, die sich im Darstellungsfeld am nächsten zu der
* Koordinate befinden.
*/
public Roboter[] holeNahe(final double x, final double y,
final int anzahl) {
Roboter[] naechste = new Roboter[anzahl];
Roboter[] alle = new Roboter[this.akteure.size()];
double[] alleEntf = new double[this.akteure.size()];
Iterator<Roboter> it = this.akteure.iterator();
double min;
int minInd;
int i = 0;
while (it.hasNext()) {
alle[i] = it.next();
alleEntf[i] = this.entfernung(x, y,
alle[i].getPosition().x,
alle[i].getPosition().y);
i++;
}
for (int j = 0; j < anzahl; j++) {
min = Double.MAX_VALUE;
minInd = 0;
for (int k = 0; k < alleEntf.length; k++) {
if (alleEntf[k] < min) {
min = alleEntf[k];
minInd = k;
}
}
naechste[j] = alle[minInd];
alleEntf[minInd] = Double.MAX_VALUE;
}
return naechste;
}
/**
* Gibt den Roboter zurück, der sich am nächsten zum
* angegebenen Punkt befindet. Die Koordinate bezieht sich dabei auf das
* NORMIERTE Feld.
*
* @param x X-Koordinate
* @param y Y-Koordinate
* @param nicht Welche Roboter nicht zurückgegeben werden sollen.
*
* @return Der Roboter, der sich im normierten Feld am nächsten zu der
* Koordinate befindet.
*/
public Roboter holeNahenNorm(final int x, final int y,
final HashSet<Roboter> nicht) {
final double xx = x;
final double yy = y;
double minEntf = Double.MAX_VALUE;
double aktEntf;
Iterator<Roboter> it = this.akteure.iterator();
Roboter naechster = null;
Roboter aktRob;
while (it.hasNext()) {
aktRob = it.next();
aktEntf = this.entfernung(xx, yy,
aktRob.getPosition().x, aktRob.getPosition().y);
if (aktEntf < minEntf) {
if (!nicht.contains(aktRob)) {
minEntf = aktEntf;
naechster = aktRob;
}
}
}
return naechster;
}
/**
* 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<Roboter> it = this.getAgenten().iterator();
Roboter aktEur;
while (it.hasNext()) {
aktEur = it.next();
if (kleinste <= aktEur.getId()) {
kleinste = aktEur.getId() + 1;
}
}
return kleinste;
}
/**
* übernimmt die übergebenen Roboter (als Robotercode) in die Population.
* Dabei werden zuerst die bereits auf dem Feld vorhandenen Roboter mit
* den neuen Automaten versehen (wobei versucht wird, die IDs zu matchen);
* falls es weniger neue als alte Roboter gibt, werden die übrigen vom
* Spielfeld gelöscht; falls es mehr neue als alte Roboter gibt, werden
* entsprechend viele neu erzeugt.
*
* Die alten Roboter, deren Code durch neuen ersetzt werden soll, werden
* als "Hüllen" bezeichnet.
*
* @param semiPop Die (möglicherweise wegen doppelten IDs ungültige)
* Population von neuen Robotern im Robotercode-Format.
*/
protected void uebernimmPop(final ArrayList<RobCode> semiPop) {
Iterator<Roboter> itAkt;
Roboter rob;
RobCode robC;
Iterator<RobCode> itSemi;
Translator[] stdTrans
= new Translator[1];
// ursprünglich: Translator[] stdTrans
// = new Translator[semiPop.get(0).getVCodes().length];
for (int i = 0; i < stdTrans.length; i++) {
if (this.pars.getParValueBoolean("UseTranslatorWITHCompletingTransitions")) {
stdTrans[i]
= ConstantsTranslator.getStdTranslatorTR(this.pars);
} else {
stdTrans[i]
= ConstantsTranslatorWOC.getStdTranslatorTR(this.pars);
}
}
itAkt = this.akteure.iterator();
itSemi = semiPop.iterator();
while (itAkt.hasNext() && itSemi.hasNext()) {
rob = itAkt.next();
robC = itSemi.next();
rob.erzTransAusSeqs(robC.getTStdCodes(), stdTrans, false);
rob.erzeugeAusSequenzen(robC.getVCodes(), rob.getConds(),
rob.getTranslatoren(), false);
rob.setTransCodes(StaticMethods.listSeqAusStrings(robC.getTCodes()));
rob.setVerhCodes(StaticMethods.listSeqAusStrings(robC.getVCodes()));
rob.setFitness(robC.getFitness());
// rob.setConds(rob2.getConds()); TODO
}
}
/**
* @return Returns the feld.
*/
public byte[][] getFeld() {
return this.feld;
}
/**
* Setzt ein Flag, dass keine Simulation läuft.
*/
public void setSimEndeFlag() {
this.simLaeuft = false;
}
/**
* Erzwingt ein Ende des aktuellen Simulationslaufs; ACHTUNG: Danach
* wird das Programm unter allen Umst�nden beendet.
*/
public void beendeSimulation() {
this.getSimulation().getSimZeit().zeitBeenden();
// System.exit(0);
}
/**
* @return Returns the neuerPixel.
*/
public Pixel2D_08Bit getNeuerPixel2D() {
return this.neuerPixel2D;
}
/**
* @return Returns the simLaeuft.
*/
public boolean isSimLaeuft() {
return this.simLaeuft;
}
/**
* Setzt eine Pixelliste in das Feld (Kollisionen werden nicht beachtet,
* die Pixel werden unbedingt gesetzt.
*
* @param liste Die zu setzenden Pixel.
*/
protected void setzePixelliste(final List<Point> liste) {
if (liste != null) {
for (Point p : liste) {
this.setzePixel(p.x, p.y, ConstantsSimulation.FARBE_RAHMEN,
true, false, true, false);
}
}
}
/**
* Setzt eine Pixelliste in das Feld.
*
* @param liste Die zu setzenden Pixel.
* @param farbe Die Farbe, auf die der Pixel gesetzt werden soll.
* @param setzen Ob das Pixel in das Feld gesetzt werden soll und die
* Observer informiert werden sollen.
* @param temp Ob das Pixel NICHT in die Liste der zu zeichnenden
* Pixel übernommen werden soll.
* @param unbed Wenn setzen true ist und dieser Parameter true ist,
* dann wird das Pixel gesetzt, auch wenn es vorher schon
* dieselbe Farbe hatte.
* @param passiv Ob das Pixel nur gesetzt werden soll, wenn das Feld
* die Hintergrundfarbe oder die durchl�ssige Farbe hat.
*
* @return Ob das Pixel ohne Kollision gesetzt werden kann.
*/
private boolean setzePixelliste(
final List<Point> liste,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed,
final boolean passiv) {
boolean alleGesetzt = true;
if (liste != null) {
for (Point p : liste) {
alleGesetzt = alleGesetzt & this.setzePixel(
p.x,
p.y,
farbe,
setzen,
temp,
unbed,
passiv);
}
}
return alleGesetzt;
}
/**
* Setzt alle Pixel-Felder der Umgebung neu.
*/
public void alleFelderNeu() {
Iterator<Roboter> it;
byte farbe;
Roboter aktRob;
for (int i = 0; i < feld.length; i++) {
for (int j = 0; j < feld[0].length; j++) {
this.setzePixel(i, j, ConstantsSimulation.FARBE_HGND,
true, false, false, false);
}
}
this.setzeFeld(ConstantsSimulation.FARBE_RAHMEN);
this.setzeGgste(ConstantsSimulation.FARBE_GGSTD);
this.setzeDynWaende();
it = this.akteure.iterator();
while (it.hasNext()) {
aktRob = it.next();
if (aktRob.isSelektiert()) {
farbe = ConstantsSimulation.FARBE_SEL;
} else {
farbe = ConstantsSimulation.FARBE_ROB;
}
this.setzeRobWennMoegl(aktRob, true, farbe, "");
}
}
/**
* Setzt einige zentrale Eigenschaften eines Roboters, identifiziert durch
* seine ID.
*
* @param id Die ID des Roboters.
* @param vAutStd Die Verhaltensautomaten in Standardkodierung.
* @param vAut Die echten Verhaltensautomatencodes.
* @param tAutStd Die Translatoren in Standardkodierung.
* @param tAut Die echten Translatorencodes.
* @param koord Die Koordinaten des Roboters.
* @param winkel Der Winkel der Blickrichtung.
* @param fitness Die Fitnesswerte des Roboters.
* @param conds Die Bedingungen.
*
* @return Ob alle Eigenschaften zugewiesen werden konnten.
*/
public boolean setEigRobUnbed(
final int id,
final String[] vAutStd,
final String[] vAut,
final String[] tAutStd,
final String[] tAut,
final Vector2D koord,
final double winkel,
final int[] fitness,
final Condition[] conds) {
Roboter aktRob;
Iterator<Roboter> it = this.akteure.iterator();
Translator[] stdTrans = new Translator[tAutStd.length];
for (int i = 0; i < stdTrans.length; i++) {
if (this.pars.getParValueBoolean("UseTranslatorWITHCompletingTransitions")) {
stdTrans[i]
= ConstantsTranslator.getStdTranslatorTR(this.pars);
} else {
stdTrans[i]
= ConstantsTranslatorWOC.getStdTranslatorTR(this.pars);
}
}
while (it.hasNext()) {
aktRob = it.next();
if (aktRob.getId() == id) {
aktRob.erzTransAusSeqs(tAutStd, stdTrans, false);
aktRob.erzeugeAusSequenzen(vAutStd, conds, null, false);
aktRob.setRobUnbed(koord.x, koord.y, winkel);
aktRob.setFitness(fitness);
aktRob.setTransCodes(StaticMethods.listSeqAusStrings(tAut));
aktRob.setVerhCodes(StaticMethods.listSeqAusStrings(vAut));
break;
}
}
return true;
}
/**
* @return Returns the gegVerschieb.
*/
public ArrayList<Vector2D> getGegVerschieb() {
return this.gegVerschieb;
}
/**
* Gibt die Summe der Fitnesswerte aller Roboter der Population zurück.
*
* @return Die Durchschnittswerte der Fitnesswerte der Population.
*/
public String getDurchFit() {
if (this.akteure.size() == 0) {
return "Keine Roboter vorhanden.";
}
Roboter rob = this.akteure.get(0);
int vAnzahl = 0;
double[] fitness = new double[rob.vAuts().length];
String s = "";
Iterator<Roboter> it = this.akteure.iterator();
while (it.hasNext()) {
rob = it.next();
for (int i = 0; i < rob.vAuts().length; i++) {
fitness[i] += rob.getFitness()[i];
vAnzahl++;
}
}
for (int i = 0; i < rob.vAuts().length - 1; i++) {
fitness[i] /= vAnzahl;
s += Math.round(fitness[i] * 10) / 10 + ", ";
vAnzahl++;
}
s += Math.round(fitness[rob.vAuts().length - 1] * 10) / 10 / vAnzahl;
return s;
}
/**
* @return Der bester Roboter. null, falls keiner existiert.
*/
public Roboter getBester() {
if (this.akteure.size() == 0) {
return null;
}
long maxFit = Long.MIN_VALUE;
Roboter bester = null;
for (Roboter r : this.akteure) {
if (r.getFitSum() > maxFit) {
maxFit = r.getFitSum();
bester = r;
}
}
return bester;
}
/**
* Setzt die Positionen der Roboter zufällig und setzt die Fitness zurück.
*/
public void resetRobs() {
ArrayList<Roboter> akt = new ArrayList<Roboter>(this.akteure.size());
akt.addAll(this.akteure);
for (Roboter r : akt) {
r.resetAnzUnf();
for (int i = 0; i < r.getVAut().length; i++) {
r.resetAktivZyk(i);
r.setFitness(i, 0);
}
this.loescheRoboter(r);
this.hinzuRobotRand(r);
}
}
/**
* @return Returns the dynDrehMittPkt.
*/
public Vector2D[] getDynDrehMittPkte() {
return this.tatdynDrehMittPkt;
}
/**
* @param drehMittPkt The dynDrehMittPkt to set.
* @param wandNum Die Nummer der Wand.
*/
public void setDynDrehMittPkt(
final int wandNum,
final Vector2D drehMittPkt) {
if (this.tatdynDrehMittPkt[wandNum] == null
|| !this.tatdynDrehMittPkt[wandNum].equals(drehMittPkt)) {
StaticMethods.log(
StaticMethods.LOG_DEBUG,
"Dynamischer Drehmittelpunkt " + wandNum
+ " wurde verändert: " + drehMittPkt,
this.pars);
this.tatdynDrehMittPkt[wandNum] = drehMittPkt;
}
}
/**
* @return Returns the dynWaende.
*/
public Polygon2D[] getDynWaende() {
return this.dynWaende;
}
/**
* @return Returns the dynVersch.
*/
public Vector2D[] getDynVersch() {
return this.dynVersch;
}
/**
* @return Returns the dynDrehWinkel.
*/
public double[] getDynDrehWinkel() {
return this.dynDrehWinkel;
}
/**
* @return Returns the aktDynPixel.
*/
public ArrayList<LinkedList<Point>> getAktDynPixel() {
return this.aktDynPixel;
}
/**
* @param className Die Klasse des Plugins.
*
* @return Das erste Plugin, das der entsprechenden Klasse entspricht.
* null, falls es kein Plugin dieser Klasse gibt.
*/
public Plugin<?> getPluginObject(final Class<?> className) {
for (Plugin<?> p : this.plugins) {
if (p.getClass().equals(className)) {
return p;
}
}
return null;
}
/**
* @param className Die Klasse des Plugins.
*
* @return Ob ein Plugin dieses Typs existiert.
*/
public boolean existsPlugin(final Class<?> className) {
return this.getPluginObject(className) != null;
}
/**
* Generische Zustände der Roboters.
*/
private HashMap<Integer, GenericState> zustaende;
/**
* @return Returns the zustaende.
*/
public HashMap<Integer, GenericState> getZustaende() {
return this.zustaende;
}
/**
* Abbildung von Zustandsnamen zu internen Nummern.
*/
private HashMap<String, Integer> stateMapping;
/**
* Zustandsnummernzähler.
*/
private int stateCounter = ConstantsSimulation.MAX_INST_BEH + 1;
/**
* fügt einen generischen Zustand zur Umgebung hinzu, die alle Roboter
* besitzen.
*
* @param gs Der generische Zustand.
*/
public void addGenericState(final GenericState gs) {
if (this.zustaende == null) {
this.zustaende = new HashMap<Integer, GenericState>();
}
if (this.stateMapping == null) {
this.stateMapping = new HashMap<String, Integer>();
}
this.zustaende.put(this.stateCounter, gs);
this.stateMapping
.put(gs.stateName().substring(0, 3), this.stateCounter);
this.stateCounter++;
}
/**
* @param name Der Name des Zustands.
*
* @return Der Zustand.
*/
public GenericState getGenState(final String name) {
return this.getGenState(this.stateMapping.get(name));
}
/**
* @param name Sensorname.
*
* @return Der interne Name.
*/
public int getGenStateInternalNum(final String name) {
return this.stateMapping.get(name);
}
/**
* @param nummer Die Nummer des Zustands.
*
* @return Der Zustand.
*/
public GenericState getGenState(final int nummer) {
return this.zustaende.get(nummer);
}
/**
* @return Die generischen Zustände.
*/
public HashMap<Integer, GenericState> getGenericStates() {
return this.zustaende;
}
}