Erste Schritte Jäger-Beute Simulation

Devanther

Top Contributor
abstrakte Klasse Akteur:
Code:
import java.util.List;

public abstract class Akteur
{
    // Instanzvariablen - ersetzen Sie das folgende Beispiel mit Ihren Variablen
    private int x;

    /**
     * Ein Beispiel einer Methode - ersetzen Sie diesen Kommentar mit Ihrem eigenen
     *
     * @param  y    ein Beispielparameter für eine Methode
     * @return        die Summe aus x und y
     */
   
    abstract public void agiere(List<Akteur> neueAkteure);
   
    abstract public boolean istAktiv();
}

aus der Klasse Fuchs:
Code:
public void agiere(List<Tier> neueFuechse)
    {
        alterErhoehen();
        hungerVergroessern();
        if(istLebendig()) {
            gebaereNachwuchs(neueFuechse);
            // In die Richtung bewegen, in der Futter gefunden wurde.
            Position neuePosition = findeNahrung();
            if(neuePosition == null) { 
                // kein Futter - zufällig bewegen
                neuePosition = gibFeld().freieNachbarposition(gibPosition());
            }
            // Ist Bewegung möglich?
            if(neuePosition != null) {
                setzePosition(neuePosition);
            }
            else {
                // Überpopulation
                sterben();
            }
        }
    }

Die Methode agiere() befindet sich in der abstrakten Klasse "Akteur" und
in der konkreten Klasse "Fuchs".
Es kommt in der Klasse Fuchs auch ne Fehlermeldung in der Methode
agiere().
Was muss ich machen um dieses Problem zu beseitigen?
Die Klasse "Fuchs" müsste doch die Methode agiere() überschreiben,
aus der Klasse "Akteur" ? Wenn ja, wie geht das?
 

Sasuke

Mitglied
Hey,

die Modellierung ist einfach nicht beachtet worden. Du hast die abstrakte Methode
Java:
abstract public void agiere(List<Akteur> neueAkteure);
definiert und musst diese implementieren.
Deine Methode
Java:
public void agiere(List<Tier> neueFuechse)
kann dies jedoch offentsichtlich schon per Definition nicht. Momentan hast du, wie da auch sehr eindeutig steht, einen name clash zwischen den beiden Methoden, weil sie sich nicht überschreiben und trotzdem die gleiche "erasure" haben.

Ein Workaround wäre zum Beispiel die Nutzung von Generics, wenn du unbedingt den generischen Typ der Liste anpassen musst.

Mit freundlichen Grüßen
Sasuke
 

Javinner

Top Contributor
@Devanther
Was richtig cool wäre:
Alle dazu gehörigen Klassen samt der Aufgabenstellung sauber zu posten. Ich glaube, das würde ein oder anderen
dazu bewegen, mit dir an deinem Dilemma zu arbeiten ;)
 

Devanther

Top Contributor
Klasse Simulator:
Code:
import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;

/**
* Ein einfacher Jäger-Beute-Simulator, basierend auf einem
* Feld mit Füchsen und Hasen.
*
* @author David J. Barnes und Michael Kölling
* @version 31.07.2011
*/
public class Simulator
{
    // Konstanten für Konfigurationsinformationen über die Simulation.
    // Die Standardbreite für ein Feld.
    private static final int STANDARD_BREITE = 120;
    // Die Standardtiefe für ein Feld.
    private static final int STANDARD_TIEFE = 80;
    // Die Wahrscheinlichkeit für die Geburt eines Fuchses an
    // einer beliebigen Position im Feld.
    private static final double FUCHSGEBURT_WAHRSCHEINLICH = 0.02;
    // Die Wahrscheinlichkeit für die Geburt eines Hasen an
    // einer beliebigen Position im Feld.
    private static final double HASENGEBURT_WAHRSCHEINLICH = 0.08;   
   
    private static final double LOEWENGEBURT_WAHRSCHEINLICH = 0.20;

    // Listen der Tiere im Feld. Getrennte Listen vereinfachen das Iterieren.
    private List<Tier> tiere;
    // Der aktuelle Zustand des Feldes
    private Feld feld;
    // Der aktuelle Schritt der Simulation
    private int schritt;
    // Eine grafische Ansicht der Simulation
    private Simulationsansicht ansicht;
   
    private List<Akteur> akteure;
   
    /**
     * Erzeuge ein Simulationsfeld mit einer Standardgröße.
     */
    public Simulator()
    {
        this(STANDARD_TIEFE, STANDARD_BREITE);
    }
     
    /**
     * Erzeuge ein Simulationsfeld mit der gegebenen Größe.
     * @param tiefe die Tiefe des Feldes (muss größer als null sein).
     * @param breite die Breite des Feldes (muss größer als null sein).
     */
    public Simulator(int tiefe, int breite)
    {
        if(breite <= 0 || tiefe <= 0) {
            System.out.println("Abmessungen müssen größer als null sein.");
            System.out.println("Benutze Standardwerte.");
            tiefe = STANDARD_TIEFE;
            breite = STANDARD_BREITE;
        }

        tiere = new ArrayList<Tier>();
        feld = new Feld(tiefe, breite);

        // Eine Ansicht der Zustände aller Positionen im Feld erzeugen.
        ansicht = new Simulationsansicht(tiefe, breite);
        ansicht.setzeFarbe(Fuchs.class, Color.blue);
        ansicht.setzeFarbe(Hase.class, Color.orange);
       
        // Einen gültigen Startzustand einnehmen.
        zuruecksetzen();
    }
   
