Package eas.users.lukas.neuroCEGPM

Source Code of eas.users.lukas.neuroCEGPM.EnvironmentNeural

/*
* Datei:          EnvironmentNeural.java
* Autor(en):      Lukas König
* Java-Version:   7.0
* Erstellt (vor): 28 February 2014
*
* (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.users.lukas.neuroCEGPM;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
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 javax.imageio.ImageIO;

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.simulation.ConstantsSimulation;
import eas.simulation.Wink;
import eas.simulation.agent.AbstractAgent;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.GenericState;
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;

/**
* Repräsentiert ein Feld, auf dem Roboter fahren können.
*
* @author Lukas König
*/
public class EnvironmentNeural extends AbstractEnvironment2D<RobNeural> {

    /**
     *
     */
    private static final long serialVersionUID = 2630679876135524964L;

    /**
     * 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<RobNeural> 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;
   
    /**
     * Plugins für diesen Lauf.
     */
//    private LinkedList<Plugin<?>> plugins;
   
    public EnvironmentNeural(
            final Random zufall,
            final int id,
            final ParCollection params,
            final String envID) {
        this(zufall, id, null, params, 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 EnvironmentNeural(
            final Random zufall,
            final int id,
            final AbstractEnvironment<?> fatherEnv,
            final ParCollection params,
            final String envID) {
        super(envID, id, fatherEnv, params);
       
        this.umgebungsBMP = params.getParValueString("umgebungDateiname");

        this.pars = params;
        this.rand = zufall;

        // Feld initialisieren:
        String dat = params.getStdDirectory() + File.separator + this.umgebungsBMP;
       
        initialisiereFeld(params, dat, null, null, null);
    }

    /**
     * @param params
     * @param dat
     */
    private void initialisiereFeld(
            final ParCollection params,
            String dat,
            ArrayList<RobNeural> akteure,
            ArrayList<Vector2D[]> akteurPunkte,
            ArrayList<String> akteurTexte
            ) {
        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];
        if (akteure == null) {
            this.akteure = new ArrayList<RobNeural>();
            this.akteurPunkte = new ArrayList<Vector2D[]>();
            this.akteurTexte = new ArrayList<String>();
        } else {
            this.akteure = new ArrayList<RobNeural>(akteure);
            this.akteurPunkte = new ArrayList<Vector2D[]>(akteurPunkte);
            this.akteurTexte = new ArrayList<String>(akteurTexte);
        }
       
        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 RobNeural roboter) {
        try {
            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;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * @return  The position of the agent.
     */
    @Override
    public Vector2D getAgentPosition(int agentID) {
        for (RobNeural 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 (RobNeural r : this.akteure) {
            if (r.id() == agentID) {
                return r.getAngle();
            }
        }
       
        return null;
    }
   
    @Override
    public Polygon2D getAgentShape(int agentID) {
        for (RobNeural r : this.akteure) {
            if (r.id() == agentID) {
                return r.getEckp();
            }
        }

        return null;
    }
   
    @Override
    public synchronized Polygon2D getAgentShapeInVisualization(int agentID) {
        for (RobNeural 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 RobNeural 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 RobNeural 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 RobNeural 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 RobNeural 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 (RobNeural 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 RobNeural 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;
    }

    private Double verzerr = null;
   
    /**
     * 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 RobNeural 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;
        if (verzerr == null) {
            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<RobNeural> getAgents() {
        return new ArrayList<RobNeural>(this.akteure);
    }

    /**
     * @return  The agents in RobEAEinfach type.
     */
    public ArrayList<RobNeural> 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 RobNeural[] holeNahen(final double x, final double y,
            final int anzahl) {
        RobNeural[] naechste = new RobNeural[anzahl];
        RobNeural[] alle = new RobNeural[this.akteure.size()];
        double[] alleEntf = new double[this.akteure.size()];
        Iterator<RobNeural> 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 RobNeural holeNahenNorm(final int x, final int y,
            final HashSet<RobNeural> nicht) {
        final double xx = x;
        final double yy = y;
        double minEntf = Double.MAX_VALUE;
        double aktEntf;
        Iterator<RobNeural> it = this.akteure.iterator();
        RobNeural naechster = null;
        RobNeural 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 (RobNeural aktEur : this.getAgents()) {
            if (kleinste <= aktEur.id()) {
                kleinste = aktEur.id() + 1;
            }
        }
       
        return kleinste;
    }

    /**
     * @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<RobNeural> it;
        byte farbe;
        RobNeural 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]));
                }
            }
        }
    }

    /**
     * @return Returns the gegVerschieb.
     */
    public ArrayList<Vector2D> getGegVerschieb() {
        return this.gegVerschieb;
    }
   
    /**
     * Setzt die Positionen der Roboter zufällig und setzt die Fitness zurück.
     */
    public void resetRobs() {
        ArrayList<RobNeural> akt = new ArrayList<RobNeural>(this.akteure.size());
        akt.addAll(this.akteure);
       
        for (RobNeural r : akt) {
            r.resetAnzUnf();
            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;
    }
   
    @Override
    public void step(final Wink cyc) {
        if (cyc.getLastTick() % 500 == 49) {
            this.alleFelderNeu();
        }

        this.refreshSensorValues();
    }

    private void refreshSensorValues() {
        for (RobNeural r : this.getAgents()) {
            r.setAngle(r.getAngle());
        }
    }
   
    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;
    }

    private int imgWidth;
    private int imgHeight;
   
    /**
     * A view of the current state of the environment.
     */
    @Override
    public synchronized BufferedImage getOutsideView() {
        Graphics2D g;
        if (this.graphicsObject != null) {
            this.imgWidth = this.buffImgFeld.getWidth();
            this.imgHeight = this.buffImgFeld.getHeight();
        } 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 RobNeural getAgent(int agentID) {
        for (RobNeural 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"));
        list.add(new SingleParameter(
                "umgebungDateiname",
                Datatypes.STRING,
                "umgebung.bmp",
                "Der Dateiname, aus dem die Umgebung gelesen wird.",
                EnvironmentNeural.class.toString().toUpperCase()) {
                    private static final long serialVersionUID = -8388034715523249089L;

                    @Override
                    public BufferedImage getImage(final ParCollection params) {
                        BufferedImage img = null;
                        try {
                            img = ImageIO.read(new File(
                                    params.getStdDirectory()
                                        + File.separator
                                        + this.getParValue()));
                        } catch (IOException e) {
                            img = new BufferedImage(
                                    400,
                                    100,
                                    BufferedImage.TYPE_INT_RGB);
                            Graphics2D g = img.createGraphics();
                            g.setColor(Color.red);
                            g.fillRect(0, 0, 400, 100);
                            g.setColor(Color.black);
                            g.drawString("Field bitmap not found: "
                                    + params.getStdDirectory()
                                    + File.separator
                                    + this.getParValue(), 50, 50);
                        }
                       
                        return img;
                    }
        });

        return list;
    }
   
    public Random getRand() {
        return this.rand;
    }
   
    public double getFitnessSum() {
        double sum = 0;
       
        for (RobNeural r : this.getAgents()) {
            sum += r.getFitness();
        }
       
        return sum;
    }
   
    public int getAnzUnfaelle() {
        int sum = 0;
       
        for (RobNeural r : this.getAgents()) {
            sum += r.getAnzUnfaelle();
            r.resetAnzUnf();
        }
       
        return sum;
    }
   
    @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();
    }
}
TOP

Related Classes of eas.users.lukas.neuroCEGPM.EnvironmentNeural

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.