/*
* Datei: EnvironmentEA.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.simulation.spatial.sim2D.marbSimulation;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
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.Random;
import java.util.Set;
import eas.math.geometry.Pixel2D_08Bit;
import eas.math.geometry.Polygon2D;
import eas.math.geometry.Rectangle2D;
import eas.math.geometry.Vector2D;
import eas.miscellaneous.StaticMethods;
import eas.plugins.Plugin;
import eas.plugins.standard.eaPlugin.EAPlugin;
import eas.simulation.ConstantsSimulation;
import eas.simulation.Wink;
import eas.simulation.agent.AbstractAgent;
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.simulation.spatial.sim2D.standardEnvironments.AbstractEnvironment2D;
import eas.simulation.standardEnvironments.AbstractEnvironment;
import eas.startSetup.ParCollection;
import eas.startSetup.SingleParameter;
import eas.startSetup.parameterDatatypes.Datatypes;
import eas.users.other.sabrina.age.AgePlugin;
/**
* Repräsentiert ein Feld, auf dem Roboter fahren können.
*
* @author Lukas König
*/
public class EnvironmentEA extends AbstractEnvironment2D<RobEA> {
private static final long serialVersionUID = 8598151098765814500L;
/**
* Name der Bitmapdatei, aus der die Umgebung gelesen wird.
*/
private String umgebungsBMP;
/**
* Die Umgebung als Pixelfeld, so wie sie eingelesen wurde.
*/
private byte[][] inputField;
/**
* 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<RobEA> 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.
*/
@Override
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;
/**
* Plugins für diesen Lauf.
*/
private LinkedList<Plugin<?>> plugins;
public EnvironmentEA(
final Random zufall,
final int id,
final ParCollection params,
final LinkedList<Plugin<?>> plugins2,
final String envID) {
this(zufall, id, null, params, plugins2, envID);
}
/**
* 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 plugins2 Die Plugins für diese Umgebung.
* @param envID The environment's id.
* @param fatherEnvironment The environment this environment ist part of
* (may be null if this is a top level
* environment (most common case)).
*/
public EnvironmentEA(
final Random zufall,
final int id,
final AbstractEnvironment<?> fatherEnv,
final ParCollection params,
final LinkedList<Plugin<?>> plugins2,
final String envID) {
super(envID, id, fatherEnv, params);
this.umgebungsBMP = params.getParValueString(EAPlugin.UMGEBUNG_ATTR);
this.pars = params;
this.rand = zufall;
this.plugins = plugins2;
// Feld initialisieren:
String dat = params.getStdDirectory() + File.separator + this.umgebungsBMP;
initialisiereFeld(params, dat);
}
/**
* @param params
* @param dat
*/
private void initialisiereFeld(final ParCollection params, String dat) {
int arrGroesse = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
try {
this.inputField = StaticMethods.liesImage(dat);
} catch (final Exception e) {
StaticMethods.log(
StaticMethods.LOG_ERROR,
"Bitmap-Feld nicht geladen: " + dat + ".",
params);
}
this.existsVideoPlug = false;
this.drawPixel2D = new LinkedList<Pixel2D_08Bit>();
this.buffImgFeld = new BufferedImage(
this.inputField.length,
this.inputField[0].length,
BufferedImage.TYPE_INT_RGB);
this.graphicsObject = buffImgFeld.createGraphics();
graphicsObject.setColor(Color.white);
graphicsObject.fillRect(
0,
0,
this.buffImgFeld.getWidth(),
this.buffImgFeld.getHeight());
// this.dynWaendeIgnor = false;
this.simLaeuft = true;
this.gegKoll = null;
byte[][] feldPix = this.inputField;
this.aktDynPixel = new ArrayList<LinkedList<Point>>(arrGroesse);
for (int i = 0; i < arrGroesse; i++) {
this.aktDynPixel.add(null);
}
this.feld = new byte[feldPix.length][feldPix[0].length];
this.akteure = new ArrayList<RobEA>();
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);
}
StaticMethods.log(
StaticMethods.LOG_INFO,
"Environment-EA [" + this.getEnvironmentName() + "] erzeugt:\n" + this,
params);
}
/**
* 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++;
}
}
}
}
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.inputField);
}
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.inputField);
}
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.inputField);
}
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.inputField;
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.inputField;
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);
}
}
}
}
@Override
public Polygon2D getPolygonInVisualization(Polygon2D polInEnv) {
return polInEnv;
}
/**
* 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.
*/
// @Override
public boolean hinzuRobot(final RobEA roboter) {
byte farbe;
String text = "";
if (this.inputField[(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.getEckp().nPoints()];
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)) {
super.addAgent(roboter);
return true;
} else {
this.akteure.remove(roboter);
this.akteurPunkte.remove(eckpunkte);
this.akteurTexte.remove(text);
return false;
}
}
/**
* @return The position of the agent.
*/
@Override
public Vector2D getAgentPosition(int agentID) {
for (RobEA r : this.akteure) {
if (r.id() == agentID) {
return r.getPosition();
}
}
return null;
}
/**
* @param agentID The id of the agent.
* @return The angle of the view direction of the agent.
*/
@Override
public Double getAgentAngle(int agentID) {
for (RobEA r : this.akteure) {
if (r.id() == agentID) {
return r.getAngle();
}
}
return null;
}
@Override
public Polygon2D getAgentShape(int agentID) {
for (RobEA r : this.akteure) {
if (r.id() == agentID) {
return r.getEckp();
}
}
return null;
}
@Override
public synchronized Polygon2D getAgentShapeInVisualization(int agentID) {
for (RobEA r : this.akteure) {
if (r.id() == agentID) {
return r.getEckp();
}
}
return null;
}
@Override
public synchronized Polygon2D getAgentShapeInVisualization(int agentID,
double screenWidthOneTime, double screenHeightOneTime,
Rectangle2D zoomBoxOneTime) {
return this.getAgentShapeInVisualization(agentID);
}
/**
* fügt einen Roboter an eine zufällige Stelle in der Umgebung ein.
*
* @param rob Der einzufügende Roboter.
*/
public void hinzuRobotRand(final RobEA 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);
}
super.addAgent(rob);
}
/**
* Versetzt einen Roboter zufällig im Feld. Tabu-Felder werden nicht
* besetzt.
*
* @param rob Der zu versetzende Roboter.
*/
public void setzeRobotRand(final RobEA rob) {
boolean gesetzt = false;
Vector2D vek;
while (!gesetzt) {
vek = new Vector2D(
this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY());
if (this.inputField[(int) vek.x][(int) vek.y]
!= ConstantsSimulation.FARBE_INP_TABU) {
gesetzt = rob.setPos(
vek.x,
vek.y,
false);
} else {
gesetzt = false;
}
gesetzt = gesetzt && rob.setAngle(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.
* @param temp Ob das Pixel NICHT in die Liste der zu zeichnenden Pixel
* aufgenommen werden soll.
*/
public void entferneRoboter(final RobEA 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 removeAgent(final RobEA robot) {
if (this.akteure.contains(robot)) {
this.entferneRoboter(robot);
this.akteure.remove(robot);
super.removeAgent(robot.id());
return true;
} else {
return false;
}
}
@Override
public boolean removeAgent(final int robotID) {
if (!super.removeAgent(robotID)) {
return false;
}
for (RobEA a : this.akteure) {
if (a.id() == robotID) {
return removeAgent(a);
}
}
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 RobEA robot,
final boolean gegKollIgnore,
final byte farbe,
final String text) {
boolean alleFrei = true;
Vector2D[] neueEcken = new Vector2D[robot.getEckp().nPoints()];
for (int i = 0; i < robot.getEckp().nPoints(); i++) {
neueEcken[i] = robot.getEckp().get(i);
}
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 (this.existsVideoPlug) {
this.drawPixel2D.add(new Pixel2D_08Bit(x, y, farbe));
}
// TODO: Nächste IF-Bedingung überflüssig, wenn keine Observer.
if (this.isVisualized() && !temp) {
this.neuerPixel2D = new Pixel2D_08Bit(x, y, farbe);
this.setChanged();
this.notifyObservers();
}
}
}
return frei;
}
/**
* If the videoplugin exists.
*/
private boolean existsVideoPlug = false;
/**
* Pixel list to be drawn by videoplugin.
*/
private LinkedList<Pixel2D_08Bit> drawPixel2D;
// /**
// * 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 += "Umgebungsdateiname : " + this.umgebungsBMP + "\n";
s += "Umgebungsgroesse : "
+ this.inputField.length + " x "
+ this.inputField[0].length
+ " Pixel\n";
s += "\n" + StaticMethods.feldAusgabe(
this.inputField,
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 RobEA 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.
*/
@Override
public List<RobEA> getAgents() {
return new ArrayList<RobEA>(this.akteure);
}
/**
* @return The agents in RobEA type.
*/
public ArrayList<RobEA> getRobAgents() {
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 RobEA[] holeNahe(final double x, final double y,
final int anzahl) {
RobEA[] naechste = new RobEA[anzahl];
RobEA[] alle = new RobEA[this.akteure.size()];
double[] alleEntf = new double[this.akteure.size()];
Iterator<RobEA> 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 RobEA holeNahenNorm(final int x, final int y,
final HashSet<RobEA> nicht) {
final double xx = x;
final double yy = y;
double minEntf = Double.MAX_VALUE;
double aktEntf;
Iterator<RobEA> it = this.akteure.iterator();
RobEA naechster = null;
RobEA 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;
for (RobEA aktEur : this.getAgents()) {
if (kleinste <= aktEur.id()) {
kleinste = aktEur.id() + 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.
*/
public void uebernimmPop(final ArrayList<RobCode> semiPop) {
Iterator<RobEA> itAkt;
RobEA 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());
/*
* Anmerkung (Sabrina): hier wird die Methode aufgerufen, die das Alter
* aller erreichbaren Knoten und Kanten erhöht, sollte nur in Verbindung mit
* dem AgePlugin aufgerufen werden.
*/
if (this.getPars().getPlugIDList().contains(new AgePlugin().id())) {
rob.aging();
}
// 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.getSimTime().timeTerminate();
}
/**
* @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<RobEA> it;
byte farbe;
RobEA 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, "");
}
if (this.existsVideoPlug) {
this.drawPixel2D.clear();
for (int i = 0; i < feld.length; i++) {
for (int j = 0; j < feld[0].length; j++) {
this.drawPixel2D.add(new Pixel2D_08Bit(i, j, feld[i][j]));
}
}
}
}
/**
* 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) {
RobEA aktRob;
Iterator<RobEA> 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.id() == 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.";
}
RobEA rob = this.akteure.get(0);
int vAnzahl = 0;
double[] fitness = new double[rob.vAuts().length];
String s = "";
Iterator<RobEA> 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 RobEA getBester() {
if (this.akteure.size() == 0) {
return null;
}
long maxFit = Long.MIN_VALUE;
RobEA bester = null;
for (RobEA 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<RobEA> akt = new ArrayList<RobEA>(this.akteure.size());
akt.addAll(this.akteure);
for (RobEA r : akt) {
r.resetAnzUnf();
for (int i = 0; i < r.getVAut().length; i++) {
r.resetAktivZyk(i);
r.setFitness(i, 0);
}
this.removeAgent(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 id Der Name des Plugins.
*
* @return Das (erste) Plugin, das den Namen hat.
* null, falls es kein Plugin dieses Namens gibt.
*/
public Plugin<?> getPluginObject(final String id) {
return this.getSimTime().getPluginObject(id);
}
/**
* @param id Die ID des Plugins.
*
* @return Ob ein Plugin dieses Typs existiert.
*/
public boolean existsPlugin(final String id) {
return this.getPluginObject(id) != 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;
}
/**
* @return Returns the plugins.
*/
public LinkedList<Plugin<?>> getPlugins() {
return this.plugins;
}
@Override
public void step(final Wink cyc) {
if (cyc.getLastTick() % 500 == 50) {
this.alleFelderNeu();
}
}
private transient BufferedImage buffImgFeld;
private transient Graphics2D graphicsObject;
private LinkedList<Polygon2D> zuZeichnen = new LinkedList<Polygon2D>();
public void addZuZeichnenPolygon(Polygon2D pol) {
this.zuZeichnen.add(pol);
}
@Override
public double getScreenHeight() {
return this.buffImgFeld.getHeight();
}
@Override
public double getScreenWidth() {
return this.buffImgFeld.getWidth();
}
@Override
public synchronized BufferedImage getOutsideView(Graphics2D g2) {
this.alleFelderNeu();
BufferedImage img = this.getOutsideView();
g2.drawImage(img, 0, 0, null);
return img;
}
/**
* A view of the current state of the environment.
*/
@Override
public synchronized BufferedImage getOutsideView() {
Graphics2D g;
// if (this.graphicsObject != null) {
// } else {
// this.buffImgFeld = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
// this.graphicsObject = this.buffImgFeld.createGraphics();
// this.requestRedraw();
// this.alleFelderNeu();
// return new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
// }
g = this.graphicsObject;
for (Pixel2D_08Bit p : this.drawPixel2D) {
int i = (int) p.x;
int j = (int) p.y;
byte farbe = p.color();
if (farbe == ConstantsSimulation.FARBE_ROB) {
g.setColor(ConstantsSimulation.C_VORDERGRUND);
} else if (farbe == ConstantsSimulation.FARBE_RAHMEN) {
g.setColor(ConstantsSimulation.C_RAHMEN);
} else if (farbe == ConstantsSimulation.FARBE_GGSTD) {
g.setColor(ConstantsSimulation.C_GEGENSTAND);
} else if (farbe == ConstantsSimulation.FARBE_HGND) {
g.setColor(ConstantsSimulation.C_HINTERGRUND);
} else if (farbe == ConstantsSimulation.FARBE_SEL) {
g.setColor(ConstantsSimulation.C_SPEZIAL);
} else if (farbe == ConstantsSimulation.FARBE_DURCHLAESSIG) {
g.setColor(ConstantsSimulation.C_DURCHLAESSIG);
//
} else if (farbe == ConstantsSimulation.FARBEN_BENUTZER[0]) {
g.setColor(ConstantsSimulation.C_SPEZIAL);
} else if (farbe == ConstantsSimulation.FARBEN_BENUTZER[1]) {
g.setColor(ConstantsSimulation.C_RAHMEN);
//
} else {
g.setColor(Color.white);
}
g.drawLine(i, j, i, j);
}
this.drawPixel2D.clear();
int i = 23;
for (Polygon2D p : this.zuZeichnen) {
g.setColor(new Color(120, 180, i));
g.drawPolygon(p.toPol());
i = (i + 101) % 256;
}
this.zuZeichnen.clear();
// return super.generateEnvironmentView();
return buffImgFeld;
}
@Override
public Vector2D getPositionInVisualization(int agentID) {
return this.getAgentPosition(agentID);
}
@Override
public RobEA getAgent(int agentID) {
for (RobEA r : this.akteure) {
if (r.id() == agentID) {
return r;
}
}
return null;
}
/**
* Adds a visualizing plugin to this environment. The information if a
* visualizer is currently observing the environment should be passed on
* to agents and generic sensors to provide them with the possibility of
* omitting expensive visualization computations as long as no visualizers
* are available. Any Plugin that uses the methods getFieldView,
* getControllerView, and getSensorView of the classes AbstractEnvironment,
* AbstractAgent, and GenericSensor, resp., has to add itself to this
* list.
*
* @param vis The observing visualization.
*/
@Override
public void addVisualizer(final Plugin<?> vis) {
super.addVisualizer(vis);
if (super.isVisualized()) {
this.existsVideoPlug = true;
} else {
this.existsVideoPlug = false;
this.drawPixel2D.clear();
}
}
/**
* Removes a visualizing plugin from this environment. The information if a
* visualizer is currently observing the environment should be passed on
* to agents and generic sensors to provide them with the possibility of
* omitting expensive visualization computations as long as no visualizers
* are available.
*
* @param vis The observing visualization.
*/
@Override
public void removeVisualizer(final Plugin<AbstractEnvironment<AbstractAgent<?>>> vis) {
super.removeVisualizer(vis);
if (super.isVisualized()) {
this.existsVideoPlug = true;
} else {
this.existsVideoPlug = false;
this.drawPixel2D.clear();
}
}
/**
* @return Der Umgebungsbitmapdateiname.
*/
public String getUmgebungDatname() {
return this.umgebungsBMP;
}
/**
* Gibt die Belegung eines Feldes als Pixelarray zurück.
*
* @return Das Pixelarray.
*/
public byte[][] getInputFeld() {
return this.inputField;
}
/**
* Setzt das Feld neu.
*
* @param neuesFeld Das neue Feld.
*/
public void setFeld(final byte[][] neuesFeld) {
this.inputField = neuesFeld;
}
@Override
public synchronized void requestRedraw() {
super.requestRedraw();
// this.drawPixel2D.clear();
}
@Override
public List<SingleParameter> getParameters() {
List<SingleParameter> list = super.getParameters();
list.add(new SingleParameter(
eas.statistics.ConstantsStatistics.VERZERR_ATTR,
Datatypes.DOUBLE,
ConstantsSimulation.VERZERR,
"Die Verzerrungs-Konstante für Roboter.",
"Environment_EA"));
list.add(new SingleParameter(
eas.statistics.ConstantsStatistics.BEZIER_KONST,
Datatypes.DOUBLE,
eas.startSetup.marbBuilder.zeichenModi.ConstantsZeichenModi.BEZ_NORMAL,
"Die Bezier-Konstante (je kleiner, desto feiner).",
"Environment_EA"));
list.add(new SingleParameter(
eas.statistics.ConstantsStatistics.EINFACHE_DARSTELLUNG,
Datatypes.BOOLEAN,
true,
"Ob einfache Darstellung für MARBs ausgewählt ist.",
"Environment_EA"));
list.add(new SingleParameter(
"GraphVizTEMPDIR",
Datatypes.STRING,
"C:/temp",
"Das Verzeichnis, in dem das GraphViz-Interface temporäre Dateien speichert.",
"Environment_EA"));
list.add(new SingleParameter(
"GraphVizStartDotFile",
Datatypes.STRING,
"C:/Program Files (x86)/Graphviz2.34/bin/dot.exe",
"Die Startdatei (dot.exe) für GraphViz.",
"Environment_EA"));
return list;
}
public Random getRand() {
return this.rand;
}
@Override
public void onSimulationResumed() {
super.onSimulationResumed();
int imgWidth = this.inputField.length;
int imgHeight = this.inputField[0].length;
this.buffImgFeld = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
this.graphicsObject = this.buffImgFeld.createGraphics();
this.requestRedraw();
this.alleFelderNeu();
}
}