    /**
     * Starte die Simulation vom aktuellen Zustand aus für einen längeren
     * Zeitraum (4000 Schritte).
     */
    public void starteLangeSimulation()
    {
        simuliere(4000);
    }
   
    /**
     * Führe vom aktuellen Zustand aus die angegebene Anzahl an
     * Simulationsschritten durch.
     * Brich vorzeitig ab, wenn die Simulation nicht mehr aktiv ist.
     * @param schritte die Anzahl der auszuführenden Schritte.
     */
    public void simuliere(int schritte)
    {
        for(int schritt = 1; schritt <= schritte && ansicht.istAktiv(feld); schritt++) {
            simuliereEinenSchritt();
        }
    }
   
    /**
     * Führe einen einzelnen Simulationsschritt aus:
     * Durchlaufe alle Feldpositionen und aktualisiere den
     * Zustand jedes Fuchses und Hasen.
     */
    public void simuliereEinenSchritt()
    {
        schritt++;
       
        // Platz für neugeborenes Tier anlegen.
        List<Akteur> neueAkteure = new ArrayList<Akteur>();
        // Alle Tiere agieren lassen.
        for(Iterator<Akteur> iter = akteure.iterator(); iter.hasNext(); ) {
            Akteur akteur = iter.next();
            akteur.agiere(neueAkteure);
            if(!akteur.istAktiv()) {
                iter.remove();
            }
        }
       
        // Neugeborene Füchse und Hasen in die Hauptliste einfügen.
        akteure.addAll(neueAkteure);

        ansicht.zeigeStatus(schritt, feld);
    }
       
    /**
     * Setze die Simulation an den Anfang zurück.
     */
    public void zuruecksetzen()
    {
        schritt = 0;
        tiere.clear();
        bevoelkere();
       
        // Zeige den Startzustand in der Ansicht.
        ansicht.zeigeStatus(schritt, feld);
    }
   
    /**
     * Bevölkere das Feld mit Füchsen und Hasen.
     */
    private void bevoelkere()
    {
        Random rand = Zufallssteuerung.gibZufallsgenerator();
        feld.raeumen();
        for(int zeile = 0; zeile < feld.gibTiefe(); zeile++) {
            for(int spalte = 0; spalte < feld.gibBreite(); spalte++) {
                if(rand.nextDouble() <= FUCHSGEBURT_WAHRSCHEINLICH) {
                    Position position = new Position(zeile, spalte);
                    Fuchs fuchs = new Fuchs(true, feld, position);
                    tiere.add(fuchs);
                }
                else if(rand.nextDouble() <= HASENGEBURT_WAHRSCHEINLICH) {
                    Position position = new Position(zeile, spalte);
                    Hase hase = new Hase(true, feld, position);
                    tiere.add(hase);
                }
                else if(rand.nextDouble() <= LOEWENGEBURT_WAHRSCHEINLICH) {
                    Position position = new Position(zeile, spalte);
                    Loewe loewe = new Loewe(true, feld, position);
                    tiere.add(loewe);
                }
                // ansonsten die Position leer lassen
            }
        }
    }
}

Klasse Tier:
Code:
import java.util.List;

/**
* Tier ist eine abstrakte Superklasse für Tiere.
* Sie verwaltet Eigenschaften, die alle Tiere gemein haben,
* wie etwas das Alter oder eine Position.
*
* @author David J. Barnes und Michael Kölling
* @version 31.07.2011
*/
public abstract class Tier extends Akteur
{
    // Ist dieses Tier noch lebendig?
    private boolean lebendig;
    // Das Feld des Tieres
    private Feld feld;
    // Die Position dieses Tieres.
    private Position position;

    /**
     * Erzeuge ein neues Tier an der gegebenen Position im Feld.
     *
     * @param feld das aktuelle belegte Feld
     * @param position die Position im Feld
     */
    public Tier(Feld feld, Position position)
    {
        lebendig = true;
        this.feld = feld;
        setzePosition(position);
    }
   
    /**
     * Lasse dieses Tier agieren - es soll das tun, was
     * es tun muss oder möchte.
     * @param neueTiere eine Liste zum Aufnehmen neuer Tiere.
     */
   

    /**
     * Prüfe, ob dieses Tier noch lebendig ist.
     * @return true wenn dieses Tier noch lebendig ist.
     */
    protected boolean istLebendig()
    {
        return lebendig;
    }

    /**
     * Anzeigen, dass das Tier nicht mehr laenger lebendig ist
     * Es wird aus dem Feld entfernt.
     */
    protected void sterben()
    {
        lebendig = false;
        if(position != null) {
            feld.raeumen(position);
            position = null;
            feld = null;
        }
    }

