24 Commits

Author SHA1 Message Date
708515ee4f AB8/5 2022-06-07 14:40:54 +02:00
a951b5c14a AB8/3 + AB8/4 2022-06-07 14:36:07 +02:00
150eb7aa49 AB8/2 2022-06-04 13:30:20 +02:00
ac40ada302 AB8/1 2022-06-03 16:46:03 +02:00
cfba0106a9 Refacotr code for AB8 2022-06-03 14:23:51 +02:00
8f6320e069 Finish Übungstest 6 2022-06-02 14:37:11 +02:00
d718ba90e3 Fix AB6, code style 2022-06-02 14:28:43 +02:00
eab0db8e40 Aufgabenblatt 8 2022-05-30 13:18:56 +00:00
406c9b02f7 Aufgabenblatt 8 2022-05-30 14:58:17 +02:00
05c52cd3f5 Abgabe Übungstest 5 2022-05-19 14:38:54 +02:00
088fa3cdeb Implement AB6 2022-05-17 19:43:03 +02:00
f801a331c2 Implement AB6, Aufgabe 1+2 2022-05-17 19:31:19 +02:00
b89fc15602 Refactor AB6 Angabe 2022-05-17 17:28:26 +02:00
2e14e45bb0 Aufgabenblatt 6 2022-05-16 18:39:22 +00:00
e311ef3c6b Aufgabenblatt 6 2022-05-16 20:27:14 +02:00
a62ef91a8a Implement Übungstest 4 2022-05-12 14:35:07 +02:00
34c2ac91c6 Finished AB5 2022-05-07 13:20:59 +02:00
a075544fe2 Refactor BodyLinkedList 2022-05-07 12:01:43 +02:00
391b389063 Refactor BodyForceTreeMap 2022-05-07 12:01:22 +02:00
e7eae474ac Refactor MassiveForceHashMap 2022-05-06 22:45:56 +02:00
6b1f1ecc2a Refactored for AB5 2022-05-06 22:42:28 +02:00
e84bf3bf4a Aufgabenblatt 5 2022-05-02 10:31:10 +00:00
1e789dba34 Aufgabenblatt 5 2022-05-02 12:20:50 +02:00
e94d3daeda Fix AB4 main loop
Signed-off-by: Lorenz Stechauner <lorenz.stechauner@necronda.net>
2022-04-28 21:48:36 +02:00
43 changed files with 2367 additions and 204 deletions

View File

@ -10,32 +10,32 @@ Diese Aufgabenstellung ist ein vollständiges IntelliJ-Projekt, das Sie bereits
- Einstellen des _Project SDK_: Öffnen Sie dazu in IntelliJ die Projekteinstellungen (_File_ -> _Project Structure..._) und wählen Sie ein JDK unter _Project | Project SDK_ aus. - Einstellen des _Project SDK_: Öffnen Sie dazu in IntelliJ die Projekteinstellungen (_File_ -> _Project Structure..._) und wählen Sie ein JDK unter _Project | Project SDK_ aus.
## Thema ## Thema
Das allgemeine Thema dieses und der kommenden Aufgabenblätter ist der Weltraum und die Simulation der physikalischen Gesetze, die für Himmelskörper gelten. Obwohl ein möglichst exaktes physikalisches Modell wünschenswert ist, ist bei der Implementierung die Genauigkeit der physikalischen Modelle sekundär. Konzeptuelle Fehler bei den physikalischen Berechnungen spielen keine Rolle bei der Bewertung. Schwerpunkt sind die Konzepte der Programmiersprache. Das allgemeine Thema dieses und der kommenden Aufgabenblätter ist der Weltraum und die Simulation der physikalischen Gesetze, die für Himmelskörper gelten. Obwohl ein möglichst exaktes physikalisches Modell wünschenswert ist, ist bei der Implementierung die Genauigkeit der physikalischen Modelle sekundär. Konzeptuelle Fehler bei den physikalischen Berechnungen spielen keine Rolle bei der Bewertung. Schwerpunkt sind die Konzepte der Programmiersprache.
## Ziel ## Ziel
Ziel der Aufgabe ist die Anwendung der Konzepte: Objekt- vs. Klassenmethode, Datensatz, Data Hiding, Konstruktoren (siehe Skriptum Seiten 31-50). Ziel der Aufgabe ist die Anwendung der Konzepte: Objekt- vs. Klassenmethode, Datensatz, Data Hiding, Konstruktoren (siehe Skriptum Seiten 31-50).
## Aufgaben ## Aufgaben
1. Lesen Sie sich die Kommentare in den Dateien durch und führen Sie die Klasse `Simulation` aus. 1. Lesen Sie sich die Kommentare in den Dateien durch und führen Sie die Klasse `Simulation` aus.
2. Data hiding: 2. Data hiding:
1. Machen Sie in den Klassen `Vector3` und `Body` alle Objektvariablen `private`. 1. Machen Sie in den Klassen `Vector3` und `Body` alle Objektvariablen `private`.
2. Definieren Sie entsprechende Konstruktoren, um die Objektvariablen zu initialisieren. `Simulation` soll nur noch diese nutzen und nicht mehr direkt auf die Objektvariablen zugreifen dürfen. Testen Sie zunächst die vervollständigten Klassen `Vector3` und `Body` mit der Klasse `Aufgabe1Test`. Entfernen Sie dazu die Kommentarzeichen in der Klassendefinition. 2. Definieren Sie entsprechende Konstruktoren, um die Objektvariablen zu initialisieren. `Simulation` soll nur noch diese nutzen und nicht mehr direkt auf die Objektvariablen zugreifen dürfen. Testen Sie zunächst die vervollständigten Klassen `Vector3` und `Body` mit der Klasse `Aufgabe1Test`. Entfernen Sie dazu die Kommentarzeichen in der Klassendefinition.
3. Datenkapselung: Anstelle der gegebenen statischen Methoden in der Datei `Simulation.java` sollen nur noch entsprechende Objektmethoden der Klassen `Body` und `Vector3` benutzt werden. (Ausnahme ist die Methode `main`. Die statischen Methoden der Klasse `SpaceDraw` müssen auch nicht verändert werden.) Implementieren Sie dazu die spezifizierten Methoden und bauen Sie `Simulation` so um, dass anstelle der Aufrufe statischer Methoden Objektmethoden genutzt werden. Sie sollen alle in `Body` und `Vector3` spezifizierten Methoden implementieren, auch wenn nicht alle von `Simulation` genutzt werden. Die in `Simulation.java` gegebenen statischen Methoden können dann entfernt werden (natürlich bis auf die erwähnten Ausnahmen). Nutzen Sie die implementierten Methoden auch in `Simulation.java`, um die Himmelskörper zu bewegen und zu zeichnen. 3. Datenkapselung: Anstelle der gegebenen statischen Methoden in der Datei `Simulation.java` sollen nur noch entsprechende Objektmethoden der Klassen `Body` und `Vector3` benutzt werden. (Ausnahme ist die Methode `main`. Die statischen Methoden der Klasse `SpaceDraw` müssen auch nicht verändert werden.) Implementieren Sie dazu die spezifizierten Methoden und bauen Sie `Simulation` so um, dass anstelle der Aufrufe statischer Methoden Objektmethoden genutzt werden. Sie sollen alle in `Body` und `Vector3` spezifizierten Methoden implementieren, auch wenn nicht alle von `Simulation` genutzt werden. Die in `Simulation.java` gegebenen statischen Methoden können dann entfernt werden (natürlich bis auf die erwähnten Ausnahmen). Nutzen Sie die implementierten Methoden auch in `Simulation.java`, um die Himmelskörper zu bewegen und zu zeichnen.
## Zusatzfragen ## Zusatzfragen
Beantworten Sie folgende Zusatzfragen als Kommentar in `Simulation.java`: Beantworten Sie folgende Zusatzfragen als Kommentar in `Simulation.java`:
1. Was versteht man unter _Datenkapselung_? Geben Sie ein Beispiel, wo dieses Konzept in dieser Aufgabenstellung angewendet wird. 1. Was versteht man unter _Datenkapselung_? Geben Sie ein Beispiel, wo dieses Konzept in dieser Aufgabenstellung angewendet wird.
2. Was versteht man unter _Data Hiding_? Geben Sie ein Beispiel, wo dieses Konzept in dieser Aufgabenstellung angewendet wird. 2. Was versteht man unter _Data Hiding_? Geben Sie ein Beispiel, wo dieses Konzept in dieser Aufgabenstellung angewendet wird.
3. Was steht bei einem Methodenaufruf links vom `.` (z.B. bei `SpaceDraw.massToColor(1e30)` oder 3. Was steht bei einem Methodenaufruf links vom `.` (z.B. bei `SpaceDraw.massToColor(1e30)` oder
`body.radius()`)? Woran erkennt man dabei Objektmethoden? `body.radius()`)? Woran erkennt man dabei Objektmethoden?
### Denkanstöße (ohne Bewertung) ### Denkanstöße (ohne Bewertung)
Folgende Fragen sind als Denkanstöße gedacht und bilden die Grundlage für eine Diskussion in der Übungseinheit zu diesem Aufgabenblatt. Folgende Fragen sind als Denkanstöße gedacht und bilden die Grundlage für eine Diskussion in der Übungseinheit zu diesem Aufgabenblatt.
1. Welche anderen oder weiteren Objektmethoden hätten Sie zur Verfügung gestellt, wenn es keine Vorgaben gegeben hätte? 1. Welche anderen oder weiteren Objektmethoden hätten Sie zur Verfügung gestellt, wenn es keine Vorgaben gegeben hätte?
2. Wann wäre es sinnvoll, die Klasse `SpaceDraw` so zu ändern, dass diese ebenfalls Objektmethoden 2. Wann wäre es sinnvoll, die Klasse `SpaceDraw` so zu ändern, dass diese ebenfalls Objektmethoden
zur Verfügung stellt? zur Verfügung stellt?
#### _Punkteaufteilung_ #### _Punkteaufteilung_

View File

@ -1,7 +1,7 @@
# Aufgabenblatt 2 # Aufgabenblatt 2
## Allgemeine Anmerkungen ## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 28.3. 11h durch `git commit` und `push` Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 28.3. 11h durch `git commit` und `push`
abzugeben. Mit der Angabe werden folgende Dateien mitgeliefert: `BodyQueue.java`, `BodyForceMap.java` und `Aufgabe2Test.java`. Diese Klassen dürfen nur an den Stellen verändert werden, die mit `TODO` markiert sind. Zusätzliche Klassen, Interfaces, Methoden und Variablen dürfen aber eingefügt werden. Wenn Sie zusätzlich zu den gefragten Klassen, weitere Klassen definieren, achten Sie darauf, dass die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden. abzugeben. Mit der Angabe werden folgende Dateien mitgeliefert: `BodyQueue.java`, `BodyForceMap.java` und `Aufgabe2Test.java`. Diese Klassen dürfen nur an den Stellen verändert werden, die mit `TODO` markiert sind. Zusätzliche Klassen, Interfaces, Methoden und Variablen dürfen aber eingefügt werden. Wenn Sie zusätzlich zu den gefragten Klassen, weitere Klassen definieren, achten Sie darauf, dass die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden.
## Ziel ## Ziel
@ -10,10 +10,10 @@ Ziel der Aufgabe ist die Implementierung einer linearen und einer assoziativen D
## Beschreibung der gegebenen Dateien ## Beschreibung der gegebenen Dateien
- `BodyQueue` ist das Gerüst für eine Implementierung einer linearen Datenstruktur zur Verwaltung - `BodyQueue` ist das Gerüst für eine Implementierung einer linearen Datenstruktur zur Verwaltung
von Objekten des Typs `Body`. von Objekten des Typs `Body`.
- `BodyForceMap` ist das Gerüst für eine Implementierung einer assoziativen Datenstruktur, die - `BodyForceMap` ist das Gerüst für eine Implementierung einer assoziativen Datenstruktur, die
einen Himmelskörper mit der auf ihn wirkenden Kraft assoziiert. einen Himmelskörper mit der auf ihn wirkenden Kraft assoziiert.
- `Aufgabe2Test` ist eine vorgegebene Klasse, die Sie zum Testen Ihrer Implementierung verwenden - `Aufgabe2Test` ist eine vorgegebene Klasse, die Sie zum Testen Ihrer Implementierung verwenden
sollten. Bei einer fehlerfreien Implementierung sollten bei der Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful") ausgegeben werden. Sie müssen diese Klasse nicht verändern, können aber eigene Testfälle hinzufügen. sollten. Bei einer fehlerfreien Implementierung sollten bei der Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful") ausgegeben werden. Sie müssen diese Klasse nicht verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben ## Aufgaben
@ -27,10 +27,10 @@ Ihre Aufgaben sind folgende:
Body[] keys; // assume descending order according to mass Body[] keys; // assume descending order according to mass
Body toInsert; Body toInsert;
... ...
int left = 0; int left = 0;
int right = size - 1; int right = size - 1;
while (left <= right) { while (left <= right) {
int middle = left + ((right - left) / 2); int middle = left + ((right - left) / 2);
if (keys[middle].mass() < toInsert.mass()) { if (keys[middle].mass() < toInsert.mass()) {
@ -39,14 +39,14 @@ Ihre Aufgaben sind folgende:
left = middle + 1; left = middle + 1;
} }
} }
// index where to insert: right + 1 // index where to insert: right + 1
``` ```
4. Bauen Sie die bereits bestehende Klasse `Simulation` so um, dass keine Kollisionen von Himmelskörpern mehr berücksichtigt werden. Dadurch soll der Programmcode vereinfacht werden. Die Anzahl der Himmelskörper ändert sich im Laufe der Simulation somit nicht. Testen Sie die Simulation. 4. Bauen Sie die bereits bestehende Klasse `Simulation` so um, dass keine Kollisionen von Himmelskörpern mehr berücksichtigt werden. Dadurch soll der Programmcode vereinfacht werden. Die Anzahl der Himmelskörper ändert sich im Laufe der Simulation somit nicht. Testen Sie die Simulation.
5. Ändern Sie nun die Klasse `Simulation` so, dass zur Verwaltung der Himmelskörper anstelle des Arrays Objekte der Klassen `BodyQueue` und `BodyForceMap` verwendet werden. Das heißt beispielsweise, dass die Zugriffe auf die Himmelskörper der Simulation über Methoden von `BodyQueue` erfolgen müssen. Anstelle des Arrays `forceOnBody` soll ein Objekt des Typs `BodyForceMap` benutzt werden. 5. Ändern Sie nun die Klasse `Simulation` so, dass zur Verwaltung der Himmelskörper anstelle des Arrays Objekte der Klassen `BodyQueue` und `BodyForceMap` verwendet werden. Das heißt beispielsweise, dass die Zugriffe auf die Himmelskörper der Simulation über Methoden von `BodyQueue` erfolgen müssen. Anstelle des Arrays `forceOnBody` soll ein Objekt des Typs `BodyForceMap` benutzt werden.
6. Testen Sie die Simulation wieder. Das Verhalten der Simulation sollte unverändert sein. Je nach Implementierung der Klassen `BodyQueue` und `BodyForceMap` ist es möglich (und kein Problem), dass die Simulation jetzt langsamer läuft, als nach dem Umbau in Schritt 4. 6. Testen Sie die Simulation wieder. Das Verhalten der Simulation sollte unverändert sein. Je nach Implementierung der Klassen `BodyQueue` und `BodyForceMap` ist es möglich (und kein Problem), dass die Simulation jetzt langsamer läuft, als nach dem Umbau in Schritt 4.
7. (Freiwillige Zusatzaufgabe ohne Bewertung:) Testen Sie die Simulation mit den folgenden fünf 7. (Freiwillige Zusatzaufgabe ohne Bewertung:) Testen Sie die Simulation mit den folgenden fünf
Himmelskörpern: Himmelskörpern:
``` ```
Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0)); Body sun = new Body(1.989e30,new Vector3(0,0,0),new Vector3(0,0,0));
Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0)); Body earth = new Body(5.972e24,new Vector3(-1.394555e11,5.103346e10,0),new Vector3(-10308.53,-28169.38,0));
@ -60,4 +60,4 @@ Himmelskörpern:
- Implementierung von `BodyQueue`: 2 Punkte - Implementierung von `BodyQueue`: 2 Punkte
- Implementierung von `BodyForceMap`: 2 Punkte - Implementierung von `BodyForceMap`: 2 Punkte
- Anpassung von `Simulation`: 1 Punkt - Anpassung von `Simulation`: 1 Punkt
- Gesamt: 5 Punkte - Gesamt: 5 Punkte

