Skip to Content

8.4 Übungen

Duke als Boxer

(Lizenz)

 8.4.1 Telefonbuchanwendung (1)

Implementieren Sie eine Telefonbuchanwendung die es erlaubt die folgenden Datensätze zu verwalten:

  • Name String
  • Vorname String
  • Telefonnummer Ganzzahl

 

Die Klasse Telefonbuch soll die folgenden Eigenschaften haben:

  • Verwaltung des Namens, Vornamens, Telefonnummer in drei Feldern mit den entsprechenden Typen
  • Eine Methode die das gesamte Telefonbuch ausdruckt
  • Suche nach allen drei Attributen mit drei verschiedenen Methoden
  • Eine Methode zum "bevölkern" des Telefonbuchs mit mindestens 10 Namen
    • Alle Datensätze seien unterschiedlich
  • Das Telefonbuch soll initial Felder für 4 Einträge besitzen. Beim Vollaufen des Telefonbuchs sollen neue Felder angelegt werden die um 50% größer sind.
  • Kapseln Sie die gesamt Implementierung der Felder innerhalb der Klasse
  • Implementieren Sie eine Methode zum Löschen eines gesuchten Datensates
    • Beim Löschen sollen keine leeren Einträge in den Feldern entstehen
  • Implementieren Sie eine Testmethode die
    • 10 Adressen einträgt
    • 2 Adressen löscht
    • 1 Adresse hinzufügt

Hinweise:

  • Benutzen sie Methoden für alle sinnvollen Teilaufgaben
  • Das Telefonbuch ist nicht notwendigerweise sortiert. Man muss alle Datensätze durchsuchen

Tipp: Die Suchanfragen lassen sich mit wenig Aufwand vom einer grafischen Swingoberfläche steuern. Ein Beispielprogramm finden Sie hier.

8.4.2 "Objektorientierte" Telefonbuchanwendung (2)

Überarbeiten Sie die Telefonbuchanwendung aus der vorhergehenden Aufgabe derart, dass Sie:

  • Eine Klasse Person mit den drei Attributen nutzen
  • Nur ein Feld vom Typ Person in dem alle Daten verwaltet werden

Welche der beiden Lösungen gefällt Ihnen besser? Warum?

8.4.3 Sortierte Telefonbuchanwendung (3)

Überarbeiten die vorhergehende Lösung derart, dass Sie statt einem Feld mit unsortierten Personen,

drei Personen-Felder haben, die jeweils immer sortiert sind. Erweitern Sie die Ausdruckmethode derart, dass das Addressbuch nach allen drei Kriterien ausgegeben wird.

8.4.4 Zufallszahlengenerator

Schreiben Sie ein Programm welches die Zuverlässigkeit des Java Zufallszahlengenerator prüft.

  • Erzeugen Sie ein Feld mit 1 Million (Anzahl konfigurierbar) Zufallszahlen im Bereich von 0 bis 999. Nutzen Sie die Methode Math.random() und das existierende Beispielprogramm.
  • Erzeugen Sie ein dreidimensionales Feld für Ganzzahlen mit einer Größe von 10*10*10 Einträgen (Index jeweils 0..9).
    • Speichern Sie in diesem Feld die Häufigkeit einer vorgekommenen Zahl.
    • Bsp: Erhöhen sie den Zähler der Position [5][4][3] um wenn Sie eine Zufallszahl "534" gefunden haben. Die Zelle [5][4][3] speichert die Anzahl der gefundenen Zahlen "542".
  • Zählen Sie die Zufallszahlen und tragen Sie sie in das dreidimensionale Feld ein
    • Beispiel: Inkrementieren den Wert der Zelle array[2][4][5] für jedes Vorhandensein der Zahl 245
  • Schreiben Sie eine Methode zum Ausdrucken des Feldes
  • Schreiben Sie Methoden die die folgenden Fragen beantworten
    • Welche Zahl kommen am häufigsten vor?
    • Welche Zahl kommen am seltensten vor?
    • Welche Einer-, Zehner, Hunderterziffer ist am häufigsten?
  • Optional: Gibt es lokale Häufungen?
    • Haben Zellen mit über/unterdurchschnittlich vielen Einträgen auch Nachbarn mit über/unterdurchschnittlich vielen Einträgen?
    • Eine Zelle array[x][y][z] hat meistens 8 Nachbarn array[x+/-1][y+/-1][z+/-1]

