/*
* Datei: Umgebung.java
* Autor(en): Lukas K�nig
* Java-Version: 6.0
* Erstellt (vor): 05.05.2007
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/
package fmg.fmg8.umgebung2D;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
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 fmg.fmg8.endlAutomat.RobCode;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.endlAutomat.translator.Translator;
import fmg.fmg8.graphVis.DargestellterGraph;
import fmg.fmg8.graphVis.darstellungsModi.DarstModEA;
import fmg.fmg8.graphVis.graph.Knoten;
import fmg.fmg8.graphVis.zeichenModi.Geometrie2D;
import fmg.fmg8.graphVis.zeichenModi.PfeilMaster;
import fmg.fmg8.graphVis.zeichenModi.Polygon2D;
import fmg.fmg8.sonstiges.SonstMeth;
import fmg.fmg8.statistik.Parametersatz;
import fmg.fmg8.umgebung2D.dynWaende.Dynamik;
/**
* 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<Vektor2D[]> akteurPunkte;
/**
* Die aktuell zu den Robotern dargestellten Informationstexte.
*/
private ArrayList<String> akteurTexte;
/**
* Der Zufallsgenerator.
*/
private Random rand;
/**
* Die Parameter.
*/
private Parametersatz pars;
/**
* @return Returns the pars.
*/
public Parametersatz getPars() {
return this.pars;
}
/**
* Der neu gesetzte Pixel.
*/
private Pixel neuerPixel;
/**
* Flag, ob Simulation l�uft.
*/
private boolean simLaeuft;
/**
* Liste von Gegenst�nden.
*/
private ArrayList<HashMap<Vektor2D, Object>> gegenstaende;
/**
* Die Verschiebung der Gegenst�nde.
*/
private ArrayList<Vektor2D> gegVerschieb;
/**
* Die Liste der dynamischen W�nde, sortiert nach Farben der W�nde.
*/
private Polygon2D[] dynWaende;
/**
* Die Liste der zu den dynamischen W�nden geh�renden
* Verschiebungsvektoren.
*/
private Vektor2D[] dynVersch;
/**
* Die Liste der alten Verschiebungen.
*/
private Vektor2D[] dynOldVersch;
/**
* Ob die dynamischen W�nde gesetzt sind.
*/
private boolean[] dynGesetzt;
/**
* Drehwinkel der Objekte.
*/
private double[] dynDrehWinkel;
/**
* Drehwinkel der Objekte.
*/
private double[] dynDrehWinkelOld;
/**
* Drehmittelpunkt relativ zum Zentrum des Objekts.
*/
private Vektor2D[] dynDrehMittPkt;
/**
* Horizontaler Verzerrungsfaktor.
*/
private double[] dynHorFaktor;
/**
* Alter horizontaler Verzerrungsfaktor.
*/
private double[] dynHorFaktorOld;
/**
* 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 Vektor2D 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;
/**
* Das f�r die Dynamik der W�nde verwendete Objekt.
*/
private Dynamik wandDynamik;
/**
* @return Returns the simulation.
*/
public Simulation getSimulation() {
return this.simulation;
}
/**
* 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 Wanddynamik f�r diese Umgebung.
*/
public Umgebung(final Random zufall,
final Parametersatz params,
final Observer obs,
final Simulation sim,
final Dynamik wandDyn) {
int arrGroesse = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
this.pars = params;
if (this.pars.getGraphisch().booleanValue()) {
this.addObserver(obs);
}
this.wandDynamik = wandDyn;
this.simulation = sim;
this.dynWaendeIgnor = false;
this.simLaeuft = true;
this.gegKoll = null;
byte[][] feldPix = params.getFeld();
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<Vektor2D[]>();
this.akteurTexte = new ArrayList<String>();
this.gegenstaende = new ArrayList<HashMap<Vektor2D, Object>>();
this.gegVerschieb = new ArrayList<Vektor2D>();
this.erzeugeDynWaende(feldPix);
this.setzeDynWaende();
this.setzeFeld(Konstanten.FARBE_RAHMEN);
this.holeGegenstaende();
this.setzeGgste(Konstanten.FARBE_GGSTD);
if (this.gegenstaende.size() > 0) {
SonstMeth.log(
SonstMeth.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. Gibt zur�ck, ob die Wand
* verschoben werden konnte. 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++) {
this.setzeDynWand(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.dynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
Konstanten.FARBE_RAHMEN,
true,
true,
false);
if (alleFrei == null) {
this.setzeDynWand(
wandNum,
this.dynWaende[wandNum],
this.dynVersch[wandNum],
this.dynHorFaktor[wandNum],
this.dynVertFaktor[wandNum],
this.dynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
Konstanten.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),
Konstanten.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.dynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
Konstanten.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.dynDrehMittPkt[wandNum],
this.dynDrehWinkel[wandNum],
Konstanten.FARBE_RAHMEN,
true,
false,
false);
this.dynOldVersch[wandNum]
= new Vektor2D(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.dynDrehMittPkt[wandNum],
this.dynDrehWinkelOld[wandNum],
Konstanten.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 Vektor2D versch,
final double horzFakt,
final double vertFakt,
final Vektor2D drehMittPkt,
final double drehWinkel,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
Point nichtFrei = null;
Vektor2D aktPkt;
Iterator<Vektor2D> it = wand.iterator();
Vektor2D m = new Vektor2D(
wand.mittelpunkt().x + versch.x + drehMittPkt.x,
wand.mittelpunkt().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 (this.pars.getAufnSp()
&& nichtFrei == null
&& (farbe == Konstanten.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 Vektor2D[arrGroesse];
this.dynGesetzt = new boolean[arrGroesse];
this.dynOldVersch = new Vektor2D[arrGroesse];
this.dynDrehMittPkt = new Vektor2D[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] != Konstanten.FARBE_HGND
&& feldPix[i][j] != Konstanten.FARBE_HGND_INP
&& feldPix[i][j] != Konstanten.FARBE_RAHMEN
&& feldPix[i][j] != Konstanten.FARBE_INP_GEG
&& feldPix[i][j] != Konstanten.FARBE_INP_TABU) {
dynFarbe = feldPix[i][j] - Byte.MIN_VALUE;
if (this.dynWaende[dynFarbe] == null) {
this.dynWaende[dynFarbe] = new Polygon2D();
this.dynVersch[dynFarbe] = new Vektor2D(0, 0);
this.dynOldVersch[dynFarbe] = new Vektor2D(0, 0);
this.dynGesetzt[dynFarbe] = false;
this.dynDrehMittPkt[dynFarbe]
= new Vektor2D(Vektor2D.NULL_VEKTOR);
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 Vektor2D(i, j));
}
}
}
// L�sche Farben, die schon eine andere explizite Verwendung haben.
for (int i = 0; i < Konstanten.BENUTZTE_FARBEN.length; i++) {
this.dynWaende[(int) Konstanten.BENUTZTE_FARBEN[i] - Byte.MIN_VALUE]
= null;
this.dynVersch[(int) Konstanten.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) {
SonstMeth.log(
SonstMeth.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 Vektor2D versch) {
Point nichtFrei;
this.dynVersch[wandNum].setzeKoord(versch.x, versch.y);
nichtFrei = this.setzeDynWand(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 (x < 0 || y < 0) {
throw new RuntimeException("Verzerrung darf nicht negativ sein: "
+ new Vektor2D(x, y));
}
this.dynHorFaktor[wandNum] = x;
this.dynVertFaktor[wandNum] = y;
nichtFrei = this.setzeDynWand(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;
this.dynDrehWinkel[wandNum] = winkel * Math.PI / 180;
gesetzt = this.setzeDynWand(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<Vektor2D, Object> gegenstand,
final byte[][] feldPix) {
if (x < 0 || y < 0 || x >= feldPix.length || y >= feldPix[0].length) {
return;
}
if (feldPix[x][y] != Konstanten.FARBE_INP_GEG) {
return;
}
if (gegenstand.containsKey(new Vektor2D(x, y))) {
return;
}
gegenstand.put(new Vektor2D(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<Vektor2D, Object> gegenstand;
Vektor2D neuVek;
Iterator<HashMap<Vektor2D, Object>> it;
byte[][] feldPix = this.pars.getFeld();
boolean gefunden;
Vektor2D verschiebung;
for (int j = 0; j < feldPix[0].length; j++) {
for (int i = 0; i < feldPix.length; i++) {
if (feldPix[i][j] == Konstanten.FARBE_INP_GEG) {
neuVek = new Vektor2D(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<Vektor2D, Object>();
this.findeGgstd(i, j, gegenstand, feldPix);
this.gegenstaende.add(gegenstand);
verschiebung = new Vektor2D(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<Vektor2D, Object>> it = this.gegenstaende.iterator();
HashMap<Vektor2D, 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<Vektor2D, Object> ggst,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
boolean alleFrei = true;
Vektor2D aktVek;
Iterator<Vektor2D> it = ggst.keySet().iterator();
while (it.hasNext()) {
aktVek = (Vektor2D) 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.pars.getFeld();
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.pars.getFeld()[(int) roboter.getPosition().x]
[(int) roboter.getPosition().y]
== Konstanten.FARBE_INP_TABU) {
return false;
}
if (roboter.isSelektiert()) {
farbe = Konstanten.FARBE_SEL;
} else {
farbe = Konstanten.FARBE_ROB;
}
Vektor2D[] eckpunkte = new Vektor2D[roboter.getEckPunkte().length];
for (int i = 0; i < eckpunkte.length; i++) {
eckpunkte[i] = new Vektor2D(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 Vektor2D(this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY()));
rob.setBlickRicht(this.rand.nextDouble() * 360);
while (!this.hinzuRobot(rob)) {
rob.setPosition(new Vektor2D(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;
Vektor2D vek;
while (!gesetzt) {
vek = new Vektor2D(
this.rand.nextDouble() * this.ausdX(),
this.rand.nextDouble() * this.ausdY());
if (this.pars.getFeld()[(int) vek.x][(int) vek.y]
!= Konstanten.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,
Konstanten.FARBE_HGND,
true,
false,
false,
false);
}
}
this.setzeFeld(Konstanten.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 Roboter robot,
final boolean temp) {
if (this.akteure.contains(robot)) {
this.setzeRobWennMoegl(robot, true, Konstanten.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, true);
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 Vektor2D lu,
final Vektor2D ro,
final boolean setzen) {
Vektor2D lu2 = new Vektor2D(lu.x, ro.y);
Vektor2D ro2 = new Vektor2D(ro.x, lu.y);
byte farbe;
if (setzen) {
farbe = Konstanten.FARBE_DURCHLAESSIG;
} else {
farbe = Konstanten.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 Vektor2D lu,
final Vektor2D 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 Vektor2D linksUnten,
final boolean setzen) {
Vektor2D lu = new Vektor2D(linksUnten);
Vektor2D ro = new Vektor2D(linksUnten.x + Konstanten.TEXT_AUSDEHNUNG.x,
linksUnten.y + Konstanten.TEXT_AUSDEHNUNG.y);
Vektor2D verschiebung = new Vektor2D(Konstanten.TEXT_AUSDEHNUNG.x
+ Konstanten.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 Vektor2D[] eckP,
final byte farbe,
final boolean setzen,
final boolean temp,
final boolean unbed) {
final Vektor2D mitte = new Vektor2D((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<Vektor2D, Object> altGgst = this.gegenstaende.get(ggstID);
HashMap<Vektor2D, Object> neuGgst = new HashMap<Vektor2D, Object>();
Set<Vektor2D> ggst = altGgst.keySet();
Iterator<Vektor2D> it = ggst.iterator();
Vektor2D aktVek;
Vektor2D neuVek;
Vektor2D altVersch = (Vektor2D) this.gegVerschieb.get(ggstID);
Vektor2D neuVersch;
while (it.hasNext()) {
aktVek = (Vektor2D) it.next();
neuVek = new Vektor2D(aktVek.x + xRicht,
aktVek.y + yRicht);
neuGgst.put(neuVek, null);
}
this.setzeGgst(altGgst, Konstanten.FARBE_HGND, true, true, false);
alleFrei = this.setzeGgst(neuGgst,
Konstanten.FARBE_GGSTD,
false,
true,
false);
if (alleFrei) { // Alte Punkte endg. l�schen.
this.setzeGgst(altGgst, Konstanten.FARBE_HGND, true, false, true);
}
if (alleFrei) { // Neue Punkte endg�ltig setzen.
this.setzeGgst(neuGgst, Konstanten.FARBE_GGSTD, true, false, false);
neuVersch
= new Vektor2D(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, Konstanten.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;
Vektor2D[] neueEcken = robot.getEckPunkte();
Vektor2D[] zwischenEcken = new Vektor2D[4];
int indexRob = this.akteure.indexOf(robot);
Vektor2D[] alteEcken = (Vektor2D[]) this.akteurPunkte.get(indexRob);
String alterText = (String) this.akteurTexte.get(indexRob);
byte falseFarb = Konstanten.FARBE_HGND;
Vektor2D ecke = null;
if (alteEcken != null && alteEcken[0] != null) {
ecke = new Vektor2D(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<Vektor2D, 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 Vektor2D(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 != null && alteEcken[0] != null) {
this.setzeText(alterText, ecke, false);
this.setzeText(text, new Vektor2D(neueEcken[0]), true);
this.akteurTexte.remove(indexRob);
this.akteurTexte.add(indexRob, text);
}
for (int i = 0; i < neueEcken.length; i++) {
alteEcken[i] = new Vektor2D(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] != Konstanten.FARBE_HGND
&& this.feld[x][y] != Konstanten.FARBE_DURCHLAESSIG)) {
return false;
} else {
if (((farbe == Konstanten.FARBE_HGND
|| farbe == Konstanten.FARBE_DURCHLAESSIG)
&& this.feld[x][y] == farbe)
|| ((farbe != Konstanten.FARBE_HGND
&& farbe != Konstanten.FARBE_DURCHLAESSIG)
&& (this.feld[x][y] == Konstanten.FARBE_ROB
|| this.feld[x][y] == Konstanten.FARBE_SEL
|| this.feld[x][y] == Konstanten.FARBE_RAHMEN
|| this.feld[x][y] == Konstanten.FARBE_GGSTD))) {
if (this.feld[x][y] == Konstanten.FARBE_GGSTD
&& this.gegKoll == null) {
this.gegKoll = new Vektor2D(x, y);
}
frei = false;
}
}
if (setzen) {
if (this.feld[x][y] != farbe || unbed) {
this.feld[x][y] = farbe;
if (this.pars.getGraphisch().booleanValue() && !temp) {
this.neuerPixel = new Pixel(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.neuerPixel = null;
this.setChanged();
this.notifyObservers();
}
/**
* Erzeugt eine Textausgabe des Feldes.
*
* @return Testausgabe.
*/
public String toString() {
return SonstMeth.feldAusgabe(this.feld, 8, 17,
SonstMeth.ZEICHEN_FELD, SonstMeth.PRIORITAET_FELD);
}
/**
* 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 Vektor2D[][] 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.getVerzerr().doubleValue();
double konst1 = 1.0 / Math.pow(51.0, 1 / 150.0);
double konst2 = 255.0 * Math.pow(konst1,
-Konstanten.ROB_AUSDEHNUNG_X / 2.0);
byte farbe;
byte letztFarbe;
if (robot.isSelektiert()) {
farbe = Konstanten.FARBE_SEL;
} else {
farbe = Konstanten.FARBE_ROB;
}
this.entferneRoboter(robot, false);
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 = Konstanten.FARBE_HGND;
while (xi >= 0 && xi < this.feld.length
&& yi >= 0 && yi < this.feld[0].length
&& feld[xi][yi] != Konstanten.FARBE_ROB
&& feld[xi][yi] != Konstanten.FARBE_SEL
&& feld[xi][yi] != Konstanten.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 == Konstanten.FARBE_SEL
|| letztFarbe == Konstanten.FARBE_ROB) {
entfernung = entfernung * Konstanten.ROBOTER_KONST;
}
if (i == Konstanten.BEAMER - 1) {
entfernung = entfernung * Konstanten.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> getAkteure() {
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 = (double) x;
final double yy = (double) 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.getAkteure().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[semiPop.get(0).getVCodes().length];
for (int i = 0; i < stdTrans.length; i++) {
stdTrans[i]
= fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_TR;
}
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(SonstMeth.listSeqAusStrings(robC.getTCodes()));
rob.setVerhCodes(SonstMeth.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 beendeSimulation() {
this.simLaeuft = false;
}
/**
* @return Returns the neuerPixel.
*/
public Pixel getNeuerPixel() {
return this.neuerPixel;
}
/**
* @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.
*/
private void setzePixelliste(final List<Point> liste) {
if (liste != null) {
for (Point p : liste) {
this.setzePixel(p.x, p.y, umgebung2D.Konstanten.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, Konstanten.FARBE_HGND,
true, false, false, false);
}
}
this.setzeFeld(Konstanten.FARBE_RAHMEN);
this.setzeGgste(Konstanten.FARBE_GGSTD);
this.setzeDynWaende();
it = this.akteure.iterator();
while (it.hasNext()) {
aktRob = it.next();
if (aktRob.isSelektiert()) {
farbe = Konstanten.FARBE_SEL;
} else {
farbe = Konstanten.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 Vektor2D 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++) {
stdTrans[i]
= fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_TR;
}
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(SonstMeth.listSeqAusStrings(tAut));
aktRob.setVerhCodes(SonstMeth.listSeqAusStrings(vAut));
break;
}
}
return true;
}
/**
* @return Returns the gegVerschieb.
*/
public ArrayList<Vektor2D> 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() {
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;
}
/**
* Der konstante Modus "bester".
*/
private final String modusBester = "best";
/**
* Der konstante Modus "einzelRoboter".
*/
private final String modusEinzelRob = "rob";
/**
* @param modus Der Modus.
* @return Das BufferedImage des Feldes.
*/
private BufferedImage erzeugeFeldBild(
final String[] str,
final String modus) {
BufferedImage buffImgFeld = new BufferedImage(
this.feld.length,
this.feld[0].length,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImgFeld.createGraphics();
Roboter bester = this.getBester();
int radius = (int) ((double) 60 * this.pars.getVerzerr());
// Feld zeichnen.
for (int i = 0; i < feld.length; i++) {
for (int j = 0; j < feld[0].length; j++) {
if (feld[i][j] == Konstanten.FARBE_ROB) {
g.setColor(Konstanten.C_VORDERGRUND);
} else if (feld[i][j] == Konstanten.FARBE_RAHMEN) {
g.setColor(Konstanten.C_RAHMEN);
} else if (feld[i][j] == Konstanten.FARBE_GGSTD) {
g.setColor(Konstanten.C_GEGENSTAND);
} else if (feld[i][j] == Konstanten.FARBE_HGND) {
g.setColor(Konstanten.C_HINTERGRUND);
} else if (feld[i][j] == Konstanten.FARBE_SEL) {
g.setColor(Konstanten.C_SPEZIAL);
} else if (feld[i][j] == Konstanten.FARBE_DURCHLAESSIG) {
g.setColor(Konstanten.C_DURCHLAESSIG);
} else {
g.setColor(Color.white);
}
g.drawLine(i, j, i, j);
}
}
if (this.pars.getAutomatInGIFModus().equalsIgnoreCase(
this.modusBester)) {
g.setColor(Color.RED);
g.setStroke(new BasicStroke(
2,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
g.drawOval(
(int) bester.getPosition().x - radius / 2,
(int) bester.getPosition().y - radius / 2,
radius,
radius);
} else if (this.pars.getAutomatInGIFModus().startsWith(
this.modusEinzelRob)) {
int num = Integer.parseInt(
this.pars.getAutomatInGIFModus().split(":")[1]);
g.setColor(Color.RED);
g.setStroke(new BasicStroke(
2,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
g.drawOval(
(int) this.getAkteure().get(num).getPosition().x
- radius / 2,
(int) this.getAkteure().get(num).getPosition().y
- radius / 2,
radius,
radius);
}
// Feld beschriften.
g.setColor(Color.BLUE);
for (int i = 0; i < str.length; i++) {
g.drawString(str[i], 10, 20 + 15 * i);
}
return buffImgFeld;
}
/**
* @param modus Der Modus.
* @return Das BufferedImage des Automaten.
*/
private BufferedImage erzeugeAutBild(final String modus) {
Roboter bester = this.getBester();
BufferedImage buffImgAut = null;
Graphics2D g;
if (this.pars.getAutomatInGIFModus().equalsIgnoreCase(
this.modusBester)
|| this.pars.getAutomatInGIFModus().startsWith(
this.modusEinzelRob)) {
if (this.pars.getAutomatInGIFModus().startsWith(
this.modusEinzelRob)) {
int num = Integer.parseInt(
this.pars.getAutomatInGIFModus().split(":")[1]);
bester = this.akteure.get(num);
}
PfeilMaster master = new PfeilMaster(this.pars);
Knoten aktKnot = bester.getAktZustand();
if (aktKnot == null) {
aktKnot = bester.getVAut()[0].holeStartzustand();
}
DargestellterGraph darstellung = new DarstModEA(
0,
0,
this.pars.getFeld()[0].length - 100,
this.pars.getFeld()[0].length - 100).erzeuge(
bester.vAuts()[0], aktKnot);
List<Object> zeichenListe = master.graph(darstellung);
buffImgAut = Geometrie2D.erzBuffImgAusObjekten(
zeichenListe,
this.pars);
Polygon2D rahmen = Geometrie2D.rahmen(zeichenListe);
BufferedImage zwisch = new BufferedImage(
this.pars.getFeld()[0].length,
this.pars.getFeld()[0].length,
BufferedImage.TYPE_INT_RGB);
g = zwisch.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, zwisch.getWidth(), zwisch.getHeight());
g.drawImage(
buffImgAut,
0,
(int) ((zwisch.getHeight() - rahmen.getBoundingBox().getHoehe()) / 2),
null);
g.setColor(Color.BLUE);
g.drawString(
"Bester Roboter: "
+ bester.getId()
+ " ("
+ bester.getFitString()
+ ")",
90,
20);
buffImgAut = zwisch;
}
return buffImgAut;
}
/**
* Gibt ein Bild des aktuellen Feldes zur�ck.
*
* @param str Links oben zu setzende Strings.
*
* @return Ein Bild des aktuellen Feldes.
*/
public BufferedImage erzeugeBild(final String[] str) {
Graphics2D g;
BufferedImage gesamtImg, autImg, feldImg;
feldImg = this.erzeugeFeldBild(str, this.pars.getAutomatInGIFModus());
autImg = this.erzeugeAutBild(this.pars.getAutomatInGIFModus());
if (feldImg == null) {
return autImg;
}
if (autImg == null) {
return feldImg;
}
gesamtImg = new BufferedImage(
feldImg.getWidth() + autImg.getWidth(),
Math.max(feldImg.getHeight(), autImg.getHeight()),
BufferedImage.TYPE_INT_RGB);
g = gesamtImg.createGraphics();
g.drawImage(
feldImg,
0,
0,
feldImg.getWidth(),
feldImg.getHeight(),
null);
g.drawImage(
autImg,
feldImg.getWidth(),
0,
autImg.getWidth(),
autImg.getHeight(),
null);
return gesamtImg;
}
/**
* @return Der bester Roboter.
*/
private Roboter getBester() {
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 Vektor2D[] getDynDrehMittPkte() {
return this.dynDrehMittPkt;
}
/**
* @param drehMittPkt The dynDrehMittPkt to set.
* @param wandNum Die Nummer der Wand.
*/
public void setDynDrehMittPkt(
final int wandNum,
final Vektor2D drehMittPkt) {
this.dynDrehMittPkt[wandNum] = drehMittPkt;
}
/**
* @return Returns the dynWaende.
*/
public Polygon2D[] getDynWaende() {
return this.dynWaende;
}
/**
* @return Returns the dynVersch.
*/
public Vektor2D[] 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 ignorieren The dynWaendeIgnor to set.
*/
public void setDynWaendeIgnor(final boolean ignorieren) {
this.dynWaendeIgnor = ignorieren;
}
/**
* @return Returns the wandDynamik.
*/
public Dynamik getWandDynamik() {
return this.wandDynamik;
}
}