View File

@ -2,15 +2,15 @@
## Allgemeine Anmerkungen ## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 2.5. 11h durch `git commit` und `push` Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 2.5. 11h durch `git commit` und `push`
abzugeben. Mit der Angabe werden die Dateien `CosmicSystem.java`, `Drawable.java`, abzugeben. Mit der Angabe werden die Dateien `CosmicSystem.java`, `Drawable.java`,
`NamedBodyForcePair.java`, `HierarchicalSystem.java`, `Simulation4.java` und `Aufgabe4Test.java` `NamedBodyForcePair.java`, `HierarchicalSystem.java`, `Simulation4.java` und `Aufgabe4Test.java`
mitgeliefert. mitgeliefert.
Wenn Sie zusätzlich zu den gefragten Klassen weitere Klassen definieren, achten Sie darauf, dass Wenn Sie zusätzlich zu den gefragten Klassen weitere Klassen definieren, achten Sie darauf, dass
die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden. die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden.
## Ziel ## Ziel
Ziel der Aufgabe ist die Anwendung der Konzepte: Interfaces, dynamisches Binden, toString() Ziel der Aufgabe ist die Anwendung der Konzepte: Interfaces, dynamisches Binden, toString()
(siehe Skriptum Seite 75-84). (siehe Skriptum Seite 75-84).
## Beschreibung der gegebenen Dateien ## Beschreibung der gegebenen Dateien
@ -20,7 +20,7 @@ Ziel der Aufgabe ist die Anwendung der Konzepte: Interfaces, dynamisches Binden,
Hierarchie von Systemen und Subsystemen beschreiben. Unser Sonnensystem ist ein Beispiel eines Systems, Hierarchie von Systemen und Subsystemen beschreiben. Unser Sonnensystem ist ein Beispiel eines Systems,
das mehrere Teilsysteme beinhaltet. Ein solches Teilsystem ist beispielsweise das System Erde und Erdmond. das mehrere Teilsysteme beinhaltet. Ein solches Teilsystem ist beispielsweise das System Erde und Erdmond.
Ein anderes Teilsystem wäre Jupiter mit seinen Monden. Verändern Sie dieses Interface nicht. Ein anderes Teilsystem wäre Jupiter mit seinen Monden. Verändern Sie dieses Interface nicht.
- [Drawable](../src/Drawable.java) wird von `CosmicSystem` verwendet. Verändern Sie dieses Interface - [Drawable](../src/Drawable.java) wird von `CosmicSystem` verwendet. Verändern Sie dieses Interface
nicht. nicht.
- [NamedBodyForcePair](../src/NamedBodyForcePair.java) ist das Gerüst für eine Klassendefinition. - [NamedBodyForcePair](../src/NamedBodyForcePair.java) ist das Gerüst für eine Klassendefinition.
Die Klasse implementiert `CosmicSystem` und repräsentiert einen einzelnen benannten Himmelskörper Die Klasse implementiert `CosmicSystem` und repräsentiert einen einzelnen benannten Himmelskörper
@ -34,8 +34,8 @@ die Simulation analog zur Klasse `Simulation` implementiert werden (damit Sie Ih
Datei](../src/Simulation.java) nicht überschreiben müssen). Datei](../src/Simulation.java) nicht überschreiben müssen).
- [Aufgabe4Test](../src/Aufgabe4Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer - [Aufgabe4Test](../src/Aufgabe4Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer
Implementierung verwenden sollten. Bei einer fehlerfreien Implementierung sollten bei der Implementierung verwenden sollten. Bei einer fehlerfreien Implementierung sollten bei der
Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful") Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful")
ausgegeben werden. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie ausgegeben werden. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie
müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen. müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben ## Aufgaben
@ -45,7 +45,7 @@ Ihre Aufgaben sind folgende:
**1. Implementierung von `CosmicSystem` in `NamedBodyForcePair`:** **1. Implementierung von `CosmicSystem` in `NamedBodyForcePair`:**
Fügen Sie in der Klasse `Body` eine öffentliche Methode `massCenter()` hinzu, die die Fügen Sie in der Klasse `Body` eine öffentliche Methode `massCenter()` hinzu, die die
Position des Himmelskörpers liefert. Position des Himmelskörpers liefert.
Definieren Sie die Klasse `NamedBodyForcePair` so, dass sie das Interface `CosmicSystem` Definieren Sie die Klasse `NamedBodyForcePair` so, dass sie das Interface `CosmicSystem`
implementiert. Die Methoden `getMass()` und `getMassCenter()` geben lediglich die Masse bzw. implementiert. Die Methoden `getMass()` und `getMassCenter()` geben lediglich die Masse bzw.
Position des Himmelskörpers zurück. Position des Himmelskörpers zurück.
@ -84,14 +84,14 @@ Kraft, indem alle Kräfte die von Körpern aus `this` auf das `NamedBodyForcePai
ausgeübt werden, zur Kraft im Objekt hinzuaddiert werden. Beispiel: Die ausgeübt werden, zur Kraft im Objekt hinzuaddiert werden. Beispiel: Die
Anweisung `cs.addForce(cs)` aktualisiert alle wechselseitigen im System `cs` wirkenden Kräfte. Anweisung `cs.addForce(cs)` aktualisiert alle wechselseitigen im System `cs` wirkenden Kräfte.
- `update()` führt auf Basis der gespeicherten Kräfte alle Bewegungen im System `this` durch und - `update()` führt auf Basis der gespeicherten Kräfte alle Bewegungen im System `this` durch und
setzt danach alle Kräfte wieder auf den null-Vektor zurück. setzt danach alle Kräfte wieder auf den null-Vektor zurück.
- `getBodies()` liefert eine Liste (Typ: `BodyLinkedList`) mit allen Himmelskörpern aus `this`. - `getBodies()` liefert eine Liste (Typ: `BodyLinkedList`) mit allen Himmelskörpern aus `this`.
**3. Implementierung von `Simulation4`:** **3. Implementierung von `Simulation4`:**
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
`HierachicalSystem`. Alle Berechnungen sollen mittels Methoden von `CosmicSystem` durchgeführt `HierachicalSystem`. Alle Berechnungen sollen mittels Methoden von `CosmicSystem` durchgeführt
werden. werden.
@ -110,7 +110,7 @@ die einzelnen Körper in `cs` dadurch erreicht werden, dass `this` für alle sei
und Untersysteme `addForceTo(cs)` aufruft. Wird beim rekursiven Abstieg ein einzelner Himmelskörper und Untersysteme `addForceTo(cs)` aufruft. Wird beim rekursiven Abstieg ein einzelner Himmelskörper
erreicht (Blattknoten) ruft dieser `cs.addForceFrom(this)` auf. erreicht (Blattknoten) ruft dieser `cs.addForceFrom(this)` auf.
- Achten Sie bei der Berechnung der Kräfte in `addForceFrom(Body b)` darauf, dass die Kraft nicht - Achten Sie bei der Berechnung der Kräfte in `addForceFrom(Body b)` darauf, dass die Kraft nicht
verändert wird, wenn `this` und `b` derselbe Himmelskörper sind. verändert wird, wenn `this` und `b` derselbe Himmelskörper sind.
#### _Punkteaufteilung_ #### _Punkteaufteilung_

102
angabe/Aufgabenblatt5.md Normal file
View File

@ -0,0 +1,102 @@
# Aufgabenblatt 5
## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 9.5. 11h durch `git commit` und `git push`
abzugeben. Mit der Angabe werden die Dateien `Massive.java`, `NamedBody.java`, `MassiveLinkedList.java`,
`MassiveForceHashMap.java`, `Simulation5.java` und `Aufgabe5Test.java` mitgeliefert.
Wenn Sie zusätzlich zu den gefragten Klassen weitere Klassen definieren, achten Sie darauf, dass
die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden.
## Ziel
Ziel der Aufgabe ist die Anwendung der Konzepte: Gleichheit und Hash-Werte, Hash-Tabelle
(siehe Skriptum Seite 85-91).
## Beschreibung der gegebenen Dateien
- [Massive](../src/Massive.java) ist ein Interface, das Himmelskörper (als kohärente Massen)
beschreibt. `Massive` ist der gemeinsame Obertyp für verschiedene Klassen von Himmelkörpern. Die
meisten spezifizierten Methoden sind mit einer `default`-Implementierung definiert. Dieser
Programmcode wird ausgeführt, falls die entsprechende Klasse (`Body` oder `NamedBody`) über keine
eigene Definition der Methode verfügt. Verändern Sie diese Datei bitte nicht.
- [NamedBody](../src/NamedBody.java) ist das Gerüst einer Klassendefinition. Die Klasse
repräsentiert Himmelskörper, die einen Namen haben.
- [MassiveLinkedList](../src/MassiveLinkedList.java) ist das Gerüst für eine Implementierung einer
verketteten Liste von `Massive`-Objekten. Die Liste unterscheidet sich von `BodyLinkedList`
dadurch, dass der Elementtyp statt `Body` der Obertyp `Massive` ist.
- [MassiveForceHashMap](../src/MassiveForceHashMap.java) ist das Gerüst für eine Implementierung
einer assoziativen Datenstruktur, die ein `Massive`-Objekt mit der auf das Objekt wirkenden Kraft
assoziiert.
- [Simulation5](../src/Simulation5.java) ist ein Gerüst für eine ausführbare Klasse. Hier soll
die Simulation analog zur Klasse `Simulation` implementiert werden (damit Sie Ihre [ursprüngliche
Datei](../src/Simulation.java) nicht überschreiben müssen).
- [Aufgabe5Test](../src/Aufgabe5Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer
Implementierung verwenden sollten. Bei einer fehlerfreien Implementierung sollten bei der
Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful")
ausgegeben werden. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie
müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben
Ihre Aufgaben sind folgende:
**1. Implementieren Sie `Massive` in den Klassen `Body` und `NamedBody`.**
Passen Sie die bestehende Definition von `Body` so an, dass die Klasse `Massive` implementiert wird.
Vervollständigen Sie auch `NamedBody` so, dass sie `Massive` implementiert und die vorgegebene
Spezifikationen der Methoden erfüllt.
**2. Überschreiben von `equals` und `hashCode` in `NamedBody`:**
Überschreiben Sie in `NamedBody` die Methoden `equals` und `hashCode` gemäß der dort angeführten
Spezifikation. Achten Sie bei der Implementierung darauf, dass die in der Klasse `Object`
beschriebenen Bedingungen für `equals` und `hashCode` eingehalten werden. `equals` und `hashCode`
müssen zusammen passen.
**3. Vervollständigen von `MassiveLinkedList`:**
Definieren Sie `MassiveLinkedList`. Die Klasse ist wie `BodyLinkedList` aufgebaut, mit dem
Unterschied, dass der Elementtyp statt `Body` nun der Typ `Massive` ist. Die Methode `indexOf`
vergleicht Objekte mittels `equals`.
**4. Implementierung von `MassiveForceHashMap`:**
Vervollständigen Sie die Definition der Klasse `MassiveForceHashMap`, die eine Hash-Tabelle
mit Schlüssel vom Typ `Massive` und Wert vom Typ `Vector3` implementiert. Die Klasse ist ähnlich
zur Klasse `BodyForceTreeMap`. Die Unterschiede sind:
- Der Typ des Schlüssels ist der gemeinsame Obertyp von `Body` und `NamedBody` (`Massive`).
Dadurch lassen sich Objekte beider Klassen gemeinsam in der Hash-Tabelle speichern.
- Die Schlüssel-Werte-Paare sind nicht nach Masse sortiert. Stattdessen wird der Hash-Wert zur
Suche benutzt.
- Es gibt eine zusätzliche Methode `keyList()`. Die Methoden `equals` und `hashCode` werden
redefiniert.
**5. Implementierung von `Simulation5`:**
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
`MassiveForceHashMap`. Die Methode `keyList()` hilft beim Iterieren der Hash-Tabelle.
Kollisionen von Himmelskörpern müssen in dieser Simulation nicht berücksichtigt werden.
### Hinweise:
- Verwenden Sie bei der Implementierung von `MassiveForceHashMap` eine geeignete Kollisionsbehandlung
für gleiche Hash-Werte. Als Vorlage können Sie den Beispielcode aus dem Skriptum nutzen.
### Denkanstöße (ohne Bewertung)
1. Wie könnte man vorgehen, wenn man - wie in früheren Simulationen - Himmelskörper im Fall von
Kollisionen verschmelzen will?
2. Was ändert sich am Verhalten von `MassiveForceHashMap`, wenn man in `Body` die Methoden
`equals` und `hashCode` überschreiben würde?
#### _Punkteaufteilung_
- Implementierung von `Massive` in `NamedBody`: 1 Punkt
- Implementierung von `Massive` in `Body`: 0.5 Punkt
- Implementierung von `MassiveForceHashMap`: 2 Punkte
- Implementierung von `MassiveLinkedList`: 0.5 Punkte
- Implementierung von `Simulation5`: 1 Punkte
- Gesamt: 5 Punkte

75
angabe/Aufgabenblatt6.md Normal file
View File

@ -0,0 +1,75 @@
# Aufgabenblatt 6
## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 23.5. 11h durch `git commit` und `git push`
abzugeben. Mit der Angabe werden die Dateien `MassiveIterable.java`, `MassiveIterator.java`,
`MassiveSet.java`, `MassiveForceTreeMap.java`, `Simulation6.java` und `Aufgabe6Test.java`
mitgeliefert.
Wenn Sie zusätzlich zu den gefragten Klassen weitere Klassen definieren, achten Sie darauf, dass
die Klassennamen mit `My` beginnen, um Konflikte mit späteren Aufgabenblättern zu vermeiden.
## Ziel
Ziel der Aufgabe ist die Anwendung der Konzepte: Iterator, Kopie vs. Sichtweise, Sortieren
(siehe Skriptum Seite 91-109).
## Beschreibung der gegebenen Dateien
- [MassiveIterable](../src/MassiveIterable.java) ist ein Interface, das iterierbare Objekte mit
Elementen vom Typ `Massive` spezifiziert. Verändern Sie diese Datei bitte nicht.
- [MassiveIterator](../src/MassiveIterator.java) ist ein Interface, das einen Iterator über
Elemente vom Typ `Massive` spezifiziert. Verändern Sie diese Datei bitte nicht.
- [MassiveSet](../src/MassiveSet.java) ist ein Interface, das iterierbare Mengen mit
`Massive`-Elementen spezifiziert. Verändern Sie diese Datei bitte nicht.
- [MassiveForceTreeMap](../src/MassiveForceTreeMap.java) ist das Gerüst für eine Implementierung
einer assoziativen Datenstruktur, die ein `Massive`-Objekt mit der auf das Objekt wirkenden Kraft
assoziiert.
- [Simulation6](../src/Simulation6.java) ist ein Gerüst für eine ausführbare Klasse. Hier soll
die Simulation analog zur Klasse `Simulation` implementiert werden (damit Sie Ihre [ursprüngliche
Datei](../src/Simulation.java) nicht überschreiben müssen).
- [Aufgabe6Test](../src/Aufgabe6Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer
Implementierung verwenden sollten. Bei einer fehlerfreien Implementierung sollten bei der
Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful")
ausgegeben werden. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie
müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben
Ihre Aufgaben sind folgende:
**1. Implementieren Sie die Klasse `MassiveForceTreeMap`.**
Implementieren Sie die Klasse `MassiveForceTreeMap`. `MassiveForceTreeMap` ist wie
`BodyForceTreeMap` aufgebaut, mit dem Unterschied, dass der Typ des Schlüssels statt `Body` nun
der Typ `Massive` ist. Weiters soll die Klasse Methode `getKeys()` zur Verfügung stellen,
die eine `MassiveSet`-Sichtweise auf die Menge der Schlüssel liefert. Änderungen an dem
zurückgelieferten `MassiveSet`-Objekt wirken sich auf das zugrunde
liegende `MassiveForceTreeMap`-Objekt aus. Die Methode `toList()` liefert dagegen eine
unabhängige Liste (Kopie) mit allen Schlüsseln der Map. Für die Implementierung von
`MassiveSet` können Sie einen eigenen Klassennamen beginnend mit `My` wählen. Die Definition kann
in einer eigenen Datei oder in der Datei `MassiveForceTreeMap.java` erfolgen.
**2. Adaptieren Sie die Klasse `HierarchicalSystem`:**
Die Klasse `HierarchicalSystem` soll so geändert werden, dass sie das gegebene
Interface `MassiveIterable` implementiert. Die Reihenfolge der vom Iterator gelieferten
Elemente ist nicht festgelegt. Sie dürfen für die Implementierung bei Bedarf Ihren Klassen
`NamedBodyForcePair` und `HierarchicalSystem` neue, nicht angegebene Methoden hinzufügen.
Die Verwendung von Klassen des Java-Collection-Frameworks (z.B. java.util.Stack) ist erlaubt
(aber nicht notwendig).
**3. Implementierung von `Simulation6`:**
Implementieren Sie die Simulationsschleife unter Verwendung eines Objekts vom Typ
`MassiveForceTreeMap`. Die Methode `getKeys()` hilft beim Iterieren der gespeicherten Schlüssel.
Kollisionen von Himmelskörpern müssen in dieser Simulation nicht berücksichtigt werden.
#### _Punkteaufteilung_
- Implementierung von `MassiveForceTreeMap`: 3 Punkte
- Implementierung von `MassiveIterable` in `HierarchicalSystem`: 1.5 Punkte
- Implementierung von `Simulation6`: 0.5 Punkte
- Gesamt: 5 Punkte

152
angabe/Aufgabenblatt8.md Normal file
View File

@ -0,0 +1,152 @@
# Aufgabenblatt 8
## Allgemeine Anmerkungen
Ihre Lösung für dieses Aufgabenblatt ist bis Montag, 13.6., 11h durch `git commit` und `git push`
abzugeben.
Wenn Sie zusätzlich zu den gefragten Klassen und Interfaces weitere Klassen oder
Interfaces definieren, achten Sie darauf, dass die Klassennamen mit `My` beginnen, um Konflikte
mit späteren Aufgabenblättern zu vermeiden.
Weiters werden die Dateien `StateFileNotFoundException.java`,
`StateFileFormatException.java`, `ReadDataUtil.java`, `Simulation8.java`, `Simulation9.java`,
`Aufgabe8Test.java` und das Verzeichnis `states` mit `txt`-Dateien mitgeliefert.
## Ziel
Ziel der Aufgabe ist das Verständnis und die Anwendung der Konzepte: Java-Collections, Eingabe mit
Validierung, Exceptions (S. 110-123).
## Beschreibung der gegebenen Dateien
- [states](../states) ist ein Verzeichnis, in dem mehrere Dateien mit der Endung `.txt`
mitgeliefert werden. Diese enthalten Daten von je einem Himmelskörper sowie dessen Positionen und
Geschwindigkeitsvektoren für alle Tage der Jahre 2019-2021. Die Angaben sind wie gewohnt in
kartesischen Koordinaten, wobei die Sonne den Ursprung des Koordinatensystems bildet und die
Ekliptik die x-y-Ebene darstellt. Die Daten stammen von [https://ssd.jpl.nasa.gov/horizons.cgi#top](https://ssd.jpl.nasa.gov/horizons.cgi#top).
**ACHTUNG**: Die Werte sind in km bzw. km/sec angegeben!
- [StateFileNotFoundException](../src/StateFileNotFoundException.java) enthält die Definition
der Klasse `StateFileNotFoundException`. Diese sollen Sie vervollständigen.
- [StateFileFormatException](../src/StateFileFormatException.java) enthält die Definition
der Klasse `StateFileFormatException`. Diese sollen Sie vervollständigen.
- [ReadDataUtil](../src/ReadDataUtil.java) ist eine Klasse mit einer statischen Methode zum
Einlesen von Position- und Bewegungsvektoren von Himmelskörpern aus Dateien.
Diese sollen Sie vervollständigen.
- [Simulation8](../src/Simulation8.java) ist ein Gerüst für eine ausführbare Klasse. Hier soll
die Simulation analog zur Klasse `Simulation` implementiert werden (damit Sie Ihre [ursprüngliche
Datei](../src/Simulation.java) nicht überschreiben müssen).
- [Simulation9](../src/Simulation9.java) ist eine leere Datei. Hier soll eine weitere Simulation
implementiert werden, die so wie `Simulation8` funktioniert, mit dem Unterschied, dass anstelle
der selbst implementierten Datenstrukturen nur vorgefertigte Klassen aus dem
Java-Collection-Framework benutzt werden sollen.
- [Aufgabe8Test](../src/Aufgabe8Test.java) ist eine vorgegebene Klasse, die Sie zum Testen Ihrer
Implementierung verwenden sollten. Bei einer fehlerfreien Implementierung sollten bei der
Ausführung dieser Klasse keine Exceptions geworfen werden und alle Tests als erfolgreich ("successful")
ausgegeben werden. Entfernen Sie die Kommentarzeichen, um diese Klasse verwenden zu können. Sie
müssen diese Klasse nicht weiter verändern, können aber eigene Testfälle hinzufügen.
## Aufgaben
1. Ändern Sie Ihre Implementierung, sodass ein `MassiveIterator` eine Exception
vom Typ `java.util.NoSuchElementException` wirft, falls `next()` aufgerufen wird,
jedoch der Iterator keine weitere Iteration hat (`hasNext()` liefert `false`).
2. Ändern Sie den Iterator von der von `getKeys()` zurückgelieferten
Sichtweise auf `MassiveForceTreeMap` so, dass `remove()` überschrieben wird
([siehe API Dokumentation](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html#remove--)),
sodass der Iterator Einträge in Objekten von `MassiveForceTreeMap` löschen kann. Achten Sie
darauf, dass hier in bestimmten Fällen eine `java.lang.IllegalStateException` geworfen werden
soll. Der Iterator von `HierarchicalSystem` muss nicht geändert werden.
3. Validierung von Eingabedaten:
- Implementieren Sie in der Klasse `ReadDataUtil.java` die Methode `readConfiguration`.
Es soll ein gepufferter Stream zum Einlesen genutzt werden (siehe Skriptum Seite 128).
Erstellen Sie zum Testen auch Varianten der txt-Dateien mit Formatfehlern.
- Fügen Sie der Klasse `NamedBody` bei Bedarf
eine Methode `setState(Vector3 position, Vector3 velocity)` zum Setzen der Position
und des Geschwindigkeitsvektors des Himmelskörpers hinzu.
- Definieren Sie die beiden angegebenen Exceptionklassen in den entsprechenden
mitgelieferten Dateien.
4. Ausnahmebehandlung:
In der Klasse `Simulation8` sollen nun die Himmelskörper mit Daten aus den gegebenen
txt-Dateien initialisiert werden. Dabei sollen zumindest die Sonne sowie die
inneren Planeten
Merkur, Venus, Erde und Mars vorkommen. Sie können weitere Himmelskörper (siehe txt-Dateien)
hinzufügen. Nutzen Sie die Klasse `MassiveForceTreeMap` und ihre Iteratoren, um die
Himmelskörper der Simulation zu verwalten. (Kollisionen von Himmelskörpern müssen nicht
berücksichtigt werden.)
Ändern Sie die Klasse `Simulation8` so, dass sie zwei Kommandozeilenargumente verarbeitet.
Das erste Argument ist ein String mit der Angabe des Pfades zum Verzeichnis, wo die
entsprechenden txt-Dateien (z.B. `Venus.txt`,`Mercury.txt`,`Earth.txt`) mit den Konfigurationen
der Himmelskörper zu finden sind. Die Dateien haben die Namen der Himmelskörper mit Endung `
.txt`. Für die Sonne gibt es keine txt-Datei (es wird die Position (0,0,0) angenommen).
Das zweite Argument ist ein String mit einer Datumsangabe der Form YYYY-MMM-DD, also z.B.
2020-Dec-04, die den Tag der auszulesenden Position und Bewegungsvektor bestimmt. Die Klasse
soll beim Auftreten von Problemen bei der Ausführung entsprechende Fehlermeldungen ausgeben und
die Ausführung in bestimmten Fällen beenden. Beispiele für Aufrufe im Kommandozeileninterpreter
mit entsprechenden Fehlermeldungen (Sie können zum Ausführen das Terminal in IntelliJ nutzen
oder die Programmargumente unter `Edit Configurations` angeben):
```
$ javac Simulation8.java
$ java Simulation8 ../states 2021-May-28
Running simulation ...
$ java Simulation8 ../states
Error: wrong number of arguments.
$ java Simulation8 ../states 2025-Dec-12
Warning: State not available for Earth.
Running simulation without Earth.
Warning: State not available for Venus.
Running simulation without Venus.
...
$ java Simulation8 ../states-altered 2021-May-28
Warning: File ../states-altered/Venus.txt does not have required format.
Running simulation without Venus.
Warning: File ../states-altered/Mars.txt not found.
Running simulation without Mars.
Running simulation ...
$ java Simulation8 ../states -17
Error: State has wrong format (requires YYYY-MM-DD), aborting.
$ java Simulation8 blah 2021-May-28
Warning: File blah/Earth.txt not found.
Running simulation without Earth.
Warning: File blah/Venus.txt not found.
Running simulation without Venus.
...
```
5. Kopieren Sie den Inhalt der Datei `Simulation8.java` in die Datei `Simulation9.java` und bauen
Sie `Simulation9` so um, dass anstelle der selbst implementierten Datenstrukturen nur
vorgefertigte Klassen aus dem Java-Collection-Framework benutzt werden.
6. Freiwillige Zusatzaufgabe (ohne Bewertung):
Ändern Sie die Klasse `Simulation8` so um, dass ein drittes optionales Kommandozeilenargument
verarbeitet werden kann. Dieses gibt an, wie viele Tage simuliert werden sollen. Beispielsweise
kann eine zweite Datumsangabe möglich sein, oder die Anzahl an Tagen.
Sobald dieser Zeitpunkt in der Simulation erreicht wurde, können die aktuellen Positionen der
Himmelskörper mit den in den txt-Dateien angegebenen Positionen verglichen werden (z.B.
durch erneutem Aufruf von `readConfiguration` und `draw`). Wie groß sind die Abweichungen
der von NASA errechneten Positionen zu den Positionen, die Ihre Simulation liefert?
### Denkanstöße (ohne Bewertung)
1. Haben Sie die remove-Methode des Iterators so implementiert, dass der Aufruf keine
zusätzliche Suche nach dem zu löschenden Eintrag benötigt?
2. Wie verhalten sich die von der Methode `toList()` der Klasse `MassiveForceTreeMap`
zurückgelieferten Listen, wenn deren enthaltene Himmelskörper durch `setState` verändert werden?
Werden dadurch die Himmelskörper der ursprünglichen `MassiveForceTreeMap`-Objekte auch geändert?
(Anmerkung: diesbezüglich gibt es im Aufgabenblatt 6 keine Vorgaben).
3. Wie verhalten sich Ihre Iteratoren, wenn Objekte geändert werden?
4. Wie kann man durch Einfügen von Zeichen `,` und newlines (`\n`) aus den `txt`-Dateien eine
"fehlerhafte" Datei machen, die trotzdem von der Methode akzeptiert wird? Kann man solche Probleme
verhindern?
#### _Punkteaufteilung_
- Änderung von `next()` von `MassiveIterator`: 0.5 Punkte
- Implementierung der Methode `remove()` im Iterator der `MassiveSet`-Sichtweise
von `MassiveForceTreeMap`: 2 Punkte
- Implementierung der Exceptionklassen und Implementierung von `readConfiguration`
in `ReadDataUtil`: 1.5 Punkte
- Implementierung von `Simulation8` und `Simulation9`: 1 Punkt

96
src/Aufgabe5Test.java Normal file
View File

@ -0,0 +1,96 @@
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class Aufgabe5Test {
@Test
public void testEP2() {
//test classes NamedBody and MassiveForceHashMap
// create 12 named bodies
NamedBody sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1;
// create a nameless body
Body earth2 = new Body(SolSystem4.EARTH);
// create the same 12 named body-force pairs
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
moon1 = new NamedBody(SolSystem4.MOON_NAMED);
mars1 = new NamedBody(SolSystem4.MARS_NAMED);
deimos1 = new NamedBody(SolSystem4.DEIMOS_NAMED);
phobos1 = new NamedBody(SolSystem4.PHOBOS_NAMED);
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
vesta1 = new NamedBody(SolSystem4.VESTA_NAMED);
pallas1 = new NamedBody(SolSystem4.PALLAS_NAMED);
hygiea1 = new NamedBody(SolSystem4.HYGIEA_NAMED);
ceres1 = new NamedBody(SolSystem4.CERES_NAMED);
NamedBody sun2 = new NamedBody("Sun", 1.9895E30, new Vector3(0.1, 0.0, 0.0), new Vector3(0.0, 0.0, 0.0));
NamedBody earth3 = new NamedBody("Earth", 1, new Vector3(0, 0, 0), new Vector3(0, 0, 0));
assertEquals(sun1, sun2);
assertEquals(sun2.hashCode(), sun1.hashCode());
assertEquals(earth1, earth3);
assertEquals(earth3.hashCode(), earth1.hashCode());
// check basic functions of 'MassiveForceHashMap'
MassiveForceHashMap map = new MassiveForceHashMap();
map.put(sun1, new Vector3(0, 0, 0));
map.put(mercury1, new Vector3(0, 0, 0));
map.put(venus1, new Vector3(0, 0, 0));
map.put(earth1, new Vector3(0, 0, 0));
map.put(moon1, new Vector3(0, 0, 0));
map.put(mars1, new Vector3(0, 0, 0));
map.put(deimos1, new Vector3(0, 0, 0));
map.put(phobos1, new Vector3(0, 0, 0));
map.put(vesta1, new Vector3(0, 0, 0));
map.put(pallas1, new Vector3(0, 0, 0));
map.put(hygiea1, new Vector3(0, 0, 0));
map.put(ceres1, new Vector3(0, 0, 0));
map.put(mars1, new Vector3(0, 0, 0)); // inserted twice
assertEquals(12, map.keyList().size());
assertTrue(map.toString().contains("Mars"));
assertTrue(map.toString().contains("Deimos"));
assertTrue(map.toString().contains("Moon"));
assertTrue(map.toString().contains("Earth"));
MassiveLinkedList bl = map.keyList();
boolean allThere = true;
while (bl.size() > 0) {
allThere &= map.containsKey(bl.pollFirst());
}
assertTrue(allThere);
assertFalse(map.containsKey(new Body(0, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
assertFalse(map.containsKey(new NamedBody("Omuamua", 0, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
int hashCode1 = map.hashCode();
Vector3 f = new Vector3(5, 5, 5);
map.put(earth3, f);
assertEquals(f, map.get(earth1));
assertNull(map.get(earth2));
int hashCode2 = map.hashCode();
assertEquals(map, map);
assertEquals(hashCode2, map.hashCode());
assertNotEquals(hashCode1, hashCode2);
}
@Test
public void testDelKey() {
MassiveForceHashMap map = new MassiveForceHashMap();
NamedBody sun1 = new NamedBody(SolSystem4.SUN_NAMED);
NamedBody earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
NamedBody moon1 = new NamedBody(SolSystem4.MOON_NAMED);
map.put(sun1, new Vector3());
map.put(earth1, new Vector3());
map.put(moon1, new Vector3());
assertNotNull(map.get(sun1));
assertNotNull(map.delete(sun1));
assertNull(map.get(sun1));
assertNull(map.delete(sun1));
}
}

133
src/Aufgabe6Test.java Normal file
View File

@ -0,0 +1,133 @@
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import static org.junit.jupiter.api.Assertions.*;
public class Aufgabe6Test {
@Test
public void testEP2() {
NamedBody sun1, mercury1, venus1, earth1, moon1, mars1, deimos1, phobos1, vesta1, pallas1, hygiea1, ceres1;
// create the same 12 named body-force pairs
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
earth1 = new NamedBody(SolSystem4.EARTH_NAMED);
moon1 = new NamedBody(SolSystem4.MOON_NAMED);
mars1 = new NamedBody(SolSystem4.MARS_NAMED);
deimos1 = new NamedBody(SolSystem4.DEIMOS_NAMED);
phobos1 = new NamedBody(SolSystem4.PHOBOS_NAMED);
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
vesta1 = new NamedBody(SolSystem4.VESTA_NAMED);
pallas1 = new NamedBody(SolSystem4.PALLAS_NAMED);
hygiea1 = new NamedBody(SolSystem4.HYGIEA_NAMED);
ceres1 = new NamedBody(SolSystem4.CERES_NAMED);
// check basic functions of 'MassiveForceHashMap'
MassiveForceTreeMap map = new MassiveForceTreeMap();
map.put(sun1, new Vector3(0, 0, 0));
map.put(mercury1, new Vector3(0, 0, 0));
map.put(venus1, new Vector3(0, 0, 0));
map.put(earth1, new Vector3(0, 0, 0));
map.put(moon1, new Vector3(0, 0, 0));
map.put(mars1, new Vector3(0, 0, 0));
map.put(deimos1, new Vector3(0, 0, 0));
map.put(phobos1, new Vector3(0, 0, 0));
map.put(vesta1, new Vector3(0, 0, 0));
map.put(pallas1, new Vector3(0, 0, 0));
map.put(hygiea1, new Vector3(0, 0, 0));
map.put(ceres1, new Vector3(0, 0, 0));
map.put(mars1, new Vector3(0, 0, 0)); // inserted twice
HashSet<Massive> set1 = new HashSet<>();
set1.add(sun1);
set1.add(mercury1);
set1.add(venus1);
set1.add(earth1);
set1.add(moon1);
set1.add(mars1);
set1.add(deimos1);
set1.add(phobos1);
set1.add(vesta1);
set1.add(pallas1);
set1.add(hygiea1);
set1.add(ceres1);
assertTrue(map.toString().contains("Mars"));
assertTrue(map.toString().contains("Deimos"));
assertTrue(map.toString().contains("Moon"));
assertTrue(map.toString().contains("Earth"));
assertEquals(12, map.getKeys().size());
assertTrue(map.getKeys().contains(mars1));
assertTrue(map.getKeys().contains(new NamedBody("Mars", 6.41712E23, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
assertFalse(map.getKeys().contains(new Body(6.41712E23, new Vector3(0, 0, 0), new Vector3(0, 0, 0))));
HashSet<Massive> set2 = new HashSet<>();
for (Massive m : map.getKeys()) {
set2.add(m);
}
assertEquals(set1, set2);
MassiveLinkedList list = map.getKeys().toList();
while (list.size() > 0) {
set1.remove(list.pollLast());
}
assertTrue(set1.isEmpty());
map.getKeys().remove(mars1);
assertFalse(map.containsKey(mars1));
assertEquals(11, map.getKeys().size());
map.getKeys().clear();
assertEquals(0, map.getKeys().size());
NamedBodyForcePair sun2, mercury2, venus2, earth2, moon2, mars2, deimos2, phobos2, vesta2, pallas2, hygiea2, ceres2;
//test classes NamedBody and MassiveForceHashMap
// create 12 named bodies
// create the same 12 named body-force pairs
sun2 = new NamedBodyForcePair(SolSystem4.SUN_NAMED);
earth2 = new NamedBodyForcePair(SolSystem4.EARTH_NAMED);
moon2 = new NamedBodyForcePair(SolSystem4.MOON_NAMED);
mars2 = new NamedBodyForcePair(SolSystem4.MARS_NAMED);
deimos2 = new NamedBodyForcePair(SolSystem4.DEIMOS_NAMED);
phobos2 = new NamedBodyForcePair(SolSystem4.PHOBOS_NAMED);
mercury2 = new NamedBodyForcePair(SolSystem4.MERCURY_NAMED);
venus2 = new NamedBodyForcePair(SolSystem4.VENUS_NAMED);
vesta2 = new NamedBodyForcePair(SolSystem4.VESTA_NAMED);
pallas2 = new NamedBodyForcePair(SolSystem4.PALLAS_NAMED);
hygiea2 = new NamedBodyForcePair(SolSystem4.HYGIEA_NAMED);
ceres2 = new NamedBodyForcePair(SolSystem4.CERES_NAMED);
CosmicSystem earthSystem = new HierarchicalSystem(earth2, moon2);
CosmicSystem marsSystem = new HierarchicalSystem(mars2, deimos2, phobos2);
HierarchicalSystem solarSystem = new HierarchicalSystem(sun2, mercury2, venus2, earthSystem, marsSystem, vesta2, pallas2, hygiea2, ceres2);
int count = 0;
for (Massive b : solarSystem) {
count++;
}
assertEquals(12, count);
}
@Test
public void testIterator() {
NamedBody sun1, mercury1, venus1;
sun1 = new NamedBody(SolSystem4.SUN_NAMED);
mercury1 = new NamedBody(SolSystem4.MERCURY_NAMED);
venus1 = new NamedBody(SolSystem4.VENUS_NAMED);
MassiveForceTreeMap map = new MassiveForceTreeMap();
map.put(sun1, new Vector3());
map.put(mercury1, new Vector3());
map.put(venus1, new Vector3());
for (Massive m : map.getKeys().toList()) {
System.out.println(m);
}
}
}

50
src/Aufgabe8Test.java Normal file
View File

@ -0,0 +1,50 @@
import org.junit.jupiter.api.Test;
import java.util.NoSuchElementException;
import static org.junit.jupiter.api.Assertions.*;
public class Aufgabe8Test {
@Test
public void testEP2() {
MassiveForceTreeMap map = new MassiveForceTreeMap();
NamedBody mars;
map.put(new NamedBody("Oumuamua", 8e6, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Earth", 5.972E24, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Moon", 7.349E22, new Vector3(), new Vector3()), new Vector3());
map.put(mars = new NamedBody("Mars", 6.41712E23, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Deimos", 1.8E20, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Phobos", 1.08E20, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Mercury", 3.301E23, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Venus", 4.86747E24, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Vesta", 2.5908E20, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Pallas", 2.14E20, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Hygiea", 8.32E19, new Vector3(), new Vector3()), new Vector3());
map.put(new NamedBody("Ceres", 9.394E20, new Vector3(), new Vector3()), new Vector3());
assertEquals(12, map.size());
MassiveIterator iterator = map.getKeys().iterator();
int count;
for (count = 0; iterator.hasNext(); count++) {
if (iterator.next().equals(mars)) {
iterator.remove();
}
}
assertEquals(12, count);
assertEquals(11, map.getKeys().size());
assertEquals(11, map.size());
assertFalse(map.getKeys().contains(mars));
assertThrows(NoSuchElementException.class, iterator::next);
iterator = map.getKeys().iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
assertEquals(0, map.getKeys().size());
}
}

View File

@ -3,7 +3,7 @@ import codedraw.CodeDraw;
/** /**
* This class represents celestial bodies like stars, planets, asteroids, etc... * This class represents celestial bodies like stars, planets, asteroids, etc...
*/ */
public class Body { public class Body implements Massive {
private final double mass; private final double mass;
private Vector3 massCenter; // position of the mass center. private Vector3 massCenter; // position of the mass center.
private Vector3 currentMovement; private Vector3 currentMovement;
@ -20,6 +20,19 @@ public class Body {
this.currentMovement = new Vector3(other.currentMovement); this.currentMovement = new Vector3(other.currentMovement);
} }
public Body(double mass) {
this(mass, new Vector3(), new Vector3());
}
public Body() {
this(0);
}
public void setState(Vector3 position, Vector3 velocity) {
this.massCenter = new Vector3(position);
this.currentMovement = new Vector3(velocity);
}
/** /**
* Returns the distance between the mass centers of this body and the specified body 'b'. * Returns the distance between the mass centers of this body and the specified body 'b'.
*/ */

View File

@ -4,7 +4,7 @@
*/ */
public class BodyForceTreeMap { public class BodyForceTreeMap {
private int size = 0; private int size = 0;
private BodyForceTreeMapItem root = null; private Item root = null;
/** /**
* Adds a new key-value association to this map. If the key already exists in this map, * Adds a new key-value association to this map. If the key already exists in this map,
@ -13,30 +13,30 @@ public class BodyForceTreeMap {
*/ */
public Vector3 put(Body key, Vector3 value) { public Vector3 put(Body key, Vector3 value) {
if (root == null) { if (root == null) {
root = new BodyForceTreeMapItem(key, value); root = new Item(key, value);
size++; size++;
return null; return null;
} }
BodyForceTreeMapItem item = root; Item item = root;
while (item != null) { while (item != null) {
if (item.key() == key) { if (item.key == key) {
Vector3 old = item.value(); Vector3 old = item.value;
item.setValue(value); item.value = value;
return old; return old;
} else if (item.key().mass() > key.mass()) { } else if (item.key.mass() > key.mass()) {
if (item.left() != null) { if (item.left != null) {
item = item.left(); item = item.left;
} else { } else {
item.setLeft(new BodyForceTreeMapItem(key, value)); item.setLeft(new Item(key, value));
size++; size++;
break; break;
} }
} else { } else {
if (item.right() != null) { if (item.right != null) {
item = item.right(); item = item.right;
} else{ } else{
item.setRight(new BodyForceTreeMapItem(key, value)); item.setRight(new Item(key, value));
size++; size++;
break; break;
} }
@ -52,14 +52,14 @@ public class BodyForceTreeMap {
* Precondition: key != null. * Precondition: key != null.
*/ */
public Vector3 get(Body key) { public Vector3 get(Body key) {
BodyForceTreeMapItem item = root; Item item = root;
while (item != null) { while (item != null) {
if (item.key() == key) { if (item.key == key) {
return item.value(); return item.value;
} else if (item.key().mass() > key.mass()) { } else if (item.key.mass() > key.mass()) {
item = item.left(); item = item.left;
} else { } else {
item = item.right(); item = item.right;
} }
} }
return null; return null;
@ -69,14 +69,14 @@ public class BodyForceTreeMap {
* Returns 'true' if this map contains a mapping for the specified key. * Returns 'true' if this map contains a mapping for the specified key.
*/ */
public boolean containsKey(Body key) { public boolean containsKey(Body key) {
BodyForceTreeMapItem item = root; Item item = root;
while (item != null) { while (item != null) {
if (item.key() == key) { if (item.key == key) {
return true; return true;
} else if (item.key().mass() > key.mass()) { } else if (item.key.mass() > key.mass()) {
item = item.left(); item = item.left;
} else { } else {
item = item.right(); item = item.right;
} }
} }
return false; return false;
@ -86,15 +86,15 @@ public class BodyForceTreeMap {
return this.size; return this.size;
} }
private String toString(BodyForceTreeMapItem item) { private String toString(Item item) {
String s = ""; StringBuilder s = new StringBuilder();
if (item == null) { if (item == null) {
return s; return s.toString();
} }
s += this.toString(item.right()); s.append(this.toString(item.right));
s += String.format("{%s: %s}\n", item.key(), item.value()); s.append(String.format("{%s: %s}\n", item.key, item.value));
s += this.toString(item.left()); s.append(this.toString(item.left));
return s; return s.toString();
} }
/** /**
@ -103,53 +103,29 @@ public class BodyForceTreeMap {
*/ */
@Override @Override
public String toString() { public String toString() {
return toString(root); return (root != null) ? toString(root) : "";
} }
}
private static class Item {
class BodyForceTreeMapItem { private final Body key;
private final Body key; private Vector3 value;
private Vector3 value; private Item parent;
private BodyForceTreeMapItem parent; private Item left;
private BodyForceTreeMapItem left; private Item right;
private BodyForceTreeMapItem right;
public Item(Body key, Vector3 value) {
public BodyForceTreeMapItem(Body key, Vector3 value) { this.key = key;
this.key = key; this.value = value;
this.value = value; }
}
public void setLeft(Item left) {
public Body key() { this.left = left;
return this.key; if (left != null) left.parent = this;
} }
public void setValue(Vector3 value) { public void setRight(Item right) {
this.value = value; this.right = right;
} if (right != null) right.parent = this;
}
public Vector3 value() {
return this.value;
}
public BodyForceTreeMapItem left() {
return this.left;
}
public BodyForceTreeMapItem right() {
return this.right;
}
public BodyForceTreeMapItem parent() {
return this.parent;
}
public void setLeft(BodyForceTreeMapItem left) {
this.left = left;
if (left != null) left.parent = this;
}
public void setRight(BodyForceTreeMapItem right) {
this.right = right;
if (right != null) right.parent = this;
} }
} }

View File

@ -6,8 +6,8 @@ import java.util.Iterator;
*/ */
public class BodyLinkedList implements Iterable<Body> { public class BodyLinkedList implements Iterable<Body> {
private int size = 0; private int size = 0;
private BodyLinkedListItem first; private Item first;
private BodyLinkedListItem last; private Item last;
/** /**
* Initializes 'this' as an empty list. * Initializes 'this' as an empty list.
@ -35,11 +35,11 @@ public class BodyLinkedList implements Iterable<Body> {
*/ */
public void addFirst(Body body) { public void addFirst(Body body) {
if (first == null) { if (first == null) {
first = new BodyLinkedListItem(body); first = new Item(body);
last = first; last = first;
} else { } else {
first.setPrev(new BodyLinkedListItem(body)); first.setPrev(new Item(body));
first = first.prev(); first = first.prev;
} }
size++; size++;
} }
@ -49,11 +49,11 @@ public class BodyLinkedList implements Iterable<Body> {
*/ */
public void addLast(Body body) { public void addLast(Body body) {
if (last == null) { if (last == null) {
last = new BodyLinkedListItem(body); last = new Item(body);
first = last; first = last;
} else { } else {
last.setNext(new BodyLinkedListItem(body)); last.setNext(new Item(body));
last = last.next(); last = last.next;
} }
size++; size++;
} }
@ -63,7 +63,7 @@ public class BodyLinkedList implements Iterable<Body> {
* Returns 'null' if the list is empty. * Returns 'null' if the list is empty.
*/ */
public Body getLast() { public Body getLast() {
return (last != null) ? last.body() : null; return (last != null) ? last.body : null;
} }
/** /**
@ -71,7 +71,7 @@ public class BodyLinkedList implements Iterable<Body> {
* Returns 'null' if the list is empty. * Returns 'null' if the list is empty.
*/ */
public Body getFirst() { public Body getFirst() {
return (first != null) ? first.body() : null; return (first != null) ? first.body : null;
} }
/** /**
@ -82,8 +82,8 @@ public class BodyLinkedList implements Iterable<Body> {
if (first == null) { if (first == null) {
return null; return null;
} }
Body b = first.body(); Body b = first.body;
first = first.next(); first = first.next;
if (first != null) first.setPrev(null); if (first != null) first.setPrev(null);
size--; size--;
return b; return b;
@ -97,8 +97,8 @@ public class BodyLinkedList implements Iterable<Body> {
if (last == null) { if (last == null) {
return null; return null;
} }
Body b = last.body(); Body b = last.body;
last = last.prev(); last = last.prev;
if (last != null) last.setNext(null); if (last != null) last.setNext(null);
size--; size--;
return b; return b;
@ -117,28 +117,28 @@ public class BodyLinkedList implements Iterable<Body> {
return; return;
} }
BodyLinkedListItem item = first; Item item = first;
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
item = item.next(); item = item.next;
} }
item.prev().setNext(new BodyLinkedListItem(body)); item.prev.setNext(new Item(body));
item.setPrev(item.prev().next()); item.setPrev(item.prev.next);
size++; size++;
} }
private Body removeItem(BodyLinkedListItem item) { private Body removeItem(Item item) {
if (item == first) { if (item == first) {
first = item.next(); first = item.next;
if (first != null) first.setPrev(null); if (first != null) first.setPrev(null);
} else if (item == last) { } else if (item == last) {
last = item.prev(); last = item.prev;
if (last != null) last.setNext(null); if (last != null) last.setNext(null);
} else { } else {
item.next().setPrev(item.prev()); item.next.setPrev(item.prev);
} }
size--; size--;
return item.body(); return item.body;
} }
/** /**
@ -146,19 +146,19 @@ public class BodyLinkedList implements Iterable<Body> {
* Precondition: i >= 0 && i < size(). * Precondition: i >= 0 && i < size().
*/ */
public Body get(int i) { public Body get(int i) {
BodyLinkedListItem item; Item item;
if (i < size / 2) { if (i < size / 2) {
item = first; item = first;
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
item = item.next(); item = item.next;
} }
} else { } else {
item = last; item = last;
for (int j = size - 1; j > i; j--) { for (int j = size - 1; j > i; j--) {
item = item.prev(); item = item.prev;
} }
} }
return item.body(); return item.body;
} }
/** /**
@ -170,12 +170,9 @@ public class BodyLinkedList implements Iterable<Body> {
return -1; return -1;
} }
BodyLinkedListItem item = first; Item item = first;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++, item = item.next) {
if (item.body() == body) { if (item.body == body) return i;
return i;
}
item = item.next();
} }
return -1; return -1;
@ -187,8 +184,8 @@ public class BodyLinkedList implements Iterable<Body> {
*/ */
public BodyLinkedList removeCollidingWith(Body body) { public BodyLinkedList removeCollidingWith(Body body) {
BodyLinkedList removed = new BodyLinkedList(); BodyLinkedList removed = new BodyLinkedList();
for (BodyLinkedListItem item = first; item != null; item = item.next()) { for (Item item = first; item != null; item = item.next) {
if (body != item.body() && body.collidesWith(item.body())) { if (body != item.body && body.collidesWith(item.body)) {
removed.addLast(this.removeItem(item)); removed.addLast(this.removeItem(item));
} }
} }
@ -205,57 +202,45 @@ public class BodyLinkedList implements Iterable<Body> {
@Override @Override
public Iterator<Body> iterator() { public Iterator<Body> iterator() {
return new Iterator<>() { return new Iterator<>() {
BodyLinkedListItem ptr = first; Item ptr = first;
boolean yieldedFirst = false; boolean yieldedFirst = false;
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return ptr != null && (!yieldedFirst || ptr.next() != null); return ptr != null && (!yieldedFirst || ptr.next != null);
} }
@Override @Override
public Body next() { public Body next() {
if (!yieldedFirst) { if (!yieldedFirst) {
yieldedFirst = true; yieldedFirst = true;
return ptr.body(); } else {
ptr = ptr.next;
} }
ptr = ptr.next(); return ptr.body;
return ptr.body();
} }
}; };
} }
}
class BodyLinkedListItem { private static class Item {
private final Body body; private final Body body;
private BodyLinkedListItem prev; private Item prev;
private BodyLinkedListItem next; private Item next;
public BodyLinkedListItem(Body body) { public Item(Body body) {
this.body = body; this.body = body;
this.prev = null; this.prev = null;
this.next = null; this.next = null;
} }
public Body body() { public void setPrev(Item prev) {
return body; this.prev = prev;
} if (prev != null) prev.next = this;
}
public BodyLinkedListItem prev() { public void setNext(Item next) {
return prev; this.next = next;
} if (next != null) next.prev = this;
}
public void setPrev(BodyLinkedListItem prev) {
this.prev = prev;
if (prev != null) prev.next = this;
}
public BodyLinkedListItem next() {
return next;
}
public void setNext(BodyLinkedListItem next) {
this.next = next;
if (next != null) next.prev = this;
} }
} }

View File

@ -1,15 +1,17 @@
import codedraw.CodeDraw; import codedraw.CodeDraw;
import java.util.NoSuchElementException;
/** /**
* A cosmic system that is composed of a central named body (of type 'NamedBodyForcePair') * A cosmic system that is composed of a central named body (of type 'NamedBodyForcePair')
* and an arbitrary number of subsystems (of type 'CosmicSystem') in its orbit. * and an arbitrary number of subsystems (of type 'CosmicSystem') in its orbit.
* This class implements 'CosmicSystem'. * This class implements 'CosmicSystem'.
*/ */
public class HierarchicalSystem implements CosmicSystem { public class HierarchicalSystem implements CosmicSystem, MassiveIterable {
private final NamedBodyForcePair central; private final NamedBodyForcePair central;
private final CosmicSystem[] orbit; private CosmicSystem[] orbit;
private final CosmicSystem[] all; private CosmicSystem[] all;
/** /**
* Initializes this system with a name and a central body. * Initializes this system with a name and a central body.
@ -110,4 +112,69 @@ public class HierarchicalSystem implements CosmicSystem {
return sb.toString(); return sb.toString();
} }
/**
* Puts the system 'cs' at the first place in the orbit of this system.
* Precondition: cs != null
*/
public boolean putFirst(CosmicSystem cs) {
CosmicSystem[] old = orbit;
orbit = new CosmicSystem[old.length + 1];
all = new CosmicSystem[old.length + 2];
orbit[0] = cs;
System.arraycopy(old, 0, orbit, 1, old.length);
all[0] = central;
System.arraycopy(orbit, 0, all, 1, orbit.length);
return true;
}
@Override
public MassiveIterator iterator() {
return new MassiveIterator() {
private int i = 0;
private MassiveIterator cur = null;
@Override
public Massive next() {
if (!hasNext()) throw new NoSuchElementException();
if (cur != null && cur.hasNext()) return cur.next();
while (i < all.length) {
CosmicSystem sys = all[i++];
if (sys instanceof NamedBodyForcePair m) {
return m.getBody();
} else if (sys instanceof HierarchicalSystem hs) {
cur = hs.iterator();
if (cur.hasNext()) {
return cur.next();
}
}
}
return null;
}
@Override
public boolean hasNext() {
if (cur != null && cur.hasNext()) return true;
while (i < all.length) {
CosmicSystem sys = all[i];
if (sys instanceof NamedBodyForcePair) return true;
i++;
if (sys instanceof HierarchicalSystem hs) {
cur = hs.iterator();
if (cur.hasNext()) {
return true;
}
}
}
return false;
}
};
}
} }

73
src/Massive.java Normal file
View File

@ -0,0 +1,73 @@
/**
* Represents a coherent mass with a mass center in 3D space. Has two naming schemes for its
* methods. Please, do not change this interface definition!
*/
public interface Massive extends Drawable {
/**
* Returns the mass.
*/
default double mass() {
return getMass();
}
/**
* Returns the mass center.
*/
default Vector3 massCenter() {
return getMassCenter();
}
/**
* Returns the mass.
*/
default double getMass() {
return mass();
}
/**
* Returns the mass center.
*/
default Vector3 getMassCenter() {
return massCenter();
}
/**
* Returns the approximate radius of 'this', assuming it is a coherent round mass.
* (It is assumed that the radius r is related to the mass m by r = m ^ 0.5,
* where m and r measured in solar units.)
*/
default double getRadius() {
return radius();
}
/**
* Returns the approximate radius of 'this', assuming it is a coherent round mass.
* (It is assumed that the radius r is related to the mass m by r = m ^ 0.5,
* where m and r measured in solar units.)
*/
default double radius() {
return SpaceDraw.massToRadius(mass());
}
/**
* Returns a vector representing the gravitational force exerted by 'b' on this mass.
* The gravitational Force F is calculated by F = G*(m1*m2)/(r*r), with m1 and m2 being the
* masses of the objects interacting, r being the distance between the centers of the masses
* and G being the gravitational constant.
*/
default Vector3 gravitationalForce(Massive b) {
Vector3 direction = b.massCenter().minus(this.massCenter());
double distance = direction.length();
direction.normalize();
double force = Simulation.G * this.mass() * b.mass() / (distance * distance);
return direction.times(force);
}
/**
* Centers this mass at a new position, according to the specified force vector 'force' exerted
* on it, and updates the current velocity vector accordingly.
* (Velocity depends on the mass of 'this', its current velocity and the exerted force.)
*/
void move(Vector3 force);
}

View File

@ -0,0 +1,181 @@
/**
* A hash map that associates a 'Massive'-object with a Vector3 (typically this is the force
* exerted on the object). The number of key-value pairs is not limited.
*/
public class MassiveForceHashMap {
private int size;
private Massive[] keys;
private Vector3[] values;
/**
* Initializes 'this' as an empty map.
*/
public MassiveForceHashMap() {
this(16);
}
public MassiveForceHashMap(int capacity) {
this.size = 0;
this.keys = new Massive[capacity];
this.values = new Vector3[capacity];
}
/**
* Adds a new key-value association to this map. If the key already exists in this map,
* the value is replaced and the old value is returned. Otherwise 'null' is returned.
* Precondition: key != null.
*/
public Vector3 put(Massive key, Vector3 value) {
if (size > keys.length / 2) doubleCapacity();
int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length;
for (int i = 0; i < keys.length; i++) {
int pos = (idx + i) % keys.length;
if (values[pos] == null) {
keys[pos] = key;
values[pos] = value;
size++;
return null;
} else if (keys[pos].equals(key)) {
Vector3 old = values[pos];
values[pos] = value;
return old;
}
}
throw new RuntimeException();
}
private void doubleCapacity() {
Massive[] oldKeys = keys;
Vector3[] oldValues = values;
keys = new Massive[keys.length * 2];
values = new Vector3[values.length * 2];
size = 0;
for (int i = 0; i < oldKeys.length; i++) {
Massive k = oldKeys[i];
Vector3 v = oldValues[i];
if (v != null) put(k, v);
}
}
/**
* Returns the value associated with the specified key, i.e. the method returns the force vector
* associated with the specified key. Returns 'null' if the key is not contained in this map.
* Precondition: key != null.
*/
public Vector3 get(Massive key) {
int pos = find(key);
return (pos == -1) ? null : values[pos];
}
private int find(Massive key) {
int idx = ((key.hashCode() % keys.length) + keys.length) % keys.length;
for (int i = 0; i < keys.length; i++) {
int pos = (idx + i) % keys.length;
if (keys[pos] == null) {
break;
} else if (keys[pos].equals(key)) {
return pos;
}
}
return -1;
}
/**
* Deletes the mapping for the specified key from this map if present.
* Returns the previous value associated with key, or null if there was
* no mapping for key.
* Precondition: key != null
*/
public Vector3 delete(Massive key) {
int pos = find(key);
if (pos == -1) return null;
Vector3 val = values[pos];
values[pos] = null;
return val;
}
/**
* Returns 'true' if this map contains a mapping for the specified key.
*/
public boolean containsKey(Massive key) {
return this.get(key) != null;
}
/**
* Returns a readable representation of this map, with all key-value pairs. Their order is not
* defined.
*/
@Override
public String toString() {
if (size == 0) return "{}";
StringBuilder sb = new StringBuilder("{");
for (int i = 0; i < keys.length; i++) {
Massive k = keys[i];
Vector3 v = values[i];
if (k != null && v != null) {
sb.append("\n ");
sb.append(k);
sb.append(": ");
sb.append(v);
sb.append(",");
}
}
sb.deleteCharAt(sb.length() - 1);
sb.append("\n}");
return sb.toString();
}
/**
* Compares `this` with the specified object for equality. Returns `true` if the specified
* `o` is not `null` and is of type `MassiveForceHashMap` and both `this` and `o` have equal
* key-value pairs, i.e. the number of key-value pairs is the same in both maps and every
* key-value pair in `this` equals one key-value pair in `o`. Two key-value pairs are
* equal if the two keys are equal and the two values are equal. Otherwise, `false` is returned.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof MassiveForceHashMap map) || map.size != size)
return false;
for (int i = 0; i < keys.length; i++) {
Massive k1 = keys[i];
Vector3 v1 = values[i];
if (k1 == null || v1 == null) continue;
Vector3 v2 = map.get(k1);
if (!v1.equals(v2)) return false;
}
return true;
}
/**
* Returns the hashCode of `this`.
*/
@Override
public int hashCode() {
int hash = 0;
for (int i = 0; i < keys.length; i++) {
Massive k = keys[i];
Vector3 v = values[i];
if (k == null || v == null) continue;
hash ^= k.hashCode();
hash ^= v.hashCode();
}
return hash;
}
/**
* Returns a list of all the keys in no specified order.
*/
public MassiveLinkedList keyList() {
MassiveLinkedList list = new MassiveLinkedList();
for (int i = 0; i < keys.length; i++) {
if (keys[i] != null && values[i] != null)
list.addLast(keys[i]);
}
return list;
}
}

View File

@ -0,0 +1,270 @@
import codedraw.CodeDraw;
import java.util.NoSuchElementException;
/**
* A map that associates an object of 'Massive' with a Vector3. The number of key-value pairs
* is not limited.
*/
public class MassiveForceTreeMap implements MassiveSet {
private int size = 0;
private Item root;
/**
* Adds a new key-value association to this map. If the key already exists in this map,
* the value is replaced and the old value is returned. Otherwise 'null' is returned.
* Precondition: key != null.
*/
public Vector3 put(Massive key, Vector3 value) {
if (root == null) {
root = new Item(key, value);
size++;
return null;
}
Item item = root;
while (item != null) {
if (item.key.equals(key)) {
Vector3 old = item.value;
item.value = value;
return old;
} else if (item.key.mass() > key.mass()) {
if (item.left != null) {
item = item.left;
} else {
item.setLeft(new Item(key, value));
size++;
break;
}
} else {
if (item.right != null) {
item = item.right;
} else{
item.setRight(new Item(key, value));
size++;
break;
}
}
}
return null;
}
/**
* Returns the value associated with the specified key, i.e. the method returns the force vector
* associated with the specified key. Returns 'null' if the key is not contained in this map.
* Precondition: key != null.
*/
public Vector3 get(Massive key) {
Item item = root;
while (item != null) {
if (item.key.equals(key)) {
return item.value;
} else if (item.key.mass() > key.mass()) {
item = item.left;
} else {
item = item.right;
}
}
return null;
}
/**
* Returns 'true' if this map contains a mapping for the specified key.
* Precondition: key != null
*/
public boolean containsKey(Massive key) {
Item item = root;
while (item != null) {
if (item.key.equals(key)) {
return true;
} else if (item.key.mass() > key.mass()) {
item = item.left;
} else {
item = item.right;
}
}
return false;
}
private String toString(Item item) {
StringBuilder s = new StringBuilder();
if (item == null) {
return s.toString();
}
s.append(this.toString(item.right));
s.append(String.format("{%s: %s}\n", item.key, item.value));
s.append(this.toString(item.left));
return s.toString();
}
/**
* Returns a readable representation of this map, in which key-value pairs are ordered
* descending according to 'key.getMass()'.
*/
public String toString() {
return (root != null) ? toString(root) : "";
}
/**
* Returns a `MassiveSet` view of the keys contained in this tree map. Changing the
* elements of the returned `MassiveSet` object also affects the keys in this tree map.
*/
public MassiveSet getKeys() {
return this;
}
@Override
public void draw(CodeDraw cd) {
}
@Override
public MassiveIterator iterator() {
return new MassiveIterator() {
private Item last = null;
private Item next = root.getLeftLeaf();
@Override
public Massive next() {
if (!hasNext()) throw new NoSuchElementException();
last = next;
Item newNext = (next.right != null) ? next.right.getLeftLeaf() : next.parent;
while (newNext != null && newNext.right == next) {
next = newNext;
newNext = newNext.parent;
}
next = newNext;
return last.key;
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public void remove() {
if (last == null) throw new IllegalStateException();
removeItem(last);
last = null;
}
};
}
@Override
public boolean contains(Massive element) {
return containsKey(element);
}
@Override
public void remove(Massive element) {
Item item = root;
while (item != null) {
if (item.key.equals(element)) {
removeItem(item);
return;
} else if (item.key.mass() > element.mass()) {
item = item.left;
} else {
item = item.right;
}
}
throw new NoSuchElementException();
}
private void removeItem(Item item) {
size--;
Item newP = null;
if (item.left != null) {
newP = item.left.getRightLeaf();
if (newP != item.left) {
newP.parent.setRight(newP.left);
newP.setLeft(item.left);
}
newP.setRight(item.right);
} else if (item.right != null) {
newP = item.right.getLeftLeaf();
if (newP != item.right) {
newP.parent.setLeft(newP.right);
newP.setRight(item.right);
}
newP.setLeft(item.left);
}
if (newP == null) {
root = null;
return;
}
if (item.parent != null) {
if (item.parent.left == item) {
item.parent.setLeft(newP);
} else {
item.parent.setRight(newP);
}
} else {
root = newP;
newP.parent = null;
}
}
@Override
public void clear() {
size = 0;
root = null;
}
@Override
public int size() {
return size;
}
@Override
public MassiveLinkedList toList() {
MassiveLinkedList list = new MassiveLinkedList();
for (Massive m : this) {
list.addLast(m);
}
return list;
}
private static class Item {
private final Massive key;
private Vector3 value;
private Item parent;
private Item left;
private Item right;
public Item(Massive key, Vector3 value) {
this.key = key;
this.value = value;
}
public void setLeft(Item left) {
this.left = left;
if (left != null) left.parent = this;
}
public void setRight(Item right) {
this.right = right;
if (right != null) right.parent = this;
}
public Item getLeftLeaf() {
Item cur = this;
while (cur.left != null) cur = cur.left;
return cur;
}
public Item getRightLeaf() {
Item cur = this;
while (cur.right != null) cur = cur.right;
return cur;
}
}
}

11
src/MassiveIterable.java Normal file
View File

@ -0,0 +1,11 @@
/**
* Iterable objects with 'Massive' elements.
*/
public interface MassiveIterable extends Iterable<Massive> {
/**
* Returns an iterator over elements of 'Massive'.
*/
@Override
MassiveIterator iterator();
}

20
src/MassiveIterator.java Normal file
View File

@ -0,0 +1,20 @@
import java.util.Iterator;
/**
* An iterator over elements of 'Massive'.
*/
public interface MassiveIterator extends Iterator<Massive> {
/**
* Returns the next element in the iteration.
* (Returns 'null' if the iteration has no more elements.)
*/
@Override
Massive next();
/**
* Returns 'true' if the iteration has more elements.
*/
@Override
boolean hasNext();
}

220
src/MassiveLinkedList.java Normal file
View File

@ -0,0 +1,220 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A list of massive objects implemented as a linked list.
* The number of elements of the list is not limited.
*/
public class MassiveLinkedList implements MassiveIterable {
private int size = 0;
private Item first;
private Item last;
/**
* Initializes 'this' as an empty list.
*/
public MassiveLinkedList() {
first = null;
last = null;
}
/**
* Initializes 'this' as an independent copy of the specified list 'list'.
* Calling methods of this list will not affect the specified list 'list'
* and vice versa.
* Precondition: list != null.
*/
public MassiveLinkedList(BodyLinkedList list) {
this.size = 0;
for (Body b : list) {
this.addLast(b);
}
}
/**
* Inserts the specified element 'body' at the beginning of this list.
*/
public void addFirst(Massive body) {
if (first == null) {
first = new Item(body);
last = first;
} else {
first.setPrev(new Item(body));
first = first.prev;
}
size++;
}
/**
* Appends the specified element 'body' to the end of this list.
*/
public void addLast(Massive body) {
if (last == null) {
last = new Item(body);
first = last;
} else {
last.setNext(new Item(body));
last = last.next;
}
size++;
}
/**
* Returns the last element in this list.
* Returns 'null' if the list is empty.
*/
public Massive getLast() {
return (last != null) ? last.body : null;
}
/**
* Returns the first element in this list.
* Returns 'null' if the list is empty.
*/
public Massive getFirst() {
return (first != null) ? first.body : null;
}
/**
* Retrieves and removes the first element in this list.
* Returns 'null' if the list is empty.
*/
public Massive pollFirst() {
if (first == null) {
return null;
}
Massive m = first.body;
first = first.next;
if (first != null) first.setPrev(null);
size--;
return m;
}
/**
* Retrieves and removes the last element in this list.
* Returns 'null' if the list is empty.
*/
public Massive pollLast() {
if (last == null) {
return null;
}
Massive m = last.body;
last = last.prev;
if (last != null) last.setNext(null);
size--;
return m;
}
/**
* Inserts the specified element at the specified position in this list.
* Precondition: i >= 0 && i <= size().
*/
public void add(int i, Massive m) {
if (first == null || i == 0) {
addFirst(m);
return;
} else if (i == size) {
addLast(m);
return;
}
Item item = first;
for (int j = 0; j < i; j++) {
item = item.next;
}
item.prev.setNext(new Item(m));
item.setPrev(item.prev.next);
size++;
}
/**
* Returns the element at the specified position in this list.
* Precondition: i >= 0 && i < size().
*/
public Massive get(int i) {
Item item;
if (i < size / 2) {
item = first;
for (int j = 0; j < i; j++) {
item = item.next;
}
} else {
item = last;
for (int j = size - 1; j > i; j--) {
item = item.prev;
}
}
return item.body;
}
/**
* Returns the index of the first occurrence of the specified element in this list, or -1 if
* this list does not contain the element.
*/
public int indexOf(Massive m) {
if (first == null) {
return -1;
}
Item item = first;
for (int i = 0; i < size; i++, item = item.next) {
if (item.body.equals(m)) return i;
}
return -1;
}
/**
* Returns the number of elements in this list.
*/
public int size() {
return size;
}
@Override
public MassiveIterator iterator() {
return new MassiveIterator() {
Item ptr = first;
boolean yieldedFirst = false;
@Override
public boolean hasNext() {
return ptr != null && (!yieldedFirst || ptr.next != null);
}
@Override
public Massive next() {
if (!hasNext()) throw new NoSuchElementException();
if (!yieldedFirst) {
yieldedFirst = true;
} else {
ptr = ptr.next;
}
return ptr.body;
}
};
}
private static class Item {
private final Massive body;
private Item prev;
private Item next;
public Item(Massive body) {
this.body = body;
this.prev = null;
this.next = null;
}
public void setPrev(Item prev) {
this.prev = prev;
if (prev != null) prev.next = this;
}
public void setNext(Item next) {
this.next = next;
if (next != null) next.prev = this;
}
}
}

31
src/MassiveSet.java Normal file
View File

@ -0,0 +1,31 @@
/**
* A collection of 'Massive' objects in which there are no duplicates.
*/
public interface MassiveSet extends MassiveIterable, Drawable {
/**
* Returns 'true' if the set has the specified element (i.e., has an element equal to the
* specified element).
*/
boolean contains(Massive element);
/**
* Removes the specified element from the set.
*/
void remove(Massive element);
/**
* Removes all elements from the set.
*/
void clear();
/**
* Returns the number of elements in the set.
*/
int size();
/**
* Returns an object of 'MassiveLinkedList' with all elements of 'this'.
*/
MassiveLinkedList toList();
}

67
src/NamedBody.java Normal file
View File

@ -0,0 +1,67 @@
public class NamedBody extends Body {
private final String name;
/**
* Initializes this with name, mass, current position and movement.
*/
public NamedBody(String name, double mass, Vector3 massCenter, Vector3 currentMovement) {
super(mass, massCenter, currentMovement);
this.name = name;
}
public NamedBody(String name, double mass) {
super(mass);
this.name = name;
}
public NamedBody(String name) {
super();
this.name = name;
}
public NamedBody(String name, Body body) {
super(body);
this.name = name;
}
public NamedBody(NamedBody other) {
super(other);
this.name = other.name;
}
/**
* Returns the name of the body.
*/
public String getName() {
return this.name;
}
/**
* Compares `this` with the specified object. Returns `true` if the specified `o` is not
* `null` and is of type `NamedBody` and both `this` and `o` have equal names.
* Otherwise, `false` is returned.
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof NamedBody b)) return false;
return this.name.equals(b.name);
}
/**
* Returns the hashCode of `this`.
*/
@Override
public int hashCode() {
return this.name.hashCode();
}
/**
* Returns a readable representation including the name of this body.
*/
@Override
public String toString() {
return this.getName();
}
}

View File

@ -6,8 +6,7 @@ import codedraw.CodeDraw;
*/ */
public class NamedBodyForcePair implements CosmicSystem { public class NamedBodyForcePair implements CosmicSystem {
private final String name; private final NamedBody body;
private final Body body;
private final Vector3 force = new Vector3(); private final Vector3 force = new Vector3();
/** /**
@ -15,16 +14,19 @@ public class NamedBodyForcePair implements CosmicSystem {
* is initialized with a zero vector. * is initialized with a zero vector.
*/ */
public NamedBodyForcePair(String name, double mass, Vector3 massCenter, Vector3 currentMovement) { public NamedBodyForcePair(String name, double mass, Vector3 massCenter, Vector3 currentMovement) {
this(name, new Body(mass, massCenter, currentMovement)); this(new NamedBody(name, mass, massCenter, currentMovement));
} }
public NamedBodyForcePair(String name, Body b) { public NamedBodyForcePair(String name, Body body) {
this.body = b; this(new NamedBody(name, body));
this.name = name; }
public NamedBodyForcePair(NamedBody body) {
this.body = body;
} }
public NamedBodyForcePair(NamedBodyForcePair other) { public NamedBodyForcePair(NamedBodyForcePair other) {
this(other.name, new Body(other.body)); this(new NamedBody(other.body));
} }
public Body getBody() { public Body getBody() {
@ -35,7 +37,7 @@ public class NamedBodyForcePair implements CosmicSystem {
* Returns the name of the body. * Returns the name of the body.
*/ */
public String getName() { public String getName() {
return name; return body.getName();
} }
@Override @Override

127
src/ReadDataUtil.java Normal file
View File

@ -0,0 +1,127 @@
import java.io.*;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ReadDataUtil {
private static final Pattern LINE_FORMAT = Pattern.compile("^\\d+(\\.\\d+)?, *[A-Za-z \\d:.-]+(, *[-+]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?){6}, *$");
private static final Pattern DATE_COLUMN_FORMAT = Pattern.compile("^A\\.D\\. (?<year>\\d{4})-(?<month>[A-Z][a-z]{2})-(?<day>[0-3]\\d) \\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$");
private static final Pattern DATE_FORMAT_YYYY_MMM_DD = Pattern.compile("^(?<year>\\d{4})-(?<month>[A-Z][a-z]{2})-(?<day>[0-3]\\d)$");
/**
* Reads the position and velocity vector on the specified 'day' from the file with the
* specified 'path', and sets position and current velocity of 'b' accordingly. If
* successful the method returns 'true'. If the specified 'day' was not found in the file,
* 'b' is unchanged and the method returns 'false'.
* The file format is validated before reading the state.
* Lines before the line "$$SOE" and after the line "$$EOE" the are ignored. Each line of the
* file between the line "$$SOE" and the line "$$EOE" is required to have the following format:
* JDTDB, TIME, X, Y, Z, VX, VY, VZ
* where JDTDB is interpretable as a 'double' value, TIME is a string and X, Y, Z, VX, VY and
* VZ are interpretable as 'double' values. JDTDB can be ignored. The character ',' must only
* be used as field separator. If the file is not found, an exception of the class
* 'StateFileNotFoundException' is thrown. If it does not comply with the format described
* above, the method throws an exception of the class 'StateFileFormatException'. Both
* exceptions are subtypes of 'IOException'.
* Precondition: b != null, path != null, day != null and has the format YYYY-MM-DD.
*/
public static boolean readConfiguration(NamedBody b, String path, String day) throws IOException {
State state = State.Pre;
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(path))) {
Scanner lines = new Scanner(in);
long lineNum = 0;
while (lines.hasNextLine() && state != State.Post) {
lineNum++;
String line = lines.nextLine();
State nextState = state.next(line);
if (state == State.In && nextState == State.In) {
Matcher m = LINE_FORMAT.matcher(line);
if (!m.matches()) {
throw new StateFileFormatException(path, lineNum);
}
String[] rows = line.split(", *");
String date;
try {
date = convertDateColumn(rows[1]);
} catch (IllegalArgumentException e) {
throw new StateFileFormatException(path, lineNum);
}
if (date.equals(day)) {
try {
double x = Double.parseDouble(rows[2]); // [km]
double y = Double.parseDouble(rows[3]); // [km]
double z = Double.parseDouble(rows[4]); // [km]
double vx = Double.parseDouble(rows[5]); // [km/s]
double vy = Double.parseDouble(rows[6]); // [km/s]
double vz = Double.parseDouble(rows[7]); // [km/s]
b.setState(new Vector3(x * 1000, y * 1000, z * 1000), new Vector3(vx * 1000, vy * 1000, vz * 1000));
} catch (NumberFormatException e) {
throw new StateFileFormatException(path, lineNum);
}
return true;
}
}
state = nextState;
}
} catch (IOException e) {
if (e instanceof FileNotFoundException) {
throw new StateFileNotFoundException(path);
} else {
throw e;
}
}
return false;
}
private static String convertDateColumn(String column) {
Matcher m = DATE_COLUMN_FORMAT.matcher(column);
if (!m.matches()) {
throw new IllegalArgumentException();
}
return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day");
}
public static String convertDate(String date) {
Matcher m = DATE_FORMAT_YYYY_MMM_DD.matcher(date);
if (!m.matches()) {
throw new IllegalArgumentException();
}
return m.group("year") + "-" + convertMonth(m.group("month")) + "-" + m.group("day");
}
private static String convertMonth(String month) {
return switch (month) {
case "Jan" -> "01";
case "Feb" -> "02";
case "Mar" -> "03";
case "Apr" -> "04";
case "May" -> "05";
case "Jun" -> "06";
case "Jul" -> "07";
case "Aug" -> "08";
case "Sep" -> "09";
case "Oct" -> "10";
case "Nov" -> "11";
case "Dec" -> "12";
default -> throw new IllegalArgumentException();
};
}
private enum State {
Pre, In, Post;
public State next(String line) {
switch (this) {
case Pre: if (line.equals("$$SOE")) return In; break;
case In: if (line.equals("$$EOE")) return Post; break;
case Post: break;
}
return this;
}
}
}

View File

@ -36,9 +36,7 @@ public class Simulation4 {
while (true) { while (true) {
seconds++; seconds++;
for (Body b : sol.getBodies()) { sol.addForceTo(sol);
sol.addForceFrom(b);
}
sol.update(); sol.update();
if ((seconds % 3600) == 0) { if ((seconds % 3600) == 0) {

113
src/Simulation5.java Normal file
View File

@ -0,0 +1,113 @@
import codedraw.CodeDraw;
import java.awt.*;
import java.util.Random;
/**
* Simulates the formation of a massive solar system.
*/
public class Simulation5 {
// gravitational constant
public static final double G = 6.6743e-11;
// one astronomical unit (AU) is the average distance of earth to the sun.
public static final double AU = 150e9; // meters
// one light year
public static final double LY = 9.461e15; // meters
// some further constants needed in the simulation
public static final double SUN_MASS = 1.989e30; // kilograms
public static final double SUN_RADIUS = 696340e3; // meters
public static final double EARTH_MASS = 5.972e24; // kilograms
public static final double EARTH_RADIUS = 6371e3; // meters
// set some system parameters
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
public static final int NUMBER_OF_BODIES = 22;
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
// all quantities are based on units of kilogram respectively second and meter.
/**
* The main simulation method using instances of other classes.
*/
public static void main(String[] args) {
// simulation
CodeDraw cd = new CodeDraw();
// create solar system with 12 bodies
NamedBody sun = new NamedBody(SolSystem4.SUN_NAMED);
NamedBody earth = new NamedBody(SolSystem4.EARTH_NAMED);
NamedBody moon = new NamedBody(SolSystem4.MOON_NAMED);
NamedBody mars = new NamedBody(SolSystem4.MARS_NAMED);
NamedBody deimos = new NamedBody(SolSystem4.DEIMOS_NAMED);
NamedBody phobos = new NamedBody(SolSystem4.PHOBOS_NAMED);
NamedBody mercury = new NamedBody(SolSystem4.MERCURY_NAMED);
NamedBody venus = new NamedBody(SolSystem4.VENUS_NAMED);
NamedBody vesta = new NamedBody(SolSystem4.VESTA_NAMED);
NamedBody pallas = new NamedBody(SolSystem4.PALLAS_NAMED);
NamedBody hygiea = new NamedBody(SolSystem4.HYGIEA_NAMED);
NamedBody ceres = new NamedBody(SolSystem4.CERES_NAMED);
// create some additional bodies
Body[] bodies = new Body[NUMBER_OF_BODIES];
Random random = new Random(2022);
for (int i = 0; i < bodies.length; i++) {
bodies[i] = new Body(
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length,
new Vector3(0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU),
new Vector3(0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3)
);
}
MassiveForceHashMap forceOnBody = new MassiveForceHashMap();
forceOnBody.put(sun, new Vector3());
forceOnBody.put(earth, new Vector3());
forceOnBody.put(moon, new Vector3());
forceOnBody.put(mars, new Vector3());
forceOnBody.put(deimos, new Vector3());
forceOnBody.put(phobos, new Vector3());
forceOnBody.put(mercury, new Vector3());
forceOnBody.put(venus, new Vector3());
forceOnBody.put(vesta, new Vector3());
forceOnBody.put(pallas, new Vector3());
forceOnBody.put(hygiea, new Vector3());
forceOnBody.put(ceres, new Vector3());
for (Body b : bodies) {
forceOnBody.put(b, new Vector3());
}
long seconds = 0;
while (true) {
seconds++;
for (Massive b1 : forceOnBody.keyList()) {
Vector3 force = new Vector3();
for (Massive b2 : forceOnBody.keyList()) {
if (b1 != b2) {
force = force.plus(b1.gravitationalForce(b2));
}
}
forceOnBody.put(b1, force);
}
for (Massive body : forceOnBody.keyList()) {
body.move(forceOnBody.get(body));
}
if ((seconds % 3600) == 0) {
cd.clear(Color.BLACK);
for (Massive body : forceOnBody.keyList()) {
body.draw(cd);
}
cd.show();
}
}
}
}

113
src/Simulation6.java Normal file
View File

@ -0,0 +1,113 @@
import codedraw.CodeDraw;
import java.awt.*;
import java.util.Random;
/**
* Simulates the formation of a massive solar system.
*/
public class Simulation6 {
// gravitational constant
public static final double G = 6.6743e-11;
// one astronomical unit (AU) is the average distance of earth to the sun.
public static final double AU = 150e9; // meters
// one light year
public static final double LY = 9.461e15; // meters
// some further constants needed in the simulation
public static final double SUN_MASS = 1.989e30; // kilograms
public static final double SUN_RADIUS = 696340e3; // meters
public static final double EARTH_MASS = 5.972e24; // kilograms
public static final double EARTH_RADIUS = 6371e3; // meters
// set some system parameters
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
public static final int NUMBER_OF_BODIES = 22;
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
// all quantities are based on units of kilogram respectively second and meter.
/**
* The main simulation method using instances of other classes.
*/
public static void main(String[] args) {
// simulation
CodeDraw cd = new CodeDraw();
// create solar system with 12 bodies
NamedBody sun = new NamedBody(SolSystem4.SUN_NAMED);
NamedBody earth = new NamedBody(SolSystem4.EARTH_NAMED);
NamedBody moon = new NamedBody(SolSystem4.MOON_NAMED);
NamedBody mars = new NamedBody(SolSystem4.MARS_NAMED);
NamedBody deimos = new NamedBody(SolSystem4.DEIMOS_NAMED);
NamedBody phobos = new NamedBody(SolSystem4.PHOBOS_NAMED);
NamedBody mercury = new NamedBody(SolSystem4.MERCURY_NAMED);
NamedBody venus = new NamedBody(SolSystem4.VENUS_NAMED);
NamedBody vesta = new NamedBody(SolSystem4.VESTA_NAMED);
NamedBody pallas = new NamedBody(SolSystem4.PALLAS_NAMED);
NamedBody hygiea = new NamedBody(SolSystem4.HYGIEA_NAMED);
NamedBody ceres = new NamedBody(SolSystem4.CERES_NAMED);
// create some additional bodies
Body[] bodies = new Body[NUMBER_OF_BODIES];
Random random = new Random(2022);
for (int i = 0; i < bodies.length; i++) {
bodies[i] = new Body(
Math.abs(random.nextGaussian()) * OVERALL_SYSTEM_MASS / bodies.length,
new Vector3(0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU, 0.2 * random.nextGaussian() * AU),
new Vector3(0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3, 0 + random.nextGaussian() * 5e3)
);
}
MassiveForceTreeMap forceOnBody = new MassiveForceTreeMap();
forceOnBody.put(sun, new Vector3());
forceOnBody.put(earth, new Vector3());
forceOnBody.put(moon, new Vector3());
forceOnBody.put(mars, new Vector3());
forceOnBody.put(deimos, new Vector3());
forceOnBody.put(phobos, new Vector3());
forceOnBody.put(mercury, new Vector3());
forceOnBody.put(venus, new Vector3());
forceOnBody.put(vesta, new Vector3());
forceOnBody.put(pallas, new Vector3());
forceOnBody.put(hygiea, new Vector3());
forceOnBody.put(ceres, new Vector3());
for (Body b : bodies) {
forceOnBody.put(b, new Vector3());
}
long seconds = 0;
while (true) {
seconds++;
for (Massive b1 : forceOnBody.getKeys()) {
Vector3 force = new Vector3();
for (Massive b2 : forceOnBody.getKeys()) {
if (b1 != b2) {
force = force.plus(b1.gravitationalForce(b2));
}
}
forceOnBody.put(b1, force);
}
for (Massive body : forceOnBody.getKeys()) {
body.move(forceOnBody.get(body));
}
if ((seconds % 3600) == 0) {
cd.clear(Color.BLACK);
for (Massive body : forceOnBody.getKeys()) {
body.draw(cd);
}
cd.show();
}
}
}
}

120
src/Simulation8.java Normal file
View File

@ -0,0 +1,120 @@
import codedraw.CodeDraw;
import java.awt.*;
import java.io.IOException;
/**
* Simulates the solar system.
*/
public class Simulation8 {
// gravitational constant
public static final double G = 6.6743e-11;
// one astronomical unit (AU) is the average distance of earth to the sun.
public static final double AU = 150e9; // meters
// set some system parameters
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
// all quantities are based on units of kilogram respectively second and meter.
// The main simulation method using instances of other classes.
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Error: wrong number of arguments.");
System.exit(1);
}
String statePath = args[0];
String date;
try {
date = ReadDataUtil.convertDate(args[1]);
} catch (IllegalArgumentException e) {
System.err.println("Error: State has wrong format (requires YYYY-MMM-DD), aborting.");
System.exit(2);
return;
}
// simulation
CodeDraw cd = new CodeDraw();
// create solar system with 13 bodies
MassiveForceTreeMap forceOnBody = new MassiveForceTreeMap();
forceOnBody.put(new NamedBody("Oumuamua", 8e6), new Vector3());
forceOnBody.put(new NamedBody("Earth", 5.972E24), new Vector3());
forceOnBody.put(new NamedBody("Moon", 7.349E22), new Vector3());
forceOnBody.put(new NamedBody("Mars", 6.41712E23), new Vector3());
forceOnBody.put(new NamedBody("Deimos", 1.8E20), new Vector3());
forceOnBody.put(new NamedBody("Phobos", 1.08E20), new Vector3());
forceOnBody.put(new NamedBody("Mercury", 3.301E23), new Vector3());
forceOnBody.put(new NamedBody("Venus", 4.86747E24), new Vector3());
forceOnBody.put(new NamedBody("Vesta", 2.5908E20), new Vector3());
forceOnBody.put(new NamedBody("Pallas", 2.14E20), new Vector3());
forceOnBody.put(new NamedBody("Hygiea", 8.32E19), new Vector3());
forceOnBody.put(new NamedBody("Ceres", 9.394E20), new Vector3());
MassiveIterator iter = forceOnBody.getKeys().iterator();
while (iter.hasNext()) {
Massive a = iter.next();
if (a instanceof NamedBody b) {
boolean remove = false;
try {
boolean found = ReadDataUtil.readConfiguration(b, statePath + "/" + b.getName() + ".txt", date);
if (!found) {
System.err.println("Warning: State not available for " + b.getName() + ".");
remove = true;
}
} catch (IOException e) {
if (e instanceof StateFileNotFoundException notFound) {
System.err.println("Warning: " + notFound.getMessage());
} else if (e instanceof StateFileFormatException format) {
System.err.println("Warning: " + format.getMessage());
} else {
System.err.println("Error: " + e.getMessage());
System.exit(3);
}
remove = true;
}
if (remove) {
System.err.println("Running simulation without " + b.getName());
iter.remove();
}
}
}
// add sun after states have been read from files.
forceOnBody.put(new NamedBody("Sun", 1.989E30), new Vector3());
System.out.println("Starting simulation");
long seconds = 0;
while (true) {
seconds++;
for (Massive b1 : forceOnBody.getKeys()) {
Vector3 force = new Vector3();
for (Massive b2 : forceOnBody.getKeys()) {
if (b1 != b2) {
force = force.plus(b1.gravitationalForce(b2));
}
}
forceOnBody.put(b1, force);
}
for (Massive body : forceOnBody.getKeys()) {
body.move(forceOnBody.get(body));
}
if ((seconds % 3600) == 0) {
cd.clear(Color.BLACK);
for (Massive body : forceOnBody.getKeys()) {
body.draw(cd);
}
cd.show();
}
}
}
}

122
src/Simulation9.java Normal file
View File

@ -0,0 +1,122 @@
import codedraw.CodeDraw;
import java.awt.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
/**
* Simulates the solar system.
*/
public class Simulation9 {
// gravitational constant
public static final double G = 6.6743e-11;
// one astronomical unit (AU) is the average distance of earth to the sun.
public static final double AU = 150e9; // meters
// set some system parameters
public static final double SECTION_SIZE = 10 * AU; // the size of the square region in space
// all quantities are based on units of kilogram respectively second and meter.
// The main simulation method using instances of other classes.
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Error: wrong number of arguments.");
System.exit(1);
}
String statePath = args[0];
String date;
try {
date = ReadDataUtil.convertDate(args[1]);
} catch (IllegalArgumentException e) {
System.err.println("Error: State has wrong format (requires YYYY-MMM-DD), aborting.");
System.exit(2);
return;
}
// simulation
CodeDraw cd = new CodeDraw();
// create solar system with 13 bodies
HashMap<Massive, Vector3> forceOnBody = new HashMap<>();
forceOnBody.put(new NamedBody("Oumuamua", 8e6), new Vector3());
forceOnBody.put(new NamedBody("Earth", 5.972E24), new Vector3());
forceOnBody.put(new NamedBody("Moon", 7.349E22), new Vector3());
forceOnBody.put(new NamedBody("Mars", 6.41712E23), new Vector3());
forceOnBody.put(new NamedBody("Deimos", 1.8E20), new Vector3());
forceOnBody.put(new NamedBody("Phobos", 1.08E20), new Vector3());
forceOnBody.put(new NamedBody("Mercury", 3.301E23), new Vector3());
forceOnBody.put(new NamedBody("Venus", 4.86747E24), new Vector3());
forceOnBody.put(new NamedBody("Vesta", 2.5908E20), new Vector3());
forceOnBody.put(new NamedBody("Pallas", 2.14E20), new Vector3());
forceOnBody.put(new NamedBody("Hygiea", 8.32E19), new Vector3());
forceOnBody.put(new NamedBody("Ceres", 9.394E20), new Vector3());
Iterator<Massive> iter = forceOnBody.keySet().iterator();
while (iter.hasNext()) {
Massive a = iter.next();
if (a instanceof NamedBody b) {
boolean remove = false;
try {
boolean found = ReadDataUtil.readConfiguration(b, statePath + "/" + b.getName() + ".txt", date);
if (!found) {
System.err.println("Warning: State not available for " + b.getName() + ".");
remove = true;
}
} catch (IOException e) {
if (e instanceof StateFileNotFoundException notFound) {
System.err.println("Warning: " + notFound.getMessage());
} else if (e instanceof StateFileFormatException format) {
System.err.println("Warning: " + format.getMessage());
} else {
System.err.println("Error: " + e.getMessage());
System.exit(3);
}
remove = true;
}
if (remove) {
System.err.println("Running simulation without " + b.getName());
iter.remove();
}
}
}
// add sun after states have been read from files.
forceOnBody.put(new NamedBody("Sun", 1.989E30), new Vector3());
System.out.println("Starting simulation");
long seconds = 0;
while (true) {
seconds++;
for (Massive b1 : forceOnBody.keySet()) {
Vector3 force = new Vector3();
for (Massive b2 : forceOnBody.keySet()) {
if (b1 != b2) {
force = force.plus(b1.gravitationalForce(b2));
}
}
forceOnBody.put(b1, force);
}
for (Massive body : forceOnBody.keySet()) {
body.move(forceOnBody.get(body));
}
if ((seconds % 3600) == 0) {
cd.clear(Color.BLACK);
for (Massive body : forceOnBody.keySet()) {
body.draw(cd);
}
cd.show();
}
}
}
}

View File

@ -12,16 +12,16 @@ public class SolSystem4 {
public static final Body HYGIEA = new Body(8.32E19, new Vector3(-3.983943433707043E11, 2.325833000024021E11, -2.233667695713672E10), new Vector3(-6931.864585548552, -15686.8108598699, -690.5791992347208)); public static final Body HYGIEA = new Body(8.32E19, new Vector3(-3.983943433707043E11, 2.325833000024021E11, -2.233667695713672E10), new Vector3(-6931.864585548552, -15686.8108598699, -690.5791992347208));
public static final Body CERES = new Body(9.394E20, new Vector3(3.781372641419032E11, 1.96718960466285E11, -6.366459168068592E10), new Vector3(-8555.324226752316, 14718.33755980907, 2040.230135060142)); public static final Body CERES = new Body(9.394E20, new Vector3(3.781372641419032E11, 1.96718960466285E11, -6.366459168068592E10), new Vector3(-8555.324226752316, 14718.33755980907, 2040.230135060142));
public static final NamedBodyForcePair SUN_NAMED = new NamedBodyForcePair("Sun", SUN); public static final NamedBody SUN_NAMED = new NamedBody("Sun", SUN);
public static final NamedBodyForcePair EARTH_NAMED = new NamedBodyForcePair("Earth", EARTH); public static final NamedBody EARTH_NAMED = new NamedBody("Earth", EARTH);
public static final NamedBodyForcePair MOON_NAMED = new NamedBodyForcePair("Moon", MOON); public static final NamedBody MOON_NAMED = new NamedBody("Moon", MOON);
public static final NamedBodyForcePair MARS_NAMED = new NamedBodyForcePair("Mars", MARS); public static final NamedBody MARS_NAMED = new NamedBody("Mars", MARS);
public static final NamedBodyForcePair DEIMOS_NAMED = new NamedBodyForcePair("Deimos", DEIMOS); public static final NamedBody DEIMOS_NAMED = new NamedBody("Deimos", DEIMOS);
public static final NamedBodyForcePair PHOBOS_NAMED = new NamedBodyForcePair("Phobos", PHOBOS); public static final NamedBody PHOBOS_NAMED = new NamedBody("Phobos", PHOBOS);
public static final NamedBodyForcePair MERCURY_NAMED = new NamedBodyForcePair("Mercury", MERCURY); public static final NamedBody MERCURY_NAMED = new NamedBody("Mercury", MERCURY);
public static final NamedBodyForcePair VENUS_NAMED = new NamedBodyForcePair("Venus", VENUS); public static final NamedBody VENUS_NAMED = new NamedBody("Venus", VENUS);
public static final NamedBodyForcePair VESTA_NAMED = new NamedBodyForcePair("Vesta", VESTA); public static final NamedBody VESTA_NAMED = new NamedBody("Vesta", VESTA);
public static final NamedBodyForcePair PALLAS_NAMED = new NamedBodyForcePair("Pallas", PALLAS); public static final NamedBody PALLAS_NAMED = new NamedBody("Pallas", PALLAS);
public static final NamedBodyForcePair HYGIEA_NAMED = new NamedBodyForcePair("Hygiea", HYGIEA); public static final NamedBody HYGIEA_NAMED = new NamedBody("Hygiea", HYGIEA);
public static final NamedBodyForcePair CERES_NAMED = new NamedBodyForcePair("Ceres", CERES); public static final NamedBody CERES_NAMED = new NamedBody("Ceres", CERES);
} }

View File

@ -0,0 +1,20 @@
import java.io.IOException;
public class StateFileFormatException extends IOException {
private final String fileName;
private final long lineNum;
public StateFileFormatException(String fileName, long lineNum) {
super("File " + fileName + " has illegal format (line " + lineNum + ")");
this.fileName = fileName;
this.lineNum = lineNum;
}
public String getFileName() {
return this.fileName;
}
public long getLineNum() {
return this.lineNum;
}
}

View File

@ -0,0 +1,14 @@
import java.io.IOException;
public class StateFileNotFoundException extends IOException {
private final String fileName;
public StateFileNotFoundException(String fileName) {
super("File " + fileName + " not found.");
this.fileName = fileName;
}
public String getFileName() {
return this.fileName;
}
}

1
states/Ceres.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Deimos.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Earth.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Hygiea.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Mars.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Mercury.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Moon.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Oumuamua.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Pallas.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Phobos.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Venus.txt Normal file

File diff suppressed because one or more lines are too long

1
states/Vesta.txt Normal file

File diff suppressed because one or more lines are too long