Tipp: Machen Sie die Größe des dreidimensionalen Feld konfigurierbar und Beginnen Sie mit einem kleinen Kubus(Feld).

8.4.5 Conway: Das Spiel des Lebens

Das "Spiel des Lebens" wurde 1970 vom Mathematiker John Horton Conway 1970 entworfen.

Das Simulationsspiel basiert auf auf einem zweidminensionalen zellulären Automaten. Die Regeln des Automaten sind dem Wikipediaartikel zu entnehmen.

Die gelöste Aufgabe kann man im unten aufgeführten Applet testen.

  • Das Setzen von Elementen ist mit Mausclicks auf der entsprechenden Zelle möglich
  • Eine neue Generation kann mit dem Button ">" berechnet werden
  • Der Button ">>>" erlaubt das automatische Erzeugen von neuen Generationen. Mehrfaches Klicken halbiert die Wartezeit zwischen Generationen.
  • Der Button "Stop" beendet den automatischen Modus

Das Applet kann auch als eigenständiges Hauptgramm ausgeführt werden. Laden Sie das jar-Archiv Conway.jar und starten Sie es im gleichen Verzeichnis mit dem Kommando

java -jar Conway.jar

Aufgabe

Vervollständigen die Klasse Generation.java. Nutzen Sie das Hauptprogramm SpielDesLebens.java zum Testen Ihrer Klasse.

Die Interaktion der Klasse Generation mit dem Rahmenprogramm ist im folgenden Diagramm dargestellt:

Interaktion der Klassen

Klasse Generation.java

Hinweise:

  • Das Hauptprogramm erwartet die Klasse Generation mit den vorgegebenen Methoden im gleichen Paket
  • Sie können weitere Methoden wenn nötig implementieren
  • Das Hauptprogramm wird genau eine Instanz der Klasse Generation erzeugen.

Beim Berechnen der Nachbarn eines Feldes ist auf die Sonderfälle am Rand zu achten:

Anzahl NAchbarn

Weitere Hilfestellungen sind den Kommentaren zu entnehmen. Die Klasse kann natürlich auch ohne die Hilfestellung entwickelt werden. Das Feld kann initial zum Testen sehr klein (2) sein. Die Buttons werden dann erst nach dem Vergrößern des Fenster sichtbar. Eine Größe von 50x50 ist für aktuelle Rechner ausführbar. Pro Zelle werden etwa 10 Pixel benötigt. 

package block8;

public class Generation {

// Hier ein Feld für alten Zustand deklarieren
// Hier ein Feld für neuen Zustand deklarieren
// die Felder muessen zweidimensional, vom Typ boolean sein, quadratisch sein
/**
* Groesse des quadratischen Feldes
*/
// Variable für Groesse des Feldes anlegen. Empfohlen 50 ==> GUI benötigt dann etwa 500 Pixel

/**
* Anlegen aller benoetigten Felder mit Initialwerten
* Alle Feldelemente sollen mit dem Zustand "false" = leer versehen sein
*/
public Generation() {
// Initialisieren sie die beiden Felder
// alle Felder sollen den Zustand "false" haben. Dies ist ein leeres Feld
}

/**
*
* @return Kantenlaenge des quadratischen Felds
*/
public int groesse() {return 0;} //Richtigen Wert zurueckgeben!!

/**
* Berechnen einer neuen Generation.
* Legen Sie ein neues Feld an. Berechnen Sie den neuen Zustand
* aller Feldelement aus dem alten Feld
*/
void neueGeneration() {
// Tipps:
// Weisen Sie die aktuelle Generation auf die alte zu
// Erzeugen oder wiederverwenden Sie ein Feld für eine neue Generation
// Nutzen Sie eine doppelt geschachtelte Schleife zum Ueberstrichen des aktuellen Felds
// Zaehlen Sie die Nachbarn der aktuellen Position in der alten Generation
// Achten Sie auf die Feldgrenzen!!
// Setzen Sie den Wert des aktuellen Felds auf "true" falls ein Objekt erhalten oder erzeugt werden soll
// Setzen Sie dem Wert des aktuellen Felds auf "false" falls kein Objekt in der neuen Generation existieren soll

}

/**
* Das Feld mit den aktuellen Werten
* @return
*/
public boolean[][] status() {return null;} // Hier das aktuelle Feld zurückgeben

}