    /**
     * Liefere die Position dieses Tieres.
     * @return die Position dieses Tieres.
     */
    protected Position gibPosition()
    {
        return position;
    }
   
    /**
     * Setze das Tier auf die gegebene Position im aktuellen Feld.
     * @param neuePosition die neue Position des Tieres.
     */
    protected void setzePosition(Position neuePosition)
    {
        if(position != null) {
            feld.raeumen(position);
        }
        position = neuePosition;
        feld.platziere(this, neuePosition);
    }
   
    /**
     * Liefere das Feld des Tieres.
     * @return das Feld des Tieres.
     */
    protected Feld gibFeld()
    {
        return feld;
    }   
}

Klasse Loewe:
Code:
import java.util.List;
import java.util.Iterator;
import java.util.Random;

/**
* Ein simples Modell eines Fuchses.
* Füchse altern, bewegen sich, fressen Hasen und sterben.
*
* @author David J. Barnes und Michael Kölling
* @version 31.07.2011
*/
public class Loewe extends Tier
{
    // Eigenschaften aller Füchse (Klassenvariablen)
   
    // Das Alter, in dem ein Fuchs gebärfähig wird.
    private static final int GEBAER_ALTER = 30;
    // Das Höchstalter eines Fuchses.
    private static final int MAX_ALTER = 170;
    // Die Wahrscheinlichkeit, mit der ein Fuchs Nachwuchs gebärt.
    private static final double GEBAER_WAHRSCHEINLICHKEIT = 0.20;
    // Die maximale Größe eines Wurfes (Anzahl der Jungen).
    private static final int MAX_WURFGROESSE = 3;
    // Der Nährwert eines einzelnen Hasen. Letztendlich ist
    // dies die Anzahl der Schritte, die ein Fuchs bis zur
    //nächsten Mahlzeit laufen kann.
    private static final int FUECHSEN_NAEHRWERT = 12;
    // Ein gemeinsamer Zufallsgenerator, der die Geburten steuert.
    private static final Random rand = Zufallssteuerung.gibZufallsgenerator();
   
    // Individuelle Eigenschaften (Instanzfelder).

    // Das Alter dieses Fuchses.
    private int alter;
    // Der Futter-Level, der durch das Fressen von Hasen erhöht wird.
    private int futterLevel;

    /**
     * Erzeuge einen Fuchs. Ein Fuchs wird entweder neugeboren
     * (Alter 0 Jahre und nicht hungrig) oder kann mit einem zufälligen Alter
     * und zufälligem Hungergefühl erzeugt werden.
     *
     * @param zufaelligesAlter falls true, hat der neue Fuchs ein
     *        zufälliges Alter und einen zufälligen Futter-Level.
     * @param feld das aktuelle belegte Feld
     * @param position die Position im Feld
     */
    public Loewe(boolean zufaelligesAlter, Feld feld, Position position)
    {
        super(feld, position);
        if(zufaelligesAlter) {
            alter = rand.nextInt(MAX_ALTER);
            futterLevel = rand.nextInt(FUECHSEN_NAEHRWERT);
        }
        else {
            alter = 0;
            futterLevel = FUECHSEN_NAEHRWERT;
        }
    }
   
    /**
     * Das ist was ein Fuchs die meiste Zeit tut: er jagt Hasen.
     * Dabei kann er Nachwuchs gebären, vor Hunger sterben oder
     * an Altersschwäche.
     * @param neueFuechse eine Liste zum Zurückliefern neugeborener Füchse.
     */
    public void agiere(List<Tier> neueLoewen)
    {
        alterErhoehen();
        hungerVergroessern();
        if(istLebendig()) {
            gebaereNachwuchs(neueLoewen);
            // In die Richtung bewegen, in der Futter gefunden wurde.
            Position neuePosition = findeNahrung();
            if(neuePosition == null) { 
                // kein Futter - zufällig bewegen
                neuePosition = gibFeld().freieNachbarposition(gibPosition());
            }
            // Ist Bewegung möglich?
            if(neuePosition != null) {
                setzePosition(neuePosition);
            }
            else {
                // Überpopulation
                sterben();
            }
        }
    }
   
    /**
     * Erhöhe das Alter dieses Fuchses. Dies kann zu seinem
     * Tod führen.
     */
    private void alterErhoehen()
    {
        alter++;
        if(alter > MAX_ALTER) {
            sterben();
        }
    }
   
    /**
     * Vergrößere den Hunger dieses Fuchses. Dies kann zu seinem
     * Tode führen.
     */
    private void hungerVergroessern()
    {
        futterLevel--;
        if(futterLevel <= 0) {
            sterben();
        }
    }
   
