Aufgaben¶
Aufgabe 1 (Würfelspiel)¶
Aufgabe 1
Vorbereitung (siehe Einstieg)
- Informieren Sie sich über die Klasse
JOptionPaneaus dem Paketjavax.swing(z.B. hier oder hier oder hier)
Sollten Sie mit dem Java-Modulsystem arbeiten, d.h. sollten Sie in Ihrem Java-Projekt eine Dateimodule-info.javahaben, dann müssen Sie in diese Datei (in den Anweisungsblock) die Anweisungrequires java.desktop;einfügen - das ist das Modul, in dem sich das Paketjavax.swingbefindet. - Erstellen Sie insbesondere folgenden Dialog (in den Buttons kann auch
YesundNostehen) und prüfen Sie, ob derNein- oder derJa-Button gedrückt wurde (im Beispiel stehtAfür den Namen eines Spielers – siehe Aufgabe unten):
Aufgabe
- Implementieren Sie folgendes Würfelspiel:
- An dem Spiel können beliebig viele Spieler teilnehmen.
- Die Spieler sind nacheinander an der Reihe.
- Wenn ein Spieler an der Reihe ist, dann befindet er sich in einem Versuch.
- In einem Versuch kann der Spieler so lange würfeln, bis er entweder
- eine 6 würfelt oder er
- den Versuch freiwillig beendet.
- Hat der Spieler eine 6 gewürfelt, wird der gesamte Versuch mit
0Punkten bewertet. - Hat der Spieler den Versuch freiwillig beendet, wird die in dem Versuch erzielte Summe aus sein Punktekonto addiert (gespeichert).
- Der Spieler, der zuerst eine bestimmte Punktzahl (z.B.
20) erreicht hat, hat gewonnen.
Beispiel mit zwei SpielernAundBbis Gesamtpunktzahl20:
- Laden Sie Ihr Lösung in Moodle hoch! Viel Spaß und viel Erfolg!
Aufgabe 2 (MyInteger)¶
Aufgabe 2
Vorbereitung (Selbstudium)
-
Eine statische Variable wird mit dem Schlüsselwort
staticdeklariert, also z.B.static int myVariable = 0;. Der Zugriff auf eine solche statische Variable erfolgt nicht über eine Referenzvariable, sondern über den Klassennamen. Angenommen, die VariablemyVariablewurde in der KlasseMyClassdeklariert, dann erfolgt der Zugriff auf die Variable überMyClass.myVariable. Für Objektvariablen gilt, dass jedes Objekt seine eigene(n) Objektvariable(n) hat. Statische Variablen gibt es in der Klasse genau einmal. Alle Objekte "teilen" sich eine statische Variable. Eine statische Variable heißt deshalb auch Klassenvariable. -
Eine statische Methode wird ebenfalls mit dem Schlüsselwort
staticdeklariert, also z.B.public static void myMethod() {}. Der Zugriff auf eine solche statische Methode erfolgt nicht über eine Referenzvariable, sondern über den Klassennamen. Angenommen, die MethodemyMethod()wurde in der KlasseMyClassdeklariert, dann erfolgt der Zugriff auf die Methode überMyClass.myMethod(). Wir kennen solche Methoden bereits, z.B. sind alle Methoden aus der KlasseMathstatisch und wir können sie z.B. mitMath.sqrt(value)oderMath.abs(value)aufrufen.
Aufgabe
Die Klasse MyInteger ist eine sogenannte Wrapper-Klasse. Die Idee ist, dass MyInteger eine objektorientierte Hülle um den int-Typ darstellt. Implementieren Sie die Klasse MyInteger. Diese Klasse hat folgende Eigenschaften:
- Statische Konstanten vom Typ
intMAX_VALUEundMIN_VALUE, welche als Wert die größte bzw. kleinsteint-Zahl enthalten. - Eine private Objektvariable
valuevom Typint. (Dieservaluehat jetzt eine "objektorientierte" Hülle:MyInteger). -
Eine statische Methode
parseInt(String s), die den übergebenenString salsint-Zahl zurückgibt, wennseiner Zahl entspricht. Wenn nicht, wirft die Methode eineIllegalArgumentException. Beachten Sie:skann mit+oder–beginnen,skann führende Nullen aufweisen,- die Länge von
skann mits.length()ermittelt und jedes einzelne Zeichen ausskann mits.charAt(index)betrachtet werden. - Ist
sleer, wird eineIllegalArgumentExceptiongeworfen und wennskeiner Zahl entspricht auch. - Die Exception wird nur weitergereicht, nicht hier behandelt.
-
Zwei Konstruktoren
MyInteger(int value)undMyInteger(String s), die jeweils die Objektvariablevalueinitialisieren. Der zweite Konstruktor verwendetparseInt(String)und kann ebenfalls eineIllegalArgumentExceptionwerfen (reicht die Exception vonparseInt(String)weiter). - Eine Objektmethode
intValue(), die den Wert vonvaluezurückgibt. - Eine Objektmethode
doubleValue(), die den Wert vonvaluealsdoublezurückgibt. - Eine statische Methode
valueOf(String s), die ein Objekt vonMyIntegererzeugt und zurückgibt (und evtl. eineIllegalArgumentExceptionwirft). - Eine statische Methode
valueOf(int value), die ein Objekt vonMyIntegererzeugt und zurückgibt. - Überschreiben Sie außerdem die Methoden
equals()undtoString()(Zusatz: auchhashCode()überschreiben). - Testen Sie Ihre Klasse ausführlich in einer
Testklassemitmain()-Methode. - Laden Sie Ihr Lösung in Moodle hoch! Viel Spaß und viel Erfolg!
Aufgabe 3 (Solitaire)¶
Aufgabe 3
Information und Vorbereitung
Wir wenden Aufzählungstypen und mehrdimensionale Arrays an.
Wir beginnen, ein Englisches Solitär zu programmieren. Einige kennen es auch als Steckhalma. Ziel des Spiels ist, alle Steine bis auf einen (der am besten in der Mitte übrig bleibt), zu entfernen. Ein Zug ist wie folgt: ein Stein springt über einen anderen Stein und der übersprungene Stein wird entfernt. Es gibt viele Lösungen dafür.
Teil der Aufgabe ist es auch, "fremden" Code zu lesen und zu verstehen, denn einige Klassen sind bereits gegeben:
Klasse Point.java
package aufgaben.aufgabe3;
/*
* ein Point repreasentiert eine Position
* im Spielfeld, bestehend aus der Nummer
* fuer die Zeile (row) und der Nummer
* fuer die Spalte (col)
*/
public class Point {
private int row;
private int col;
/*
* Konstruktor zur Erzeugung einer
* Position bestehend aus row und col
*/
public Point(int row, int col)
{
this.row = row;
this.col = col;
}
public int getRow() {
return this.row;
}
public int getCol() {
return this.col;
}
@Override
public String toString()
{
return "("+ this.row + "," + this.col + ")";
}
}
Klasse Move.java
package aufgaben.aufgabe3;
/*
* diese Klasse repraesentiert einen Zug
* Variablen sind Point from
* und Point to
* es wird nicht geprueft, ob der Zug ueberhaupt
* moeglich ist
*/
public class Move {
private Point from;
private Point to;
/*
* ein Zug von dem from-Point (fromRow,fromCol)
* zum to-Point (toRow,toCol)
*/
public Move(int fromRow, int fromCol, int toRow, int toCol)
{
this.from = new Point(fromRow, fromCol);
this.to = new Point(toRow, toCol);
}
/*
* in dem Konstruktor werden in this.from und this.to nicht einfach
* die Referenzen von from und to gespeichert, sondern davon Kopien
* erstellt, damit das Programm robuster gegen das Aendern von
* Referenzen ist
*/
public Move(Point from, Point to)
{
this.from = new Point(from.getRow(), from.getCol());
this.to = new Point(to.getRow(), to.getCol());
}
/*
* der Getter fuer den Point from gibt keine Referenz auf
* den Point from zurueck, sondern eine Kopie (einen Klon)
* von from --> Referenzen koennen "verbogen" werden, aber
* die Kopien bleiben unveraendert
*/
public Point getFrom()
{
return new Point(this.from.getRow(), this.from.getCol());
}
/*
* der Getter fuer den Point to gibt keine Referenz auf
* den Point to zurueck, sondern eine Kopie (einen Klon)
* von to --> Referenzen koennen "verbogen" werden, aber
* die Kopien bleiben unveraendert
*/
public Point getTo()
{
return new Point(this.to.getRow(), this.to.getCol());
}
}
Klasse Moves.java
package aufgaben.aufgabe3;
/*
* diese Klasse repraesentiert eine Folge
* von Zuegen (Move), die in einem Array
* moves gespeichert sind
*/
public class Moves {
private Move[] moves;
/*
* der Konstruktor erstellt ein leeres moves-Array
* (d.h. noch keine Zuege (Moves) gespeichert)
*/
public Moves()
{
this.moves = new Move[0];
}
/*
* der Konstruktor erstellt ein moves-Array mit einem
* Move - dem erste Zug (firstMove)
*/
public Moves(Move firstMove)
{
this.moves = new Move[1];
this.moves[0] = firstMove;
}
/*
* Anzahl der bisher gespeicherten Zuege
*/
public int getLength()
{
return this.moves.length;
}
/*
* fuegt einen Zug (nextMove) zum moves-Array hinzu
* dazu muss das moves-Array um 1 laenger sein als zuvor
* es wird eine Kopie aller Zuege erstellt und dann
* der nextMove hinzugefuegt
*/
public void addMove(Move nextMove)
{
Move[] newMoves = new Move[this.moves.length + 1];
for (int index = 0; index < this.moves.length; index++) {
newMoves[index] = this.moves[index];
}
newMoves[newMoves.length - 1] = new Move(nextMove.getFrom(), nextMove.getTo());
this.moves = newMoves;
}
/*
* gibt den Move zurueck, der im moves-Array unter dem Index index
* gespeichert ist;
* kann sein, dass index kein korrekter Index im moves-Array ist,
* dann wird eine IllegalArgumentException geworfen
*/
public Move getMoveAtIndex(int index) throws IllegalArgumentException
{
try {
return this.moves[index];
}
catch(ArrayIndexOutOfBoundsException e)
{
throw new IllegalArgumentException("kein gueltiger Index!");
}
}
/*
* Ausgabe aller im moves-Array gespeicherten Zuege
* wird nur zum Debuggen benoetigt
*/
public void printMoves()
{
System.out.printf("%n---%n");
for (int index = 0; index < this.moves.length; index++) {
Move move = this.moves[index];
Point from = move.getFrom();
Point to = move.getTo();
System.out.println(from.toString() + " --> " + to.toString());
}
System.out.printf("%n---%n%n");
}
}
enum State.java
Aufgabe
Befüllen Sie die Klasse Solitaire.java, wie in den Kommentaren beschrieben:
Klasse Solitaire.java
package aufgaben.aufgabe3.loesung;
public class Solitaire {
private Moves game;
private State[][] field;
public Solitaire()
{
this.game = new Moves();
this.field = new State[7][7];
for(int row = 0; row < this.field.length; row++)
{
for(int col = 0; col < this.field[row].length; col++)
{
if((row < 2 || row > 4) && (col < 2 || col > 4))
{
this.field[row][col] = State.NOT;
}
else
{
this.field[row][col] = State.USED;
}
}
}
this.field[3][3] = State.FREE;
}
/*
* Geben Sie das Spielfeld aus! Am Anfang sollte auf der
* Konsole so ein Bild erscheinen:
* o o o
* o o o
* o o o o o o o
* o o o o o o
* o o o o o o o
* o o o
* o o o
*
*/
public void print()
{
}
/*
* diese Methode gibt ein true zurueck, wenn von der
* uebergebenen Position (row,col) ein Zug moeglich ist
* d.h.
* 1. auf der angegebenen Position muss ein Stein sein
* 2. zwei Steine weiter (oben, unten, rechts oder links)
* darf kein Stein sein
* 3. dazwischen muss ein Stein sein
*/
public boolean possibleFrom(int row, int col)
{
return false;
}
/*
* diese Methode gibt alle Positionen (Point) zurueck,
* AUF die von (fromRow,fromCol) aus gesprungen werden
* kann
*/
public Point[] possibleTo(int fromRow, int fromCol)
{
if(!possibleFrom(fromRow, fromCol)) return new Point[0];
/*
* naechste Zeile muss entfernt werden!
* sttatdessen muessen Sie alle Point-Objekte ermitteln AUF die
* gesprungen werden kann. Diese Point-Objekte werden in einem
* Point-Array gespeichert, welches zurückgegeben wird.
*/
return null;
}
/*
* diese Methode erzeugt ein Moves-Objekt
* in dieses Moves-Objekt werden mithilfe der
* Objektmethode addMove() (aus Moves) alle
* moeglichen Zuege hinzugefuegt
* (moeglich im aktuellen Zustand von field[][])
*/
public Moves possibleMoves()
{
Moves possibleMoves = new Moves();
// next line for debugging
possibleMoves.printMoves();
return possibleMoves;
}
/*
* gibt ein true zurueck, wenn im aktuellen Zustand
* von field[][] ueberhaupt noch ein Zug moeglich ist
* sonst false
*/
public boolean movePossible()
{
return false;
}
/*
* ruft die Methode move(Move move) auf,
* wenn ein Zug moeglich ist (dann true zurueck)
* sonst false
*/
public boolean moveFirstPossible()
{
if(!movePossible()) return false;
/*
* hier einen moeglichen Zug ausfuehren
* den ersten, den Sie finden (siehe
* possibleMoves() )
*/
return true;
}
/*
* hier wird der Zug Move move ausgefuehrt
* nach dem Zug ist
* 1. die from-Position leer
* 2. die to-Position mit einem Stein besetzt
* 3. dazwischen leer (Stein wird "entfernt")
* falls Zug nicht moeglich, wird eine
* IllegalArgumentException geworfen
*/
public void move(Move move) throws IllegalArgumentException
{
}
}
Sie können selbstverständlich beliebig viele weitere (Hilfs-)Methoden hinzufügen.
Testen Sie Ihr Spiel in einer Testklasse. Führen Sie einige Züge aus und geben danach immer das Spielfeld auf die Konsole aus. Die Konsole könnte z.B. dann so aussehen:
mögliche Konsolenausgaben
o o o
o o o
o o o o o o o
o o o o o o
o o o o o o o
o o o
o o o
---
(1,3) --> (3,3)
(3,1) --> (3,3)
(3,5) --> (3,3)
(5,3) --> (3,3)
---
o o o
o o
o o o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(2,1) --> (2,3)
(2,5) --> (2,3)
(4,3) --> (2,3)
---
o o o
o o
o o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(0,2) --> (2,2)
(2,4) --> (2,2)
(3,3) --> (1,3)
(4,1) --> (2,1)
(4,2) --> (2,2)
---
o o
o
o o o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(0,4) --> (0,2)
(2,3) --> (2,1)
(3,2) --> (1,2)
(3,3) --> (1,3)
(4,1) --> (2,1)
---
o
o
o o o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(2,3) --> (2,1)
(2,4) --> (0,4)
(3,2) --> (1,2)
(3,3) --> (1,3)
(4,1) --> (2,1)
---
o
o
o o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(2,0) --> (2,2)
(2,4) --> (0,4)
(2,5) --> (2,3)
(4,2) --> (2,2)
(4,3) --> (2,3)
---
o
o
o o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(2,4) --> (0,4)
(2,5) --> (2,3)
(3,2) --> (1,2)
(4,0) --> (2,0)
(4,1) --> (2,1)
(4,3) --> (2,3)
---
o o
o o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(2,6) --> (2,4)
(3,2) --> (1,2)
(4,0) --> (2,0)
(4,1) --> (2,1)
(4,3) --> (2,3)
(4,4) --> (2,4)
---
o o
o o
o o o o o o o
o o o o o o o
o o o
o o o
---
(3,2) --> (1,2)
(3,4) --> (1,4)
(4,0) --> (2,0)
(4,1) --> (2,1)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
---
o o
o
o
o o o o o o
o o o o o o o
o o o
o o o
---
(0,2) --> (2,2)
(3,0) --> (3,2)
(3,4) --> (1,4)
(3,4) --> (3,2)
(4,0) --> (2,0)
(4,1) --> (2,1)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
(5,2) --> (3,2)
---
o
o o
o o o o o o
o o o o o o o
o o o
o o o
---
(3,0) --> (3,2)
(3,4) --> (1,4)
(3,4) --> (3,2)
(4,0) --> (2,0)
(4,1) --> (2,1)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
(5,2) --> (3,2)
---
o
o o
o o o o o
o o o o o o o
o o o
o o o
---
(3,2) --> (1,2)
(3,3) --> (3,1)
(3,4) --> (1,4)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
---
o
o
o
o o o o
o o o o o o o
o o o
o o o
---
(3,4) --> (1,4)
(3,4) --> (3,2)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
(5,2) --> (3,2)
---
o
o o
o o o
o o o o o o o
o o o
o o o
---
(0,4) --> (2,4)
(3,6) --> (3,4)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
(5,2) --> (3,2)
(5,4) --> (3,4)
---
o
o
o o o
o o o o o o o
o o o
o o o
---
(3,6) --> (3,4)
(4,3) --> (2,3)
(4,5) --> (2,5)
(4,6) --> (2,6)
(5,2) --> (3,2)
(5,4) --> (3,4)
---
o
o
o o
o o o o o o o
o o o
o o o
---
(3,3) --> (3,5)
(3,4) --> (1,4)
(3,4) --> (3,2)
(4,3) --> (2,3)
(5,2) --> (3,2)
---
o
o
o
o o o o o o o
o o o
o o o
---
(4,5) --> (2,5)
(5,2) --> (3,2)
(5,3) --> (3,3)
(5,4) --> (3,4)
---
o
o o
o o o o o o
o o o
o o o
---
(2,4) --> (2,6)
(2,5) --> (2,3)
(4,3) --> (4,5)
(5,2) --> (3,2)
(5,3) --> (3,3)
(5,4) --> (3,4)
---
o
o
o o o o o o
o o o
o o o
---
(4,3) --> (4,5)
(5,2) --> (3,2)
(5,3) --> (3,3)
(5,4) --> (3,4)
---
o
o
o o o o o
o o o
o o o
---
(4,1) --> (4,3)
(4,6) --> (4,4)
(5,2) --> (3,2)
(6,3) --> (4,3)
(6,4) --> (4,4)
---
o
o
o o o o
o o o
o o o
---
(4,6) --> (4,4)
(5,3) --> (3,3)
(6,2) --> (4,2)
(6,4) --> (4,4)
---
o
o
o o o
o o o
o o o
---
(4,3) --> (4,5)
(4,4) --> (4,2)
(5,3) --> (3,3)
(5,4) --> (3,4)
(6,2) --> (4,2)
---
o
o
o o
o o o
o o o
---
(6,2) --> (4,2)
(6,3) --> (4,3)
(6,4) --> (4,4)
---
o
o
o o o
o o
o o
---
(5,4) --> (5,2)
(6,3) --> (4,3)
(6,4) --> (4,4)
(6,4) --> (6,2)
---
o
o
o o o
o
o o
---
(4,2) --> (6,2)
(5,2) --> (3,2)
(6,4) --> (6,2)
---
o
o
o o
o o o
o
o
o o
o o o
Dabei steht z.B.
für die in dem Zustand darüber möglichen Züge.Aufgabe 4 (Operationen über Mengen)¶
Aufgabe 4
Implementieren Sie eine Klasse SetOperations.
- Erstellen Sie drei Objektvariablen (z.B.
numbers1,numbers2undboth) vom TypSet<Integer>. Erzeugen Sie für diese ObjektvariablenTreeSet-Objekte. - Erstellen Sie eine Objektmethode
fill(). In dieser Methode sollen die beiden Setsnumbers1undnumbers2mit Zufallszahlen aus dem Wertebereich0..99befüllt werden. Erzeugen Sie jeweils100Zufallszahlen (dienumbers-Sets werden dann aber jeweils weniger als 100 Einträge haben, da doppelte Elemente nicht aufgenommen werden.)
Beachten Sie, dass dienextInt()-Methode einintzurückliefert. Dieses int muss zunächst in einInteger-Objekt umgewandelt werden (Integer.valueOf(int)) und diesesInteger-Objekt wird dann dem Set hinzugefügt (wenn es nicht schon enthalten ist). - Erstellen Sie eine Objektmethode
fillBothUnion(). In dieser Methode wird dieboth-Menge derart befüllt, dassbotheiner Vereinigung der Mengennumbers1undnumbers2entspricht. Für Methoden auf Mengen siehe z.B. https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html. - Erstellen Sie eine Objektmethode
fillBothIntersection(). In dieser Methode wird dieboth-Menge derart befüllt, dassbotheinem Schnitt der Mengennumbers1undnumbers2entspricht. - Erstellen Sie eine Objektmethode
fillBothDifference(). In dieser Methode wird dieboth-Menge derart befüllt, dassbothder Differenz der Mengenumbers1minus der Mengenumbers2entspricht. - Schreiben Sie eine Methode
print()so, dass jede Menge als ein Quadrat (10x10) aus Punkten auf der Konsole erscheint. Es wird ein Punkt gezeichnet, wenn die entsprechende Zahl (die 100 Punkte bilden die Zahlen 0..99 ab) in der Menge enthalten ist und es wird kein Punkt gezeichnet, wenn die Zahl nicht vorhanden ist. (Anstelle von Punkten können Sie auch jedes beliebige Zeichen (o, *, #, x, ...) verwenden).
Gestalten Sie die Ausgabe so, dass die drei Mengennumbers1,numbers2undbothnebeneinander auf der Konsole erscheinen. -
Testen Sie alle drei Methoden
fillBothUnion(),fillBothIntersection()undfillBothDifference(). Die Ausgabe könnte wie folgt sein (Astellt die Mengenumbers1dar,Bdie Mengenumbers2und rechts ist jeweils dieboth-Menge dargestellt):


Tipps:
- Für die schwarzen Punkte habe ich das Character
'\u25cf'verwendet (ein passendes Leerzeichen dazu ist'\u2009'). Das Zeichen für die Vereinigung ist'\u222a'und für den Schnitt'\u2229'. - Schauen Sie sich auch im Skript Mengenoperationen an.
Aufgabe 5 (Maps)¶
Aufgabe 5
-
Gegeben ist die Datei pi.txt (download pi.txt.zip). Sie enthält π mit den ersten
100.000Nachkommastellen. Entpacken Sie die Dateipi.txt.zipund kopieren oder bewegen Sie die Dateipi.txtin einenassets-Ordner, der sich in Ihrem Workspace neben demsrcund demout-Ordner befindet (also direkt in dem Ordner Ihres Java-Projektes. Die folgende Abbildung zeigt, wie es z.B. bei mir aussieht (siehe auch Übung 5):
-
Erstellen Sie sich Klasse
StringPImit folgendem Inhalt:Klasse StringPi mit der Konstanten PI
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; public class StringPI { public static final String PI; static { try { String fileContent = new String(Files.readAllBytes(Paths.get("assets/pi.txt"))); PI = fileContent.replace("\n", "").replace("\r", ""); } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) { System.out.println(PI.substring(0, 100)); } }Die Ausführung der Klasse sollte folgende Ausgabe ergeben:
-
Die Zahl π ist eine irrationale Zahl, d.h. sie kann nicht als Bruch dargestellt werden. Außerdem ist sie nicht periodisch, d.h. es gibt keine immer wiederkehrende Folge von Ziffern im Nachkommabereich. Die Zahl π hat unendlich viele Nachkommastellen und da sie nicht periodisch ist, kommen alle möglichen Ziffernfolge in π vor. Beispielsweise kommt die Ziffernfolge
123456allein in den ersten 200 Millionen Nachkommastellen 208 Mal vor. -
Erstellen Sie eine
TreeMap, in der die Schlüssel vom TypStringund die Werte vom TypIntegersind. Als Schlüssel nutzen Sie alle 4-stelligen Zifferkombinationen"0000","0001"bis"9999". Als Werte sollen dazu jeweils die Anzahl der Vorkommen dieser Ziffernkombinationen in dem obigenString PIgespeichert werden. -
Erstellen Sie eine
ArrayList, in der die Ziffernkombinationen gespeichert sind, die am häufigsten in dem obigenString PIgespeichert sind. Wieviele und welche Ziffernkombinationen sind das?Tipps
-
Schauen Sie sich dazu die Klasse String genauer an!
-
Überlegen Sie sich, wie Sie am besten alle möglichen Kombinationen aus 4-stelligen Zahlen als String erzeugen können (also
"0000", "0001", "0002", ... "9999"). -
Schreiben Sie sich eine Methode
int nrOfOccurrences(String sub, String str), die die Anzahl des Vorkommens vonsubinstrzählt. Sie können diese Methode z.B. testen, indem Siesub="0000"setzen undstr=pi→"0000"kommt 9 Mal inpivor. Testen Sie auchsub="2541"undstr=pi, denn"2541"ist der allerletztesubstringin unserempiund kommt 8 Mal vor.
-
Aufgabe 6 (Interfaces)¶
Aufgabe 6
-
Das Observer-Entwurfsmuster gehört zu den am meisten verwendeten Designmustern/Designpattern/Pattern in der Programmierung. Es wird auch Beobachter-Muster oder Publisher-Pattern genannt. Man kann sich dieses Pattern so vorstellen, dass der Publisher eine Zeitung oder auch Slack ist und dass Listener diese Zeitung (oder Slack) "abonnieren". Immer, wenn eine Nachricht veröffentlicht wird, dann erfahren alle Abonnenten davon. Wir werden eine (einfache) Implementierung dieses Entwurfsmusters durchführen.
-
Erstellen Sie ein Interface
Publishermit folgenden (abstrakten) Methoden (ist also kein functional interface):public boolean register(Listener listener);public boolean unregister(Listener listener);public void notifyListeners();public String getUpdate(Listener listener);
-
Erstellen Sie ein weiteres Interface
Listenermit folgenden (abstrakten) Methoden:public void update();public void setPublisher(Publisher publisher);public void removePublisher(Publisher publisher);
-
Erstellen Sie eine Klasse
Slack, die dasPublisher-Interface implementiert. Objektvariablen der Klasse sindprivate Set<Listener> listeners;(speichert alle "Abonnenten"; kann gerne auch eine Liste sein)-
private int nrOfMessages;(speichert die aktuelle Nummer einer veröffentlichten Nachricht - die Nachrichten, die veröffentlicht werden, sollen fortlaufend nummeriert werden) -
Im parameterlosen Konstruktor werden die Menge (oder Liste) erzeugt und die
nrOfMessagesauf0gesetzt. -
In der Methode
register(Listener listener)wird derlistenerin die Setlistenerseingefügt. Geben Sie eintruezurück, wennlistenertatsächlich eingefügt wurde undfalsesonst (falls er schon in der Menge (oder Liste) war). -
In der Methode
unregister(Listener listener)wird derlistenerwieder aus der Setlistenersgelöscht. Geben Sie eintruezurück, wennlistenertatsächlich gelöscht wurde undfalsesonst (falls er nicht in der Menge (oder Liste) war. -
In der Methode
notifyListeners()wird für allelisteneraus der Mengelistenersdieupdate()-Methode aufgerufen (sieheListenerundStudent). -
Die Methode
getUpdate(Listener obj)liefert einfach folgenden String zurück:"Breaking News " + this.nrOfMessages. -
Erstellen Sie eine Methode
public void publishNews(), in der dienrOfMessagesum 1 erhöht und die MethodenotifyListeners()aufgerufen wird.
-
Erstellen Sie eine Klasse
Student, die dasListener-Interface implementiert. Objektvariablen der Klasse sind-
private String name;(speichert den Namen vonStudent) -
private Publisher publisher;(speichert denPublisher, an den sichStudentanmeldet) -
Im parametrisierten Konstruktor
public Student(String name)wird der Name initalisiert. -
In der Methode
setPublisher(Publisher publisher)wird dieregister()-Methode despublisheraufgerufen und der Wert der Objektvariablepublishergesetzt. Geben Sie bei erfolgreicher Anmeldung an denpublisherauf die Konsolethis.name + " registered!"aus. -
In der Methode
removePublisher(Publisher publisher)meldet sichStudentwieder vompublisherab (Aufruf vonunregister()) und Ausgabe auf die Konsolethis.name + " deregistered!". -
In der Methode
update()wird diegetUpdate()-Methode despublisheraufgerufen und die zurückgegebene Nachrichtmsgwie folgt auf die Konsole ausgegben:this.name + " received " + msg. -
Implementieren Sie für
Studentauch die Methodenequals()undhashCode().
-
-
Wenn Sie Ihre Implementierung mit folgender Klasse testen:
public class Testklasse { public static void main(String[] args) { final int NR_OF_STUDENTS = 5; Slack slack = new Slack(); Student[] students = new Student[NR_OF_STUDENTS]; Character c = 'A'; for(int index=0; index < students.length; index++) { students[index] = new Student(c.toString()); c++; students[index].setPublisher(slack); } slack.publishNews(); System.out.println(); students[1].removePublisher(slack); students[3].removePublisher(slack); System.out.println(); slack.publishNews(); System.out.println(); students[1].setPublisher(slack); students[2].removePublisher(slack); students[4].removePublisher(slack); System.out.println(); slack.publishNews(); System.out.println(); students[0].removePublisher(slack); students[1].removePublisher(slack); students[3].setPublisher(slack); System.out.println(); slack.publishNews(); } }dann sollte die Ausgabe ungefähr so sein:
A registered! B registered! C registered! D registered! E registered! D received Breaking News 1 C received Breaking News 1 B received Breaking News 1 A received Breaking News 1 E received Breaking News 1 B deregistered! D deregistered! C received Breaking News 2 A received Breaking News 2 E received Breaking News 2 B registered! C deregistered! E deregistered! B received Breaking News 3 A received Breaking News 3 A deregistered! B deregistered! D registered! D received Breaking News 4
Aufgabe 7 (Lambdas und Streams I)¶
Aufgabe 7
-
Die Aufgabe kommt aus dem ersten Semster (siehe Probeklausuren - Studentin). Jetzt wollen wir diese Aufgabe mithilfe von Streams und Lambdas lösen. Gegeben Sie die folgenden Klassen (download aufgabe7.zip):
Name.java
package aufgaben.aufgabe7; import java.util.Arrays; public class Name { private char[] name; public Name(String name) { this.name = name.toCharArray(); } @Override public String toString() { String s = ""; for(char c : this.name) { s += c; } return s; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Name other = (Name) o; return Arrays.equals(this.name, ((Name) o).name); } public boolean isBigger(Name n) { int length = this.name.length < n.name.length ? this.name.length : n.name.length; for (int index = 0; index < length; index++) { if (this.name[index] > n.name[index]) return true; else if (this.name[index] < n.name[index]) return false; } return this.name.length > n.name.length; } }Studentin.java
package aufgaben.aufgabe7; import java.util.Random; class Studentin { private String matrNr; private int jahr; private double note; private int lp; private Name sg; public Studentin(String sg) { this.sg = new Name(sg); Random rand = new Random(); int num = rand.nextInt(10000); this.matrNr = String.format("s095%04d", num); this.jahr = rand.nextInt(16) + 2009; if (this.jahr < 2019) { this.lp = 180; } else { this.lp = (rand.nextInt(36)) * 5; } this.note = 1.0 + (rand.nextInt(30) * 0.1); } public String getMatrNr() { return this.matrNr; } public double getNote() { return this.note; } public int getLp() { return this.lp; } public Name getSg() { return this.sg; } public int getSemester() { return (2025 - this.jahr) * 2 - 1; } @Override public String toString() { if (this.lp == 180) { return String.format("%8s Absolventin (%d) aus %3s mit 180 LPs. Notendurchschnitt: %.2f", this.matrNr, this.jahr, this.sg, this.note); } return String.format("%8s %2d.Semester (%d) aus %3s mit %3d LPs. Notendurchschnitt: %.2f", this.matrNr, this.getSemester(), this.jahr, this.sg, this.lp, this.note); } }Main.java
package aufgaben.aufgabe7; import java.util.Random; public class Main { public static void main(String[] args) { System.out.printf("%n%n---------------- Name-Objekte --------------%n%n"); Name n1 = new Name("FIW"); Name n2 = new Name("AI"); Name n3 = new Name("IMI"); System.out.println(n1.toString()); System.out.println(n2.toString()); System.out.println(n3.toString()); System.out.println(); System.out.println("FIW > AI ? (true == " + n1.isBigger(n2) + ")"); System.out.println("FIW > IMI ? (false == " + n1.isBigger(n3) + ")"); System.out.printf("%n%n---------------- Studentin --------------%n%n"); Studentin[] studis = new Studentin[40]; Random r = new Random(); for (int index = 0; index < 40; index++) { studis[index] = switch(r.nextInt(5)) { case 0 -> new Studentin("FIW"); case 1,2 -> new Studentin("AI"); case 3,4 -> new Studentin("IMI"); default -> throw new IllegalStateException("Unexpected value: " + r.nextInt(5)); }; System.out.println(studis[index].toString()); } System.out.printf("%n%n---------------- Studiengaenge --------------%n%n"); SG fiw = new SG(studis, "FIW"); System.out.println(fiw.toString()); fiw.sort(true); System.out.println(fiw.toString()); fiw.sort(false); System.out.println(fiw.toString()); SG ai = new SG(studis, "AI"); System.out.println(ai.toString()); ai.sort(true); System.out.println(ai.toString()); ai.sort(false); System.out.println(ai.toString()); SG imi = new SG(studis, "IMI"); System.out.println(imi.toString()); imi.sort(true); System.out.println(imi.toString()); imi.sort(false); System.out.println(imi.toString()); System.out.printf("%n------------ Studiengaenge (FIW) ---------------%n%n"); Studentin fiwBesterAbschluss = fiw.besterAbschluss(); if(fiwBesterAbschluss != null) System.out.println(fiwBesterAbschluss.toString()); System.out.printf("durchschnittliche Abschlussnote : %.4f", fiw.durchschnittlicheAbschlussnote()); Studentin[] nochStudierend = fiw.nochStudierend(); System.out.printf("%n%n"); System.out.println("Folgende Studentinnen studieren noch in FIW : "); for(int index = 0; index < nochStudierend.length; index++) { System.out.println(" " + nochStudierend[index].toString()); } System.out.printf("%n------------------- HTW ------------------%n%n"); HTW htw = new HTW(studis); System.out.println(htw.toString()); Studentin[] nochHTW = htw.nochStudierend(); System.out.println("aktuell studieren " + nochHTW.length + " Studierende an der HTW : "); for (int index = 0; index < nochHTW.length; index++) { System.out.println(nochHTW[index].toString()); } } }SG.java
package aufgaben.aufgabe7; public class SG { private Studentin[] studis; private Name sg; public SG(Studentin[] studis, String sg) { this.sg = new Name(sg); /* Das studis-Array des Parameters enthält Studentin-Objekte aus verschiedenen Studiengängen. Ermitteln Sie, wie viele Studentin-Objekte es für den Studiengang sg enthält und erzeugen Sie das studis-Array der Objektvariablen entsprechend. Befüllen Sie das studis-Array der Objektvariablen mit allen Studentin-Objekten aus dem studis-Array des Parameters, die zum Studiengang sg gehören. Nutzen Sie dazu Streams! */ this.studis = new Studentin[0]; // TODO } public int anzahlStudis() { return this.studis.length; } public void sort(boolean note) { /* Sortieren Sie das studis-Array. Ist der Parameterwert von note true, wird das Array nach dem Notendurchschnitt sortiert (beste Note zuerst). Ist der Parameterwert von note false, wird das Array nach der Anzahl der Semester sortiert (wenigsten Semester zuerst). Nutzen Sie dazu die Sortier-Methode sort(T[] a, Comparator c) aus der Klasse Arrays Schauen Sie sich für einen passenden Comparator die compare()-Methoden der Klassen Double und Integer an! Verwenden Sie Lambdas! */ } @Override public String toString() { String s = String.format("%s mit %d Studis : %n", this.sg, this.studis.length); for(int index = 0; index < this.studis.length; index++) { s += String.format(" %s %n", this.studis[index].toString()); } s += "\n"; return s; } public Studentin besterAbschluss() { /* Geben Sie die Studentin zurück, die den besten Notendurchschnitt von allen Absolventinnen (mit 180 Leistungspunkten) des Studiengangs hat. Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - filter() // um alle Absolventinnen zu filtern - min() // um diejenige mit der besten Note zu ermitteln */ return null; // TODO } public double durchschnittlicheAbschlussnote() { /* Geben Sie den durchschnittlichen Notenwert (als double) aller Absolventinnen (mit 180 Leistungspunkten) des Studiengangs zurück. Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - filter() // um alle Absolventinnen zu filtern - mapToDouble() // oder map() - um den Studentinnen-Stream in einen Noten-Stream zu wandeln - average() */ return 0.0; //TODO } public Studentin[] nochStudierend() { /* Geben Sie ein Studentin[] zurück, das alle Studentinnen aus dem Studiengang enthält, die noch keine 180 Leistungspunkte haben. Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - filter() // um alle Studentinnen mit weniger als 180 LP zu filtern - toArray() // um ein Studentin-Array zu erzeugen */ return new Studentin[0]; // TODO } }HTW.java
package aufgaben.aufgabe7; public class HTW { private SG[] htw; public HTW(Studentin[] studis) { /* Erstellen Sie eine Name[] sgs, das alle Namen der Studiengänge enthält, in denen die Studentinnen aus dem studis-Array studieren Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - map() // um aus dem Studentinnen-Stream einen Studiengangs-Stream zu machen - distinct() // um alle Doppelungen heraus zu filtern - toArray() // um ein Name-Array zu erzeugen */ Name[] sgs = new Name[0]; // TODO this.htw = new SG[sgs.length]; for (int i = 0; i < sgs.length; i++) { htw[i] = new SG(studis, sgs[i].toString()); } } public int anzahlStudis() { /* Ermitteln Sie die Summe aller Studentinnen aus dem htw-Array. Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - mapToInt() // um die anzahlStudis (siehe SG) pro SG zu ermitteln - sum() // um die Summe der Anzahlen zu ermitteln */ return 0; // TODO } @Override public String toString() { String s = String.format("HTW mit %d Studierenden in %d Studiengaengen : %n%n", this.anzahlStudis(), this.htw.length); for (int index = 0; index < this.htw.length; index++) { s += this.htw[index].toString(); } s += "\n"; return s; } public Studentin[] nochStudierend() { /* Erzeugen Sie ein Studentin[] aller noch Studierenden aus dem htw-Array. Verwenden Sie Streams. Schauen Sie sich folgende Methoden an - stream() aus der Klasse Arrays - flatMap() // um alle nochStudierend (siehe SG) pro SG zu ermitteln - toArray() // um das Studentin[] zu erzeugen (und mit dem Stream zu befuellen) */ return new Studentin[0]; } } -
Die Klassen
Name.java,Studentin.javaundMain.javasind fertig. Aber inSG.javaundHTW.javagibt es einige//TODOs. Ersetzen Sie diese unter Beachtung der jeweils darüber befindlichen Kommentare. Eine Lösung ohne Streams und Lambdas finden Sie unter Probeklausuren - Studentin, falls Sie an manchen Stellen nicht weiterkommen.
Aufgabe 8 (Lambdas und Streams II)¶
Aufgabe 8
-
Gegeben ist eine Liste von Strings, z.B.
List<String> words = Arrays.asList("fiw", "ai", "imi", "ikg", "wi", "bui", "ce", "csb", "iiw", "wiw");Gruppieren Sie mithilfe von Streams die Strings nach ihrer Länge und zählen Sie die Anzahl der Strings in jeder Gruppe. Ausgabe könnte (für obiges Beispiel) wie folgt sein: -
Gegeben folgender Record
Rectangle:public record Rectangle(int width, int length){}und z.B. folgende Menge:Set<Rectangle> rectangles = new HashSet<>(); rectangles.add(new Rectangle(1, 2)); rectangles.add(new Rectangle(3, 2)); rectangles.add(new Rectangle(1, 4)); rectangles.add(new Rectangle(3, 4)); rectangles.add(new Rectangle(2, 5)); rectangles.add(new Rectangle(4, 2)); rectangles.add(new Rectangle(2, 4));Partitionieren Sie die Menge der
rectangles, je nachdem die Breite größer ist als die Länge und umgekehrt (Gleichheit können Sie eine der beiden Gruppen zuordnen). Mögliche Ausgabe könnte sein: -
Finden Sie alle kleinsten (größten) Rechteck aus
rectangles(Größe soll die Addition von Länge und Breite sein). (Hinweis: Ich brauchte 2 Streams oder 1 Stream und eine schlaue Behandlung der Map - vielleicht schaffen Sie es ja mit einem Stream?!). Ausgabe könnte sein:bzw. (größte)
-
Gruppieren Sie alle
rectanglesnach ihrem Flächeninhalt. Ausgabe könnte sein:
Aufgabe 9 (JUnit-Tests MyInteger)¶
Aufgabe 9
- Erstellen Sie für die Klasse
MyIntegeraus Aufgabe 2 so viele Junit-Tests, dass die Testabdeckung100%erreicht.