Klasse SpielDesLebens.java

Das Hauptprogramm. Achten Sie auf die Paketstruktur!

Beim vorgebenen Paket kann das Programm mit dem folgenden Befehl gestartet werden

$ java block8.SpielDesLebens

 

package block8;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.Icon;
import javax.swing.*;

public class SpielDesLebens extends JApplet implements Runnable {
private int size;
private int xRaster=10;
private int yRaster=10;
private Generation gen;
private JButton[][] buttonFeld;
private static boolean appletMode = true;
private static boolean autoMode = false;
private ImageIcon belegtIcon;
private ImageIcon freiIcon;
private static SpielDesLebens myself;
private int sleeptime = 2000; // Millisekunden im Automode

public class Zelle extends JButton {
public int x;
public int y;

public Zelle (Icon ic, int x, int y) {
super(ic);
this.x=x;
this.y=y;
}
}
/**
* Der Konstruktor ohne Argumente wird nur beim einem Start als Applet
* benutzt. Hier wird ein Applet mit einem Grid erzeugt.
*/
public SpielDesLebens() {
erzeugeIcons();
myself=this;
gen = new Generation();
size = gen.groesse();
JFrame f = null;
if (!appletMode) f = new JFrame("Game");
JPanel jp = new JPanel();
jp.setLayout(new GridLayout(size, size));
buttonFeld = new JButton[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
buttonFeld[i][j] = createButton(i, j);
jp.add(buttonFeld[i][j]);
}
}
JButton naechste = new JButton(">");
naechste.setToolTipText("Erzeuge nächste Generation");
naechste.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) { nextGen();}
} // Ende innere Klasse
);
JButton auto = new JButton(">>>");
auto.setToolTipText("Starte Film");
auto.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
sleeptime /=2; // Verdoppeln der Geschwindigkeit
if (!autoMode) {
autoMode=true;
Thread t1 = new Thread(SpielDesLebens.myself);
t1.start();
}
}
} // Ende innere Klasse
);
JButton stop = new JButton("Stop");
stop.setToolTipText("Stoppe Film");
stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
autoMode=false;
sleeptime=4000;
}
} // Ende innere Klasse
);
JPanel buttonPanel = new JPanel();
buttonPanel.add(naechste);
buttonPanel.add(auto);
buttonPanel.add(stop);
Container co;

if (!appletMode) co =f;
else co=this;

co.setLayout(new BorderLayout());
co.add(jp,BorderLayout.CENTER);
co.add(buttonPanel,BorderLayout.SOUTH);
co.setPreferredSize(new Dimension(size * (xRaster+3),size * (yRaster+3)));

if (!appletMode) {
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
}
/**
* Starten der Anwendung als eigenständiges Programm
* @param args
*/
public static void main(String[] args) {
appletMode = false;
SpielDesLebens k = new SpielDesLebens();
}
/**
* Erzeugen eines JButtons für jede Zelle des Feldes
* @param xx x Koordinate im Feld
* @param yy y Koordinate im Feld
* @return
*/
private JButton createButton(int xx, int yy) {
JButton myButton = new Zelle(freiIcon,xx,yy);
myButton.setToolTipText(("("+xx+","+yy+")"));
myButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent ae) {
if(!autoMode) {
Zelle f = (Zelle) ae.getSource();
//System.out.println("Action auf" +f.x + " " + f.y);
boolean[][] g = gen.status();
if (g[f.x][f.y]) {
f.setIcon(freiIcon);
g[f.x][f.y]=false;
}
else {
f.setIcon(belegtIcon);
g[f.x][f.y]=true;
}
f.updateUI();
}
}
} // Ende innere Klasse
);
return myButton;
}
/**
* Erzeuge die beiden Ikonen für eine freies und ein belegtes Feld
*/
public void erzeugeIcons() {
BufferedImage belegt =
new BufferedImage(xRaster, yRaster, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g = belegt.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, xRaster-1, yRaster-1);
g.setColor(Color.black);
g.fillOval(1, 1, xRaster-2, yRaster-2);
g.dispose();
belegtIcon = new ImageIcon(belegt);
BufferedImage frei =
new BufferedImage(xRaster, yRaster, BufferedImage.TYPE_4BYTE_ABGR);
g = frei.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, xRaster-1, yRaster-1);
g.dispose();
freiIcon = new ImageIcon(frei);
}