    /**
     * Suche nach Nahrung (Hasen) in den Nachbarpositionen.
     * Es wird nur der erste lebendige Hase gefressen.
     * @return die Position mit Nahrung, oder null, wenn keine vorhanden.
     */
    private Position findeNahrung()
    {
        Feld feld = gibFeld();
        List<Position> nachbarPositionen =
                               feld.nachbarpositionen(gibPosition());
        Iterator<Position> iter = nachbarPositionen.iterator();
        while(iter.hasNext()) {
            Position pos = iter.next();
            Object tier = feld.gibObjektAn(pos);
            if(tier instanceof Fuchs) {
                Fuchs fuchs = (Fuchs) tier;
                if(fuchs.istLebendig()) {
                    fuchs.sterben();
                    futterLevel = FUECHSEN_NAEHRWERT;
                    return pos;
                }
            }
        }
        return null;
    }
       
    /**
     * Prüfe, ob dieser Fuchs in diesem Schritt gebären kann.
     * Neugeborene kommen in freie Nachbarpositionen.
     * @param neueFuechse eine Liste zum Zurückliefern neugeborener Füchse.
     */
    private void gebaereNachwuchs(List<Tier> neueLoewen)
    {
        // Neugeborene kommen in freie Nachbarpositionen.
        // Freie Nachbarpositionen abfragen.
        Feld feld = gibFeld();
        List<Position> frei = feld.freieNachbarpositionen(gibPosition());
        int geburten = traechtig();
        for(int b = 0; b < geburten && frei.size() > 0; b++) {
            Position pos = frei.remove(0);
            Loewe jung = new Loewe(false, feld, pos);
            neueLoewen.add(jung);
        }
    }
       
    /**
     * Erzeuge eine Zahl für die Wurfgroesse, wenn der Fuchs
     * gebaeren kann.
     * @return  Wurfgroesse (kann null sein).
     */
    private int traechtig()
    {
        int wurfgroesse = 0;
        if(kannGebaeren() && rand.nextDouble() <= GEBAER_WAHRSCHEINLICHKEIT) {
            wurfgroesse = rand.nextInt(MAX_WURFGROESSE) + 1;
        }
        return wurfgroesse;
    }
    /**
     * Ein Fuchs kann gebären, wenn er das gebärfähige
     * Alter erreicht hat.
     */
    private boolean kannGebaeren()
    {
        return alter >= GEBAER_ALTER;
    }
   
}

Klasse Fuchs:
Code:
import java.util.List;
import java.util.Iterator;
import java.util.Random;

/**
* Ein simples Modell eines Fuchses.
* Füchse altern, bewegen sich, fressen Hasen und sterben.
*
* @author David J. Barnes und Michael Kölling
* @version 31.07.2011
*/
public class Fuchs extends Tier
{
    // Eigenschaften aller Füchse (Klassenvariablen)
   
    // Das Alter, in dem ein Fuchs gebärfähig wird.
    private static final int GEBAER_ALTER = 15;
    // Das Höchstalter eines Fuchses.
    private static final int MAX_ALTER = 150;
    // Die Wahrscheinlichkeit, mit der ein Fuchs Nachwuchs gebärt.
    private static final double GEBAER_WAHRSCHEINLICHKEIT = 0.08;
    // Die maximale Größe eines Wurfes (Anzahl der Jungen).
    private static final int MAX_WURFGROESSE = 2;
    // Der Nährwert eines einzelnen Hasen. Letztendlich ist
    // dies die Anzahl der Schritte, die ein Fuchs bis zur
    //nächsten Mahlzeit laufen kann.
    private static final int HASEN_NAEHRWERT = 9;
    // Ein gemeinsamer Zufallsgenerator, der die Geburten steuert.
    private static final Random rand = Zufallssteuerung.gibZufallsgenerator();
   
    // Individuelle Eigenschaften (Instanzfelder).

    // Das Alter dieses Fuchses.
    private int alter;
    // Der Futter-Level, der durch das Fressen von Hasen erhöht wird.
    private int futterLevel;

    /**
     * Erzeuge einen Fuchs. Ein Fuchs wird entweder neugeboren
     * (Alter 0 Jahre und nicht hungrig) oder kann mit einem zufälligen Alter
     * und zufälligem Hungergefühl erzeugt werden.
     *
     * @param zufaelligesAlter falls true, hat der neue Fuchs ein
     *        zufälliges Alter und einen zufälligen Futter-Level.
     * @param feld das aktuelle belegte Feld
     * @param position die Position im Feld
     */
    public Fuchs(boolean zufaelligesAlter, Feld feld, Position position)
    {
        super(feld, position);
        if(zufaelligesAlter) {
            alter = rand.nextInt(MAX_ALTER);
            futterLevel = rand.nextInt(HASEN_NAEHRWERT);
        }
        else {
            alter = 0;
            futterLevel = HASEN_NAEHRWERT;
        }
    }
   
    /**
     * Das ist was ein Fuchs die meiste Zeit tut: er jagt Hasen.
     * Dabei kann er Nachwuchs gebären, vor Hunger sterben oder
     * an Altersschwäche.
     * @param neueFuechse eine Liste zum Zurückliefern neugeborener Füchse.
     */
    public void agiere(List<Tier> neueFuechse)
    {
        alterErhoehen();
        hungerVergroessern();
        if(istLebendig()) {
            gebaereNachwuchs(neueFuechse);
            // In die Richtung bewegen, in der Futter gefunden wurde.
            Position neuePosition = findeNahrung();
            if(neuePosition == null) { 
                // kein Futter - zufällig bewegen
                neuePosition = gibFeld().freieNachbarposition(gibPosition());
            }
            // Ist Bewegung möglich?
            if(neuePosition != null) {
                setzePosition(neuePosition);
            }
            else {
                // Überpopulation
                sterben();
            }
        }
    }
   
