/*
* Datei: Umgebung.java
* Autor(en): Lukas K�nig
* Java-Version: 1.4
* 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.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
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.sonstiges.SonstMeth;
import fmg.fmg8.statistik.Parametersatz;
/**
* 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;
/**
* 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;
/**
* Gibt die Koordinate einer Kollision mit einem Gegenstand an, falls eine
* solche stattgefunden hat, <code>null</code> sonst.
*/
private Vektor2D gegKoll;
/**
* Initialisiert die Umgebung.
*
* @param zufall Der Zufallsgenerator.
* @param params Die Parameter.
* @param obs Der Observer dieser Klasse.
*/
public Umgebung(final Random zufall,
final Parametersatz params,
final Observer obs) {
this.pars = params;
if (this.pars.getGraphisch().booleanValue()) {
this.addObserver(obs);
}
this.simLaeuft = true;
this.gegKoll = null;
byte[][] feldPix = params.getFeld();
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.setzeFeld(Konstanten.FARBE_RAHMEN);
this.holeGegenstaende();
this.setzeGgste(Konstanten.FARBE_GGSTD);
SonstMeth.log(SonstMeth.LOG_INFO,
"Gegenstaende: " + this.gegenstaende.size(),
this.pars);
}
/**
* 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);
}
}
/**
* 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.
*/
public 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 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() {
String s = "";
for (int j = 0; j < this.feld[0].length; j = j + 2) {
for (int i = 0; i < this.feld.length; i++) {
if (this.feld[i][j] == Konstanten.FARBE_ROB) {
s = s + "X";
} else if (this.feld[i][j] == Konstanten.FARBE_SEL) {
s = s + "O";
} else {
s = s + " ";
}
}
s = s + "\n";
}
return s;
}
/**
* Misst im aktuellen Feld den Wert f�r den durch seine Richtung
* angegebenen Sensor des angegebenen Roboters.
*
* @param robot Der Roboter, dessen Sensoren berechnet werden.
* @param sensor Die Nummer des Sensors, der berechnet werden soll.
*
* @return Der Wert des Sensors.
*/
public int berSensWerte(final Roboter robot,
final int sensor) {
final 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.
*/
public 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;
}
/**
* @return Ein Hashwert �ber die Population mit Fitnesswerten und
* Positionen.
*/
public long getPopHashwert() {
long hash = 0;
Iterator<Roboter> it = this.akteure.iterator();
Roboter rob;
while (it.hasNext()) {
rob = it.next();
hash += (long) (rob.getPosition().x * 10);
hash += (long) (rob.getPosition().y * 10);
for (int i = 0; i < rob.vAuts().length; i++) {
hash += rob.getFitness()[i];
}
hash += (long) (rob.getWinkel() * 360);
}
return hash;
}
/**
* 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 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);
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));
// aktRob.setConds(conds);
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;
}
}