/**
* Erzeugen einer neuen Generation und Abgleich der JButtons mit neuen
* Ikonen
*/
private void nextGen() {
gen.neueGeneration();
boolean[][] stat = gen.status();
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
if (stat[i][j]) buttonFeld[i][j].setIcon(belegtIcon);
else buttonFeld[i][j].setIcon(freiIcon);
}

/**
* Lasse neue Generationen automatisiert in einem eigen Thread
* erzeugen
*/
public void run() {
try {
while (autoMode) {
Thread.sleep(sleeptime);
nextGen();
}
} catch (InterruptedException e) {
}
}
}

Lösung der Aufgabe in Zwischenschritten

1. Die Anwendung übersetzt und läuft fehlerfrei

  • Variable für Feldgröße als Objektvariable dekarieren und mit Konstante belegen 
    • Wert 5 wählen; Fenster per Hand vergrößern
  • Methode zur Rückgabe der Feldgröße implementieren
  • Zweidimensionales Feld als Objektvariable für aktuelles Feld deklarieren
  • Im Konstruktor das Feld mit doppelt geschachtelter Schleife initialisieren
  • Methode zur Rückhabe des Felds implementieren
  • Methode neueGeneration() implementieren:
    • Trivialimplementierung die genau ein beliebiges aber festes Feldelement auf "true" setzt
  • Testen der Implementierung: Initialiserung des aktuellen Feldes kann so getestet werden

2. Zellen abhängig von Anderen belegen:Methode neueGeneration()

Erweitern Sie die Methode neueGeneration()

  • Setzen Sie jedes Feldelement (x,y) auf "true" wenn das Element (x-1.y-1) belegt ("true") war. Hierdurch werden aus Punkten Striche die sich nach rechts unten forpflanzen.
  • Sie benötigen hierfür eine doppelt geschachtelte Schleife die alle Feldelemente überstreicht.
  • Achten Sie darauf, dass Sie keine Elemente auf Positionen die kleiner als Null sind abfragen!
  • Testen Sie die Anwendung: Jeder Punkt sollte in der Nachfolgegeneration einen neuen rechts unterhalb erhalten. Es steht pro Generation eine neue belegte Zelle rechts unterhalb.

3. Berechnen einer neuen Generation aus einer alten Generation

  • Deklarieren Sie eine Objektvariable die auf das alte Feld zeigt
  • Initialisieren Sie das Feld im Konstruktor. Belegen Sie alle Zellen mit dem Wert "false";
  • Erweitern Sie die Methode neueGeneration()
    • Referenzieren mit dem Zeiger der alten Generation die aktuell Generation.
    • Erzeugen sie ein Feld für die neue (aktuelle) Generation
    • Initialiseren Sie das neue Feld mit vernünftigen Werten.
    • Belegen Sie jedes Feld der neuen Generation mit "true" wenn der linke, obere Nachbar der Vorgängergeneration existiert. Dieses Problem wurde schon in der vorgehenden Phase gelöst.
  • Testen Sie die Anwendung: Jeder Punkt wandert jetzt nach rechts, unten. Es sollten jetzt keine Striche entstehen. Alle Bilder wandern nach rechts unten
  • Setzen Sie die Größe des Felds wieder auf 50 (oder mehr)

Jetzt sollte das Umkopieren von neuen auf alte Generationen funktionieren. Alle Schleifen sollten fehlerfrei laufen

4. Berechnen der korrekten Nachbarschaftsbeziehung in der Methode neueGeneration()

Erweitern Sie die Methode neueGeneration()

  • Zählen Sie für jedes Feld die Anzahl der Nachbarn. Achten SIe auf die Feldgrenzen. Prüfen Sie keine Feldelemente ab die ausserhalb des Feldes liegen.
  • Bestimmen Sie anhand der Nachbarn und es dem Wert der alten Zelle den Zustand der aktuellen Zelle.

 



book | by Dr. Radut