    /**
     * Erhöhe das Alter dieses Fuchses. Dies kann zu seinem
     * Tod führen.
     */
    private void alterErhoehen()
    {
        alter++;
        if(alter > MAX_ALTER) {
            sterben();
        }
    }
   
    /**
     * Vergrößere den Hunger dieses Fuchses. Dies kann zu seinem
     * Tode führen.
     */
    private void hungerVergroessern()
    {
        futterLevel--;
        if(futterLevel <= 0) {
            sterben();
        }
    }
   
    /**
     * Suche nach Nahrung (Hasen) in den Nachbarpositionen.
     * Es wird nur der erste lebendige Hase gefressen.
     * @return die Position mit Nahrung, oder null, wenn keine vorhanden.
     */
    private Position findeNahrung()
    {
        Feld feld = gibFeld();
        List<Position> nachbarPositionen =
                               feld.nachbarpositionen(gibPosition());
        Iterator<Position> iter = nachbarPositionen.iterator();
        while(iter.hasNext()) {
            Position pos = iter.next();
            Object tier = feld.gibObjektAn(pos);
            if(tier instanceof Hase) {
                Hase hase = (Hase) tier;
                if(hase.istLebendig()) {
                    hase.sterben();
                    futterLevel = HASEN_NAEHRWERT;
                    return pos;
                }
            }
        }
        return null;
    }
       
    /**
     * Prüfe, ob dieser Fuchs in diesem Schritt gebären kann.
     * Neugeborene kommen in freie Nachbarpositionen.
     * @param neueFuechse eine Liste zum Zurückliefern neugeborener Füchse.
     */
    private void gebaereNachwuchs(List<Tier> neueFuechse)
    {
        // Neugeborene kommen in freie Nachbarpositionen.
        // Freie Nachbarpositionen abfragen.
        Feld feld = gibFeld();
        List<Position> frei = feld.freieNachbarpositionen(gibPosition());
        int geburten = traechtig();
        for(int b = 0; b < geburten && frei.size() > 0; b++) {
            Position pos = frei.remove(0);
            Fuchs jung = new Fuchs(false, feld, pos);
            neueFuechse.add(jung);
        }
    }
       
    /**
     * Erzeuge eine Zahl für die Wurfgroesse, wenn der Fuchs
     * gebaeren kann.
     * @return  Wurfgroesse (kann null sein).
     */
    private int traechtig()
    {
        int wurfgroesse = 0;
        if(kannGebaeren() && rand.nextDouble() <= GEBAER_WAHRSCHEINLICHKEIT) {
            wurfgroesse = rand.nextInt(MAX_WURFGROESSE) + 1;
        }
        return wurfgroesse;
    }
    /**
     * Ein Fuchs kann gebären, wenn er das gebärfähige
     * Alter erreicht hat.
     */
    private boolean kannGebaeren()
    {
        return alter >= GEBAER_ALTER;
    }
   
}

Klasse Akteur: Siehe Oben.
Es gibt noch weitere Klassen.
Aber das müsste ausreichen um eine Lösung für mein Problem zu bekommen!
 

Devanther

Top Contributor
Klasse Feld:
Code:
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
* Ein rechteckiges Gitter von Feldpositionen.
* Jede Position kann ein einzelnes Tier aufnehmen.
*
* @author David J. Barnes und Michael Kölling
* @version 31.07.2011
*/
public class Feld
{
    private static final Random rand = Zufallssteuerung.gibZufallsgenerator();
 
    // Die Tiefe und die Breite des Feldes
    private int tiefe, breite;
    // Speicher für die Tiere
    private Object[][] feld;

    /**
     * Erzeuge ein Feld mit den angegebenen Dimensionen.
     * @param tiefe die Tiefe des Feldes.
     * @param breite die Breite des Feldes.
     */
    public Feld(int tiefe, int breite)
    {
        this.tiefe = tiefe;
        this.breite = breite;
        feld = new Object[tiefe][breite];
    }
 
    /**
     * Räume das Feld.
     */
    public void raeumen()
    {
        for(int zeile = 0; zeile < tiefe; zeile++) {
            for(int spalte = 0; spalte < breite; spalte++) {
                feld[zeile][spalte] = null;
            }
        }
    }
 
    /**
     * Räume die gegebene Position.
     * @param position die zu leerende Position
     */
    public void raeumen(Position position)
    {
        feld[position.gibZeile()][position.gibSpalte()] = null;
    }
 
    /**
     * Platziere das gegebene Tier an der angegebenen Position.
     * Wenn an der Position bereits ein Tier eingetragen ist,
     * geht es verloren.
     * @param tier das Tier das platziert werden soll.
     * @param zeile die Zeilenkoordinate der Position.
     * @param spalte die Spaltenkoordinate der Position.
     */
    public void platziere(Object tier, int zeile, int spalte)
    {
        platziere(tier, new Position(zeile, spalte));
    }
 
    /**
     * Platziere das gegebene Tier an der angegebenen Position.
     * Wenn an der Position bereits ein Tier eingetragen ist,
     * geht es verloren.
     * @param tier das Tier, das platziert werden soll.
     * @param position die Position, an der das Tier platziert werden soll.
     */
    public void platziere(Object tier, Position position)
    {
        feld[position.gibZeile()][position.gibSpalte()] = tier;
    }
 
    /**
     * Liefere das Tier an der angegebenen Position, falls vorhanden.
     * @param position die gewünschte Position.
     * @return das Tier an der angegebenen Position oder null, wenn
     *         dort kein Tier eingetragen ist.
     */
    public Object gibObjektAn(Position position)
    {
        return gibObjektAn(position.gibZeile(), position.gibSpalte());
    }
 
    /**
     * Liefere das Tier an der angegebenen Position, falls vorhanden.
     * @param zeile die gewünschte Zeile.
     * @param spalte die gewünschte Spalte.
     * @return das Tier an der angegebenen Position oder null, wenn
     *         dort kein Tier eingetragen ist.
     */
    public Object gibObjektAn(int zeile, int spalte)
    {
        return feld[zeile][spalte];
    }
 
    /**
     * Wähle zufällig eine der Positionen, die an die gegebene Position
     * angrenzen, oder die gegebene Position selbst.
     * Die gelieferte Position liegt innerhalb der gültigen Grenzen
     * dieses Feldes.
     * @param position die Position, von der ein Nachbar zu wählen ist.
     * @return eine gültige Position innerhalb dieses Feldes. Das kann
     *         auch die gegebene Position selbst sein.
     */
    public Position zufaelligeNachbarposition(Position position)
    {
        List<Position> nachbarn = nachbarpositionen(position);
        return nachbarn.get(0);
    }
 
    /**
     * Liefert eine gemischte Liste von freien Nachbarposition.
     * @param position die Position, für die Nachbarpositionen
     *                 zu liefern ist.
     * @return eine Liste freier Nachbarpositionen.
     */
    public List<Position> freieNachbarpositionen(Position position)
    {
        List<Position> frei = new LinkedList<Position>();
        List<Position> nachbarn = nachbarpositionen(position);
        for(Position naechste : nachbarn) {
            if(gibObjektAn(naechste) == null) {
                frei.add(naechste);
            }
        }
        return frei;
    }
 
    /**
     * Versuche, eine freie Nachbarposition zur gegebenen Position zu
     * finden. Wenn es keine gibt, liefere null.
     * Die gelieferte Position liegt innerhalb der Feldgrenzen.
     * @param position die Position, für die eine Nachbarposition
     *                 zu liefern ist.
     * @return eine gültige Position innerhalb der Feldgrenzen.
     */
    public Position freieNachbarposition(Position position)
    {
        // Die verfügbaren freien Nachbarpositionen
        List<Position> frei = freieNachbarpositionen(position);
        if(frei.size() > 0) {
            return frei.get(0);
        }
        else {
            return null;
        }
    }

    /**
     * Liefert eine gemischte Liste von Nachbarpositionen
     * zu der gegebenen Position. Diese Liste enthält nicht die gegebene
     * Position selbst. Alle Positionen liegen innerhalb des Feldes.
     * @param position die Position, für die Nachbarpositionen zu liefern sind.
     * @return eine Liste der Nachbarpositionen zur gegebenen Position.
     */
    public List<Position> nachbarpositionen(Position position)
    {
        assert position != null : "Keine Position an nachbarpostionen uebergeben";
        // Die Liste der zurueckzuliefernden Positionen
        List<Position> positionen = new LinkedList<Position>();
        if(position != null) {
            int zeile = position.gibZeile();
            int spalte = position.gibSpalte();
            for(int zDiff = -1; zDiff <= 1; zDiff++) {
                int naechsteZeile = zeile + zDiff;
                if(naechsteZeile >= 0 && naechsteZeile < tiefe) {
                    for(int sDiff = -1; sDiff <= 1; sDiff++) {
                        int naechsteSpalte = spalte + sDiff;
                        // Ungueltige Positionen und Ausgangsposition ausschliessen.
                        if(naechsteSpalte >= 0 && naechsteSpalte < breite && (zDiff != 0 || sDiff != 0)) {
                            positionen.add(new Position(naechsteZeile, naechsteSpalte));
                        }
                    }
                }
            }       
            // Mische die Liste. Verschiedene andere Methoden verlassen sich darauf,
            // dass die Liste ungeordnet ist.
            Collections.shuffle(positionen, rand);
        }
        return positionen;
    }

    /**
     * Liefere die Tiefe dieses Feldes.
     * @return die Tiefe dieses Feldes.
     */
    public int gibTiefe()
    {
        return tiefe;
    }
 
    /**
     * Liefere die Breite dieses Feldes.
     * @return die Breite dieses Feldes.
     */
    public int gibBreite()
    {
        return breite;
    }
}

Da kann man die Datei runterladen...für alle die Java BlueJ haben!
https://www.file-upload.net/downloa...n-V2DESKTOP-Copy-neuesteVersion-Copy.rar.html
 
Zuletzt bearbeitet:

Javinner

Top Contributor
Sorry, so auf die Schnelle habe ich auch keine Lösung. Anfänglich dachte ich, es geht rein um Generics, jedoch ist es hier die Hasen-Population Simulation, das übersteigt meine derzeitige Kenntnisse, da bin ich leider nicht der richtige Ansprechspartner :(
 

temi

Top Contributor
Was muss ich machen um dieses Problem zu beseitigen?
Die Klasse "Fuchs" müsste doch die Methode agiere() überschreiben,
aus der Klasse "Akteur" ? Wenn ja, wie geht das?

Java:
@Override
public void agiere(List<Akteur> neueAkteure);

Du musst eine List<Akteur> übergeben und falls notwendig innerhalb der Funktion "agiere" auf den benötigten Typen casten. Wobei das nur notwendig wäre, wenn du nicht mit den von "Akteur" angebotenen Methoden leben kannst. Grundsätzlich sollten Casts vermieden werden! Es gibt fast immer eine andere (bessere) Lösung.

Außerdem fällt auf, dass die Funktion "agiere" bei Löwe und Fuchs völlig identisch ist (Google-Suche: DRY). Diese sollte bereits in "Tier" implementiert werden, um Duplikate zu vermeiden.
 
Zuletzt bearbeitet:

Devanther

Top Contributor
Außerdem fällt auf, dass die Funktion "agiere" bei Löwe und Fuchs völlig identisch ist (Google-Suche: DRY). Diese sollte bereits in "Tier" implementiert werden, um Duplikate zu vermeiden.

Ja, aber einmal werden in der agiere() Methode von Füchse, neue Füchse geboren und in der
agiere() Methode von Loewe, neue Loewen geboren.
Also müssen beide Klassen die Methode agiere() implementieren....!
Ich denke das ist richtig so!

Ich weiss leider immer noch nicht wie ich das Problem beheben soll.
 

Harry Kane

Top Contributor
Du hast eine Menge HInweise auf "Füchse" in deiner Löwen-Klasse. Welche von den Klassen sind vorgegeben und welche sollst du implementieren? Wie lautet denn die Aufgabenstellung?
Außerdem fällt auf, dass die Funktion "agiere" bei Löwe und Fuchs völlig identisch ist (Google-Suche: DRY). Diese sollte bereits in "Tier" implementiert werden, um Duplikate zu vermeiden.
Ja, aber einmal werden in der agiere() Methode von Füchse, neue Füchse geboren und in der agiere() Methode von Loewe, neue Loewen geboren.
Wenn Methode von zwei Klassen weitestgehend gleich sind, geht man so vor: man sucht die die (wenigen) Stellen, an denen sich die Methoden unterscheiden, und implementiert das unterschiedliche Verhalten der Klassen durch Aufruf von Methoden, die dann in den verschiedenen Klassen unterschiedlich implementiert werden.
In dem konkreten Fall könnte das so aussehen: agiere ruft die Methode gebaereNachwuchs auf, die für Löwe und Fuchs wieder sehr ähnlich ist. Der einzige Unterschied besteht darin, dass in der Löwen-Methode neue Löwen instanziiert werden, und in der Fuchs-Methode neue Füchse. Du könntest die Zeilen Fuchs jung = new Fuchs(false, feld, pos); und Loewe jung = new Loewe(false, feld, pos); durch die Zeile
Tier jung = erzeugeNachkommen(false, feld, pos); ersetzen. Dazu musst in der Tier-Klasse eine geeignete abstrakte Methode deklarieren und sie in Löwe und Fuchs implementieren.
Ich habe oben geschrieben "könnte", den im konkreten Fall macht die Sichtbarkeit der Methoden einen Strick durch die Rechnung. Damit das ganze funktioniert, darf gebaereNachwuchs NICHT private sein, sondern muss mindestens protected sein, also von Unterklassen aufrufbar bzw. in Unterklassen überschreibbar.
Wer hat sich das bloss ausgedacht? Oder anders gefragt: wie lautet die Aufgabenstellung.
 

temi

Top Contributor
Ja, aber einmal werden in der agiere() Methode von Füchse, neue Füchse geboren und in der
agiere() Methode von Loewe, neue Loewen geboren.
Also müssen beide Klassen die Methode agiere() implementieren....!

Java:
public void agiere(List<Tier> neueLoewen)
    {
        alterErhoehen();
        hungerVergroessern();
        if(istLebendig()) {
            gebaereNachwuchs(neueLoewen);
            // In die Richtung bewegen, in der Futter gefunden wurde.
            Position neuePosition = findeNahrung();
            if(neuePosition == null) {
                // kein Futter - zufällig bewegen
                neuePosition = gibFeld().freieNachbarposition(gibPosition());
            }
            // Ist Bewegung möglich?
            if(neuePosition != null) {
                setzePosition(neuePosition);
            }
            else {
                // Überpopulation
                sterben();
            }
        }
    }

Java:
    public void agiere(List<Tier> neueFuechse)
    {
        alterErhoehen();
        hungerVergroessern();
        if(istLebendig()) {
            gebaereNachwuchs(neueFuechse);
            // In die Richtung bewegen, in der Futter gefunden wurde.
            Position neuePosition = findeNahrung();
            if(neuePosition == null) {
                // kein Futter - zufällig bewegen
                neuePosition = gibFeld().freieNachbarposition(gibPosition());
            }
            // Ist Bewegung möglich?
            if(neuePosition != null) {
                setzePosition(neuePosition);
            }
            else {
                // Überpopulation
                sterben();
            }
        }
    }

Der einzige Unterschied den ich auf die Schnelle erkennen kann ist der Name des Parameters. Da der Typ identisch ist, gibt es keinen Unterschied zwischen den beiden Funktionen...
 

Devanther

Top Contributor
Also die Klassen Hase und Fuechse sind vorgegeben, die Klassen Loewe und Akteuer habe ich selber erstellt.
Es ist eine Umweltsimulation(Jäger - Beute)
Die Fuechse jagen die Hasen und ich habe die Klasse Loewe implementiert, die Fuechse jagd.

Es soll halt später so sein, dass es Hasen gibt, die "Futterplanzen" jagen (die Klasse müsste man dann noch erstellen)
und es sollte so sein, dass das Wetter das Wachstum der Futterpflanzen beeiflusst(auch die Klasse müsste man
noch erstellen). Da weiss ich nicht so recht, wie man das anstellen sollte...
Und es sollte eine menschliche Klasse "Jäger" geben, die ALLE Tiere jagd.
Also Tiere, Jäger, Futterpflanzen, Wetter müssten von der Klasse Akteur erben.
Und die Tiere, Hasen, Fuechse und Lowen erben von der Klasse Tier.
 

truesoul

Top Contributor
Hallo.

Also viele Methode in den jeweiligen Tieren könntest du in Tier auslagern, da die alle das gleiche machen.
Und Methoden wie z.B findeNahrung(), wo du ein Nährwert mit drin hast. Kannst du auch entweder eine abstrakte Methode implementieren, die von allen Tieren überschrieben wird und somi den Nährwert liefert oder du gibst es der Klasse im Konstruktor mit.

Grüße
 

Harry Kane

Top Contributor
Also die Klassen Hase und Fuechse sind vorgegeben,
D. h. der modifier "private" bei der gebaereNachwuchs-Methode ist vorgegeben?
Dann leuchtet mir das ganze nicht wirklich ein. Wie oben erwähnt, würde es die ganze Sache wesentlich vereinfachen, wenn "gebaereNachwuchs" protected wäre.
Wenn die Klassen Hasen und Fuechse so bleiben müssen, wie sie sind, geht wohl kein Weg an copy-paste-Code vorbei.
Zur Ausgangsfrage: es ist nicht notwendig, den Parameter der agiere-Methode von List<Akteur> auf List<Tier> zu ändern. Die Liste dient ja nur dazu, neue Instanzen von Akteur aufzunehmen, die ein Akteur in der agiere-Methode erzeugen könnte. Eine Interaktion der aktuellen Akteur-Innstanz (also die Instanz, auf der die agiere-methode aufgerufen wird) mit den Akteuren in der List<Akteur> ist nicht vorgesehen, und würde auch keinen Sinn machen, weil jeder Akteur als Parameter der agiere-Methode einen leere List<Akteur> verpasst bekommt.
 

AndiE

Top Contributor
Ich mische mich doch mal ein. Das Problem beruht auf dem Buch zu BlueJ. Es geht bei der aktuellen Frage um folgendes. In der Klasse Simulator befindet sich eine Liste von Akteuren. Diese Klasse Akteur ist abstrakt und von ihr leitet sich eine abstrakte Klasse Tier ab und man kann dort nichttierische Akteure festlegen( Jäger). Von der abstrakten Klasse Tier leiten sich dann die konkreten Tierklassen ab. Da dieses Vorgehen schon recht fortschrittlich ist, ist nicht jeder Schritt in dem Buch beschrieben. In dieser Klassenkonstruktion muss auch die Methode Istaktiv() ausformuliert werden. Der Unterschied zu IstLebendig() ergibt sich aus dem Verhalten der Akteure.
 

Sp4daxy

Neues Mitglied
Guten Abend,
hat einer von euch zufällig diese Jäger-Beute Simulation als Bluej Datei? Ich arbeite momentan selbst an dieser Jäger Beute Simulation mit dem Jäger=Fuchs und der Beute=Hase. Wenn einer von euch eine funktionierende Datei hat, anhand welcher ich mein eigenes Projekt stützen kann und welche ich zudem zum hinzulernen benutzen kann, wäre mir sehr geholfen.
Ich danke euch für eure Hilfe.
 

Ähnliche Java Themen

Neue Themen


Oben