Skip to content
Snippets Groups Projects
Commit dd60cab7 authored by Kerschbaumer, David's avatar Kerschbaumer, David
Browse files

init + assignments from 2020 and 2021

parents
No related branches found
No related tags found
No related merge requests found
# Assignment 1 : Brutto-Netto Rechner
## Lernziel
Datentypen, Operatoren, Casts, Kontrollstrukturen, Ein-/Ausgabe, Funktionen
## Aufgabenstellung
Schreiben Sie ein Programm, das ausgehend von einem Bruttoentgelt
* den Sozialversicherungsbeitrag,
* die Lohnsteuer und
* das Nettoentgelt
ausrechnet.
Aufgrund vieler Details in der Berechnung des Nettoentgelts in Österreich (viele Leistungsklassen, Absetzbeträge, Werbungskosten, rückwirkende Steuernovelle, etc.), wird in diesem Übungsbeispiel ein vereinfachter Brutto-Netto-Rechner erstellt. Interessierte können sich gerne [eine Zusammenfassung über die tatsächliche Berechnung des Nettoentgelts in Österreich](https://www.lernenwillmehr.at/wp-content/uploads/2020/01/Lernen-Will-Mehr_aktuelles-Personalverrechnung_2020.pdf) ansehen – für dieses Assignment ist dieses Detailwissen aber nicht erforderlich.
In diesem Assignment wird das Nettoentgelt mit der Formel
```math
\text{Nettoentgelt} = \text{Bruttoentgelt} - \text{Sozialversicherungsbeitrag} - \text{Lohnsteuer}
```
berechnet.
Wie Sozialversicherungsbeitrag und Lohnsteuer zu berechnen sind, ist in den Abschnitten [Sozialversicherungsbeitrag](#berechnung-des-sozialversicherungsbeitrags-sv) und [Lohnsteuer](#berechnung-der-lohnsteuer-lst) beschrieben. Die folgenden Abschnitte zeigen auch, wie die
Ausgaben des Programms auszusehen haben.
---
**ACHTUNG!**
Bitte befolgen Sie die Anweisungen zur Ausgabe *genau*, da selbst bei kleinen Fehlern (z.B. ein Leerzeichen
zu wenig oder zu viel) die Test Cases fehlschlagen! Das wäre sehr schade und deshalb stellen wir Ihnen in
diesem Repository auch ein Testsystem zur Verfügung. Nutzen Sie es unbedingt! Es gibt Ihnen wertvolle
Hinweise auf Fehler in Ihrem Programm.
---
### Eingabe des Bruttoentgelts
Im ersten Schritt wird die/der Benutzer\*in zu einer Eingabe aufgefordert. Eine valide Eingabe ist eine Ganzzahl größer als 0 und ≤ 5 Millionen. Diese Ganzzahl gibt das Bruttoentgelt an.
```
Ihr monatliches Bruttoeinkommen: <wert>
```
Dabei wird `<wert>` durch die (mit Enter abgeschlossene) Benutzereingabe ersetzt. Die spitzen Klammern sind *nicht* Teil der Benutzereingabe. Unsere [Beispielausgabe](#beispielausgabe) verdeutlicht, wie die Ausgabe auszusehen hat.
Sollte die Eingabe nicht valide sein, erscheint folgende Fehlermeldung:
```
Invalide Eingabe!\n
```
Die hier abgebildeten Zeichen `\` und `n` sind nicht als einzelne Zeichen auszugeben, sondern sind als Newline-Character (`\n`) zu verstehen.
Nach der Fehlermeldung startet das Program von vorne, das heißt es verlangt wieder nach einer Eingabe (so lange, bis die Eingabe valide ist).
(Tipp: Bei den Test Cases wird nur auf einzelne Ganzzahlen getestet, Sie müssen sich also keine Gedanken darüber machen, wie das Programm mit anderen Eingaben (z.B. Buchstaben) umgehen soll.)
### Berechnung des Sozialversicherungsbeitrags (SV)
#### Sozialversicherungsbeitrag bei einem Bruttoentgelt bis (inkl.) 5370 €
Der Sozialversicherungsbeitrag lässt sich aus der Beitragsgrundlage (=monatliches Bruttoentgelt) errechnen. Bis zu einer Beitragsgrundlage von 5370 € lautet die Formel dafür
```math
\text{Sozialversicherungsbeitrag} = \text{Beitragsgrundlage} \cdot \frac{\text{Beitragssatz}}{100},
```
wobei der (von der Beitragsgrundlage abhängige) Beitragssatz der folgenden Tabelle entnommen werden kann.
| Beitragsgrundlage € | Beitragssatz % |
| --------- | :------: |
| 1 - 460 | 0 |
| 461 - 1733 | 15 |
| 1734 - 1891 | 16 |
| 1892 - 2049 | 17 |
| 2050 - 5370 | 18 |
Die Geringfügigkeitsgrenze liegt demnach bei 460 €. Das heißt, wer 460 € oder weniger verdient, zahlt keine Sozialversicherung.
#### Sozialversicherungsbeitragbeitrag bei einem Bruttoentgelt über 5370 €
Die Höchstbeitragsgrundlage liegt bei 5370 €. Das heißt, wer mehr verdient, zahlt gleich viel wie jemand, der 5370 € verdient.
### Berechnung der Lohnsteuer (LSt)
Eigentlich werden im österreichischen Einkommensteuergesetz (EStG) Lohnsteuerklassen (Tarifstufen) in Abhängigkeit vom Jahreseinkommen definiert. Der Einfachheit halber rechnen wir aber mit monatlichen Bezügen. Die Beitragsgrundlage für die LSt ist das monatliche Bruttoentgelt **nach Abzug der Sozialversicherung**. (Das bedeutet auch, dass sich die Beitragsgrundlage für die SV und jene für die LSt unterscheiden können!)
Auch bei der LSt gibt es eine Tabelle, mit deren Hilfe der zu zahlende Betrag ermittelt werden kann. Die Berechnung erfolgt aber etwas anders als bei der SV.
| Beitragsgrundlage € | Beitragssatz % |
| --------- | :------: |
| 0,01 - 1000,00 | 0 |
| 1000,01 - 1500,00 | 20 |
| 1500,01 - 2500,00 | 30 |
| 2500,01 - 5000,00 | 40 |
| \> 5000,00 | 50 |
Im Gegensatz zur SV wird bei der LSt nicht die gesamte Beitragsgrundlage mit dem höchsten erreichten Beitragssatz multipliziert. Es werden stattdessen die einzelnen Teile der Beitragsgrundlage mit dem jeweiligen Beitragssatz multipliziert. Für die ersten 1000€ werden 0% berechnet; für die nächsten 500€ sind es 20%; für die nächsten 1000€ 30% usw. (siehe Tabelle oben). Alle so ermittelten Werte werden addiert.
Die Formel für die Berechnung der LSt lautet:
```math
\text{Lohnsteuer} = \text{Teil 1 der Beitragsgrundlage} \cdot \frac{\text{Beitragssatz}_1}{100} \\
+ \text{Teil 2 der Beitragsgrundlage} \cdot \frac{\text{Beitragssatz}_2}{100} \\
+ ...
```
---
**Beispiel:**
Die Beitragsgrundlage für die LSt sei 2605 €. Dann beträgt die LSt
$`1000 \cdot \frac{0}{100} + 500 \cdot \frac{20}{100} + 1000 \cdot \frac{30}{100} + 105 \cdot \frac{40}{100}`$ €.
---
Der gezeigte Rechenweg ergibt lediglich die *vorläufige* LSt. Die tatsächliche LSt kann von der vorläufigen LSt abweichen, wenn die/der Benutzer\*in Kinder hat.
Vor der Berechnung der tatsächlichen Lohnsteuer wird die/der Benutzer\*in gefragt, ob dies der Fall ist.
```
Kinder im Haushalt?: <Jj/Nn>
```
Dabei wird `<Jj/Nn>` durch die (mit Enter abgeschlossene) Benutzereingabe ersetzt. Sowohl
Groß- ("J"/"N") als auch Kleinschreibung ("j"/"n") sind erlaubt.
Sollte die Eingabe kein erlaubter Wert sein, erscheint folgende Fehlermeldung:
```
Invalide Eingabe!\n
```
Nach der Fehlermeldung fährt das Programm wieder mit der Frage nach den Kindern fort.
(Tipp: Bei den Test Cases wird auf einzelne alphanumerische Zeichen getestet.)
Wenn die/der Benutzer\*in steuerpflichtig ist und Kinder hat, sinkt die Lohnsteuer um bis zu 100 € (sie kann jedoch nicht negativ werden). Genauer gesagt,
- ist die vorläufige LSt ohne Kinder $`\geq 100`$ €, so ist die tatsächliche LSt mit Kindern um 100 € geringer und
- ist die vorläufige LSt ohne Kinder $`< 100`$ €, so ist die tatsächliche LSt mit Kindern gleich 0.
### Ausgabe
Nachdem alle oben beschriebenen Eingaben getätigt wurden, gibt das Programm eine
Übersicht über die Berechnungen aus.
```
Brutto:\t\t<wert_br>\n
SV:\t\t<wert_sv>\n
LSt:\t\t<wert_ls>\n
Netto:\t\t<wert_ne>\n
```
Dabei werden die Platzhalter `<wert_XX>` durch die entsprechenden berechneten Werte ersetzt. Beachten Sie bitte folgende Hinweise:
* Alle Beträge werden auf 2 Nachkommastellen genau angezeigt.
* Alle Beträge haben eine Feldbreite von 12.
* `<wert_sv>` und `<wert_ls>` werden mit einem Vorzeichen angezeigt.
* Beachten Sie die Tabulatorzeichen `\t`.
* Es werden keine Leerzeichen oder das Minuszeichen benutzt.
Hilfestellung zu Formatierungsoptionen finden Sie unter [Wikibooks](https://de.wikibooks.org/wiki/C-Programmierung:_Einfache_Ein-_und_Ausgabe) und [printf-Cheatsheet](https://kuepper.userweb.mwn.de/informatik/printf.pdf).
## Beispielberechnung
```
Brutto = 1880 €
SV 16% = -300,80 €
Brutto-SV = 1579,20 €
LS (1500-1000)*20% +
(1579,20-1500)*30% = 123,76 €
Kind J LS-100€ = -23,76 €
Netto = 1555,44 €
```
## Beispielausgabe
```
Ihr monatliches Bruttoeinkommen: 2400
Kinder im Haushalt?: m
Invalide Eingabe!
Kinder im Haushalt?: n
Brutto: 2400.00
SV: -432.00
LSt: -240.40
Netto: 1727.60
```
## Spezifikation
* Die Eingabe des Bruttoentgelts muss im Datentyp Integer (int) erfolgen.
* abzugebende Datei: ass1.c
* Abgabe bis *spätestens*: 07.11.2020 23:59 (in Österreich gültige Zeit)
---
# A2: Playfair
## Lernziel
Funktionen, Parameterübergabe, Pointer, Arrays, Strings, ASCII
## Aufgabenstellung
Erstellen Sie ein Programm, welches eine modifizierte Version der [Playfair-Chiffre](https://de.wikipedia.org/wiki/Playfair) implementiert. Nach Eingabe eines Schlüssels (A-Z und Leerzeichen, max. 25 Zeichen) kann das Programm eine Zeichenfolge (A-Z und Leerzeichen, maximal 50 Zeichen) ver- und entschlüsseln.
### Vorbereitung (=Bereinigung) des Schlüssels
Ein gültiger Schlüssel darf nur die Buchstaben A-Z (Groß-/Kleinschreibung egal, mindestens 1 Buchstabe) und Leerzeichen enthalten und maximal 25 Zeichen (inklusive Leerzeichen) lang sein. Für die Anwendung des Schlüssels muss dieser zuerst bereinigt werden. Dieser Vorgang besteht aus den folgenden Schritten:
* Leerzeichen werden entfernt.
* Alle Zeichen werden in Großbuchstaben umgewandelt.
* W wird mit V ersetzt.
* Bei mehrfach vorkommenden Buchstaben wird nur das erste Vorkommen des Buchstabens behalten. Alle weiteren Vorkommen des Buchstabens werden entfernt.
---
**Beispiel:**
```
Wir programmieren -> VIRPOGAMEN
```
---
### Erstellen des Playfair-Quadrats
Das 5x5 Playfair Quadrat wird beginnend von oben links (Index 0) befüllt. Dabei werden zuerst alle Felder mit geraden Indizes und erst danach alle Felder mit ungeraden Indizes befüllt.
Die Befüllung erfolgt zuerst mit dem bereinigten Schlüssel, anschließend werden alle noch nicht verwendeten Buchstaben des Alphabets eingefügt.
Beispiel: siehe [Programmablauf](#programmablauf)
### Verschlüsselung
Ein gültiger Klartext (=der zu verschlüsselnde Text) darf nur die Buchstaben A-Z (Groß-/Kleinschreibung egal, mindestens ein Buchstabe) und Leerzeichen enthalten und maximal 50 Zeichen (inklusive Leerzeichen) lang sein.
Der Klartext wird wie folgt vorbereitet:
* Leerzeichen werden entfernt.
* Alle Zeichen werden in Großbuchstaben umgewandelt.
* W wird mit V ersetzt.
Anschließend wird der Klartext zu Bigrammen verarbeitet. Ein Bigramm ist ein Buchstabenpaar, das heißt, dass z. B. der vorbereitete Klartext SPITZE in die Bigramme SP, IT, und ZE umgewandelt wird. Bei dieser Umwandlung gelten folgende Regeln in dieser Reihenfolge:
* Kommen zwei gleiche Zeichen in einem Bigramm vor, wird der Buchstabe X zwischen die Buchstaben eingefügt (z.B. DO PP EL T -> DO PX PE LT). Achtung, die maximale Länge von 50 Zeichen gilt auch für die Bigramme! Das heißt, wenn die Bigramme wegen eingefügten `'X'` auf eine Gesamtlänge von mehr als 50 Zeichen wachsen, dann ist der Klartext auch ungültig.
* Hat der Text jetzt eine ungerade Anzahl an Buchstaben, wird das letzte Bigramm mit X aufgefüllt (z.B. ESP -> ES PX oder BETT -> BE TX T -> BE TX TX).
*Anmerkung:* Es bleibt euch überlassen wie genau ihr die Bigramme speichert (mit Leerzeichen dazwischen oder ohne). Für die maximale Länge von 50 Zeichen sind jedoch an dieser Stelle nur mehr die Buchstaben (inklusive möglicherweise hinzugefügten X) relevant und die Leerzeichen zwischen den Bigrammen müssen ignoriert werden.
Der Ablauf der Verschlüsselung erfolgt mit den folgenden drei Regeln der Playfair-Chiffre:
1. Befinden sich beide Buchstaben in derselben Zeile des Playfair-Quadrats, werden diese jeweils mit ihrem *rechten* Nachbarbuchstaben im Quadrat ersetzt. Falls sich ein Buchstabe am rechten Rand des Quadrats befindet, wird dieser mit dem Buchstaben am linken Rand derselben Zeile des Quadrats ersetzt.
2. Befinden sich beide Buchstaben in derselben Spalte des Playfair-Quadrats, werden diese jeweils mit ihrem *unteren* Nachbarbuchstaben im Quadrat ersetzt. Falls sich ein Buchstabe am unteren Rand des Quadrats befindet, wird dieser mit dem Buchstaben am oberen Rand derselben Spalte ersetzt.
3. Befinden sich die Buchstaben in unterschiedlichen Zeilen und Spalten des Playfair-Quadrats, wird der jeweilige Buchstabe mit dem Buchstaben in derselben Zeile, aber der Spalte des anderen Buchstabens ersetzt (die zwei Buchstaben bilden ein Rechteck im Playfair-Quadrat und werden mit den jeweiligen Ecken ersetzt).
*Anmerkung:* Der Fall, dass der Klartext ein XX enthält oder auf XX aufgefüllt wird, muss bei der Verschlüsselung nicht beachtet werden.
Beispiel: siehe [Programmablauf](#programmablauf)
### Entschlüsselung
Ein gültiger Ciphertext (=verschlüsselter Text) darf nur die Buchstaben A-Z (Groß-/Kleinschreibung egal, mindestens 2 Buchstaben) und Leerzeichen enthalten und maximal 50 Zeichen (inklusive Leerzeichen) lang sein. Die Anzahl der Buchstaben des Ciphertexts muss außerdem eine gerade Zahl sein und der Text darf weder den Buchstaben W, noch Bigramme mit zwei gleichen Buchstaben enthalten.
Für die Entschlüsselung wird der Ciphertext wie folgt vorbereitet:
* Leerzeichen werden entfernt.
* Alle Zeichen werden in Großbuchstaben umgewandelt.
Der Ablauf der Entschlüsselung erfolgt umgekehrt zur Verschlüsselung mit folgenden Regeln:
1. Befinden sich beide Buchstaben in derselben Zeile des Playfair-Quadrats, werden diese jeweils mit ihrem *linken* Nachbarbuchstaben im Quadrat ersetzt. Falls sich ein Buchstabe am linken Rand des Quadrats befindet, wird dieser mit dem Buchstaben am rechten Rand derselben Zeile des Quadrats ersetzt.
2. Befinden sich beide Buchstaben in derselben Spalte des Playfair-Quadrats, werden diese jeweils mit ihrem *oberen* Nachbarbuchstaben im Quadrat ersetzt. Falls sich ein Buchstabe am oberen Rand des Quadrats befindet, wird dieser mit dem Buchstaben am unteren Rand derselben Spalte ersetzt.
3. Befinden sich die Buchstaben in unterschiedlichen Zeilen und Spalten, erfolgt die Entschlüsselung gleich wie bei der Verschlüsselung (Regel 3).
Beispiel: siehe [Programmablauf](#programmablauf)
## Programmablauf:
Nach Programmstart soll direkt die Aufforderung zur Eingabe des Schlüssels angezeigt werden:
```
Bitte Schlüssel eingeben: <key>
```
Wobei `<key>` mit der Benutzereingabe gefolgt von Enter ersetzt wird (ohne eckige Klammern).
Wurde ein ungültiger Schlüssel eingeben, wird die letzte Abfrage wiederholt.
Wurde ein gültiger Schlüssel eingegeben, wird der [bereinigte Schlüssel](#vorbereitung-bereinigung-des-schlüssels) gefolgt vom Playfair Quadrat ausgegeben.
Beispiel mit Schlüssel ` Hallo Welt `:
```
Ausgewählter Schlüssel: HALOVET
Playfair Quadrat:
H J A K L
M O N V P
E Q T R B
S C U D X
F Y G Z I
```
Anschließend wird die/der Benutzer*in mit folgender Ausgabe gefragt, ob sie/er einen Text ver- oder entschlüsseln oder das Programm beenden will.
```
Wählen Sie bitte eine Option:
1 - Verschlüsseln
2 - Entschlüsseln
0 - Programm beenden
<Wert>
```
In dieser Ausgabe entspricht `<Wert>` der Benutzereingabe.
Falls `<Wert>` den Wert 0 hat, wird das Programm mit dem Rückgabewert 0 beendet.
Wurde ein ungültiger Wert eingeben (also weder `0` noch `1` oder `2`), wird die letzte Abfrage wiederholt.
Falls 1 oder 2 gewählt wurde, wird der Text mit dem Ablauf im Folgenden ver- oder entschlüsselt.
Anschließend wird die obige Abfrage der Optionen wiederholt, bis die/der Benutzer*in das Programm beendet.
### Verschlüsselung
Wird ein Klartext verschlüsselt, erfolgt zuerst die Abfrage des Texts:
```
Klartext: <text>
```
Dabei entspricht `<text>` der Benutzereingabe.
Wurde ein ungültiger Text eingeben, wird die letzte Abfrage wiederholt.
Anschließend wird der Text wie oben beschrieben vorbereitet, verschlüsselt und in folgendem Format ausgegeben:
Beispiel mit Klartext `Programmieren macht Spass` mit Schlüssel von oben (HALOVET)
```
Vorbereiteter Klartext: PR OG RA MX MI ER EN MA CH TS PA SX SX
Ciphertext: VB NY TK PS PF QB TM NH SJ EU NL CS CS
```
### Entschlüsselung
Wird ein Cipher-Text entschlüsselt, erfolgt zuerst die Abfrage des Texts:
```
Ciphertext: <text>
```
Dabei entspricht `<text>` der Benutzereingabe.
Wurde ein ungültiger Text eingeben, wird die letzte Abfrage wiederholt.
Anschließend wird der Text wie oben beschrieben vorbereitet, entschlüsselt und in folgendem Format ausgegeben:
Beispiel mit Ciphertext `vbnytkpspfqbtmnhsjeunlcscs` mit Schlüssel von oben (`HALOVET`)
```
Vorbereiteter Ciphertext: VB NY TK PS PF QB TM NH SJ EU NL CS CS
Klartext: PR OG RA MX MI ER EN MA CH TS PA SX SX
```
### Beispiel
```
Bitte Schlüssel eingeben: Hallo Welt
Ausgewählter Schlüssel: HALOVET
Playfair Quadrat:
H J A K L
M O N V P
E Q T R B
S C U D X
F Y G Z I
Wählen Sie bitte eine Option:
1 - Verschlüsseln
2 - Entschlüsseln
0 - Programm beenden
1
Klartext: Programmieren macht Spass
Vorbereiteter Klartext: PR OG RA MX MI ER EN MA CH TS PA SX SX
Ciphertext: VB NY TK PS PF QB TM NH SJ EU NL CS CS
Wählen Sie bitte eine Option:
1 - Verschlüsseln
2 - Entschlüsseln
0 - Programm beenden
2
Ciphertext: vbnytkpspfqbtmnhsjeunlcscs
Vorbereiteter Ciphertext: VB NY TK PS PF QB TM NH SJ EU NL CS CS
Klartext: PR OG RA MX MI ER EN MA CH TS PA SX SX
Wählen Sie bitte eine Option:
1 - Verschlüsseln
2 - Entschlüsseln
0 - Programm beenden
0
```
## Framework
Ein Framework, welches die Erstellung des Playfair-Quadrats übernimmt, wird in [framework.h](./framework.h) zur Verfügung gestellt.
Die Funktion `generatePlayfairSquare` des Frameworks kann dazu verwendet werden, den Schlüssel abzufragen, zu bereinigen und anschließend das Playfair-Quadrat auszugeben. Der Funktion `generatePlayfairSquare` wird der Parameter `square` übergeben, der das Playfair-Quadrat darstellt.
Damit die `generatePlayfairSquare` korrekt funktioniert, müssen folgende drei Funktionen in der Datei `ass2.c` implementiert werden:
* `int stringLength(char *text)`: Gibt die Länge des nullterminierten Strings `text` als int zurück. (Länge des Strings ohne den Nullterminator \0)
* `void toUpper(char *text)`: Konvertiert alle Buchstaben des Strings `text` zu Großbuchstaben.
* `void replaceLetters(char *text, char original, char new_char)`: Ersetzt alle Vorkommen des Zeichens `original` im String `text` mit dem Zeichen `new_char`.
## Spezifikation
* Es dürfen **keine Funktionen im Zusammenhang mit dynamischem Speichermanagement** verwendet werden (malloc).
* Außerdem **nicht erlaubte Bibliotheken**: <string.h> und <stdlib.h>
* Keine zusätzlichen Ausgaben
* Alle Ausgaben erfolgen auf stdout
* Keinerlei Ausgaben auf stderr
* Abgabe bis *spätestens*: 05.12.2020 23:59 (in Österreich gültige Zeit)
* Abgabe: ass2.c
# ESPipes
[[_TOC_]]
## Lernziele
Das Arbeiten mit dynamischem Speicher, File I/O mit Binärdateien
sowie die Verwendung von Bitwise-Operationen und Bit-Masken sollen anhand der
Implementation eines *Pipe*-Minigames geübt werden.
## Beschreibung
*ESPipes* ist eine Variation der *Pipe*-Minigames. Das Ziel des Spiels ist es,
durch das Drehen von Rohren eine Verbindung zwischen dem Start- und Zielrohr
herzustellen. Die Anzahl der benötigten Züge ist hierbei das Punkteergebnis,
wobei weniger Punkte (also weniger Züge) ein besseres Ergebnis bedeuten.
Jede Konfigurationsdatei enthält hierzu auch eine Highscore-Liste, die
entsprechend aktualisiert werden soll.
## Dateiformat
Die Konfigurationsdatei verwendet ein Binärformat. Es kann davon ausgegangen
werden, dass die Datei korrekt formatiert ist, wenn sie mit der korrekten
*Magic-Number* beginnt.
Das Format, also Reihenfolge und Länge der Felder, wird durch folgende
Tabellen spezifiziert (alle Felder mit numerischen Werten sind `unsigned`):
### Gesamt
| Länge | Inhalt |
| ------ | ---------------------------------------------------------------------------- |
| 7 Byte | *Magic-Number* (Muss der ASCII-Text "ESPipes", ohne String-Terminator, sein) |
| 1 Byte | Breite des Spielfelds |
| 1 Byte | Höhe des Spielfelds |
| 1 Byte | Zeile des Startrohrs |
| 1 Byte | Spalte des Startrohrs |
| 1 Byte | Zeile des Zielrohrs |
| 1 Byte | Spalte des Zielrohrs |
| 1 Byte | Anzahl der Einträge in der Highscore-Liste |
| *N/A* | Highscore-Liste |
| *N/A* | Spielfeld |
> **Hinweis**: Die Koordinaten in der Konfigurationsdatei verwenden den
> Basis-Index `0`, die Koordinaten in der Eingabe/Ausgabe den Basis-Index `1`.
### Eintrag in Highscore-Liste
| Länge | Inhalt |
| ------ | -------------------------------------------------------- |
| 1 Byte | Punktezahl |
| 3 Byte | Name (in ASCII-Zeichenkodierung, ohne String-Terminator) |
### Eintrag im Spielfeld
| Länge | Inhalt |
| ------ | --------- |
| 1 Byte | Rohr-Feld |
### Rohr-Feld
Jedes Feld besteht aus einem Byte (programmintern durch ein `uint8_t`
repräsentiert, andere programminterne Repräsentationsformen wie *structs*
sind explizit **nicht** erlaubt). Das Spielfeld wird programmintern durch ein
2-dimensionales Array dieser Felder dargestellt, wobei
die 1. Dimension die Reihen, und die 2. Dimension die Spalten sind.
Ein Feld enthält folgende Informationen:
- Richtungen, in welche das Rohr Öffnungen hat
- Richtungen, in welches das Rohr zusätzlich mit umgebenden Rohren verbunden ist
Diese Informationen sind wie folgt kodiert:
```lang-none
Feld (in binär): 10 00 00 11
Richtungen: ^^ TOP
^^ LEFT
^^ BOTTOM
^^ RIGHT
Feld (in binär): 10 00 00 11
Werte: ^ ^ ^ ^ Feld ist in entsprechende Richtung offen
^ ^ ^ ^ Feld hat in entsprechende Richtung Verbindung zu anderem Rohr
```
> **Tipp**: Man benötigt nur 6 "Basis"-Bit-Masken, alle anderen benötigten
> Bit-Masken lassen sich aus diesen durch Bitwise-Operationen generieren.
Hier sind ein paar Beispiele zum besseren Verständnis der Kodierung
(Visualisierung enthält auch die 4 umgebenden Rohre):
```lang-none
Feld (in binär): 10 00 00 11
Beschreibung: Ein "L"-förmiges Rohr, das oben und rechts offen ist, wobei
es rechts auch mit einem anderen Rohr verbunden ist.
Visualisierung:
╗╚═
```
```lang-none
Feld (in binär): 10 11 11 00
Beschreibung: Ein "T"-förmiges Rohr, das oben und links und unten offen ist,
wobei es links und unten auch mit einem anderen Rohr verbunden ist.
Visualisierung:
═╣╗
```
```lang-none
Feld (in binär): 00 10 00 11
Beschreibung: Ein gerades Rohr, das links und rechts offen ist, wobei
es rechts auch mit einem anderen Rohr verbunden ist.
Visualisierung:
╗══
```
```lang-none
Feld (in binär): 10 10 11 11
Beschreibung: Ein "+"-förmiges Rohr, das in alle Richtungen offen ist,
wobei es unten und rechts auch mit einem anderen Rohr
verbunden ist.
Visualisierung:
╗╬═
```
```lang-none
Feld (in binär): 00 00 00 00
Beschreibung: Eine Blockade. Sie hat in keine Richtung Öffnungen, und kann
daher auch nicht mit anderen Rohren verbunden sein.
Visualisierung:
╗█═
```
## Datentypen
Folgende Datentypen müssen implementiert werden:
### Direction
Der Datentyp *Direction* gibt eine Richtung an. Er kann folgende Werte haben:
| Wert | Bedeutung |
| ---- | --------- |
| 0 | TOP |
| 1 | LEFT |
| 2 | BOTTOM |
| 3 | RIGHT |
> **Tipp**: Die Werte sind so gewählt, dass mit ihnen auch gerechnet werden
> kann.
Der Datentyp dient der programminternen Repräsentation einer Richtung. Dies
kann etwa die Rotations-Richtung beim Drehen eines Feldes oder auch
die Ausrichtung zweier benachbarter Felder zueinander (zB. "Feld rechts vom
aktuellen Feld") sein.
### Highscore
Der Datentyp *Highscore* enthält die Highscore-Liste. Er darf beliebig
implementiert werden, soll jedoch ein eigener, auf die Aufgabe spezialisierter,
Datentyp sein.
## Framework
Ein Framework zur (Befehls-)Eingabe, Text-Ausgabe, und zum Pathfinding wird
bereitgestellt. Weitere Informationen zum Framework sind in Form von
Dokumentation in [framework.h](./framework.h) zu finden.
## Programm-Struktur
Es wird Empfohlen, folgende Hilfs-Funktionen zu implementieren:
```c
bool isDirectionOutOfMap(uint8_t width, uint8_t height, uint8_t coord[2], Direction dir);
bool isPipeOpenInDirection(uint8_t** map, uint8_t width, uint8_t height, uint8_t coord[2], Direction dir);
bool shouldPipeConnectInDirection(uint8_t** map, uint8_t width, uint8_t height, uint8_t coord[2], Direction dir);
uint8_t* getAdjacentPipe(uint8_t** map, uint8_t width, uint8_t height, uint8_t coord[2], Direction dir);
```
## Programm-Ablauf
### Spiel-Start
Das Programm wird mit einem Kommandozeilenparameter aufgerufen. Dieser gibt den
Pfad zur Konfigurationsdatei an, die geladen werden soll. Sollte das Programm
- mit mehr oder weniger Parametern aufgerufen werden oder
- die Konfigurationsdatei nicht geöffnet werden können oder
- die Konfigurationsdatei nicht mit der korrekten *Magic-Number* beginnen,
soll die entsprechende Fehlermeldung ausgegeben werden und das Programm mit dem
entsprechenden Rückgabewert beendet werden (siehe
[Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen)).
Anschließend beginnt die erste Runde.
### Spiel-Ablauf
Zu Beginn jeder Runde wird das Spielfeld ausgegeben:
```lang-none
│1234567
─┼───────
1│╞║╗╔╠═║
2│╗█╣╔║╗╔
3│═╠╗║╗█╣
4│╗█╣╔║═╔
5│═╠═║╗█╣
6│╚╝╚╠═║╨
```
> **Hinweis**: Die Zeichen `╨`,`╡`,`╥`,`╞` stellen die Start- bzw. Zielrohre
> dar. Sie sind in nur eine Richtung geöffnet.
Anschließend wird die Befehlszeile mit der Rundennummer (beginnend mit `1`)
ausgegeben:
```lang-none
1 >
```
Danach wird auf eine Benutzereingabe gewartet.
Wird nichts oder nur *Whitespace* eingegeben, soll die Befehlszeile erneut
ausgegeben werden sowie auf eine neue Benutzereingabe gewartet werden.
Wird ein unbekannter Befehl oder ein bekannter Befehl mit ungültigen Parametern
eingegeben, soll die entsprechende Fehlermeldung (siehe
[Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen)
) ausgegeben werden, und die Befehlszeile erneut ausgegeben werden sowie auf
eine neue Benutzereingabe gewartet werden.
Wird durch die Drehung eines Rohr-Feldes eine Verbindung zwischen Start-
und Zielrohr hergestellt, ist das Spiel zu Ende.
#### Befehl: rotate
Dieser Befehl erlaubt der/dem Benutzer*in, ein Rohr-Feld in eine Richtung zu
drehen.
Wird versucht, dass Start- oder Zielrohr zu drehen, soll die entsprechende
Fehlermeldung ausgegeben werden.
Der Befehl `rotate` hat 3 Parameter:
- die Dreh-Richtung (`left` oder `right`)
- die Zeilennummer (positive Ganzzahl, kleiner als die Anzahl an Reihen)
- die Spaltennummer (positive Ganzzahl, kleiner als die Anzahl an Spalten)
#### Befehl: help
Der Befehl `help` gibt folgenden Hilfetext aus, wobei etwaige Parameter
ignoriert werden:
```lang-none
Commands:
- rotate <DIRECTION> <ROW> <COLUMN>
<DIRECTION> is either `left` or `right`.
- help
Prints this help text.
- quit
Terminates the game.
- restart
Restarts the game.
```
#### Befehl: quit
Der Befehl `quit` (alternativ *EOF*, ausgelöst durch zB. `Ctrl-D`) beendet das
Programm. Parameter werden ignoriert.
#### Befehl: restart
Der Befehl `restart` startet das Spiel neu. Parameter werden ignoriert.
### Spiel-Ende
Zu Spielende wird das (gelöste) Spielfeld, sowie das Punkteergebnis ausgegeben:
```lang-none
│1234
─┼────
1│╞╗╔═
2│█║╬╚
3│╣╚╗║
4│╗╬╚╡
Puzzle solved!
Score: 4
```
Wurde ein Highscore aus der Highscore-Liste geschlagen, wird der Spieler davon
informiert. Danach wird die/der Benutzer*in nach einem 3 Zeichen langen Namen
gefragt:
```lang-none
Beat Highscore!
Please enter 3-letter name:
```
Werden mehr oder weniger als 3 Zeichen, oder andere Zeichen als Buchstaben
eingegeben, soll die entsprechende Fehlermeldung ausgegeben werden, sowie
erneut nach einem Namen gefragt werden.
Der eingegebene Name wird zu Großbuchstaben konvertiert, und die
Highscore-Liste aktualisiert, wobei die Anzahl an Einträgen gleich bleiben
soll. Ein Score von `0` bedeutet, dass der Platz in der Highscore-Liste frei
ist. Bei gleichem Highscore soll der neue Score weiter unten gereiht werden.
Anschließend muss die Highscore-Liste auch noch in der Konfigurationsdatei
aktualisiert werden. Hier soll **ausschließlich** die neue Highscore-Liste in
die Datei geschrieben werden, und **nicht** die ganze Datei neu geschrieben
werden.
> **Tipp**: Der *file-mode* `rb+` erlaubt es, Teile einer bestehenden Datei
> zu überschreiben.
Zuletzt wird die Highscore-Liste ausgegeben, wobei bei freien Plätzen (also
Einträgen mit Score `0`) statt des Namens `---` ausgegeben wird.
Anschließend wird das Programm beendet:
```lang-none
Highscore:
FOO 4
BAR 5
BAZ 7
QUX 11
--- 0
```
## Programm-Rückgabewerte und Fehlermeldungen
| Wert | Fehlermeldung | Bedeutung |
| ---- | ------------------------------------------ | -------------------------------------------------------------- |
| 0 | | Erfolgsfall |
| 1 | `Usage: ./a3 CONFIG_FILE\n` | Falsche Anzahl von Kommandozeilenparametern |
| 2 | `Error: Cannot open file: <CONFIG_FILE>\n` | Konfigurationsdatei kann nicht geöffnet werden |
| 3 | `Error: Invalid file: <CONFIG_FILE>\n` | Konfigurationsdatei beginnt nicht mit korrekter *Magic-Number* |
| 4 | `Error: Out of memory\n` | Kein Speicher kann mehr angefordert werden |
| | `Error: Unknown command: <COMMAND>\n` | Unbekannter Befehl eingegeben |
| | `Usage: rotate ( left \| right ) ROW COLUMN\n` | Ungültige Parameter für Befehl `rotate` |
| | `Error: Rotating start- or end-pipe is not allowed\n` | Drehung von Start- oder Zielrohr |
| | `Error: Invalid name. Only alphabetic letters allowed\n` | Name enthält ungültige Zeichen |
| | `Error: Invalid name. Name must be exactly 3 letters long\n` | Name kürzer oder länger als 3 Zeichen |
> **Hinweis**: Platzhalter sind durch `<>` markiert, und sollen durch den
> entsprechenden Wert ersetzt werden - auch die spitzen Klammern sind nicht
> Teil der Ausgabe.
## Spezifikation
- Keine zusätzlichen Ausgaben
- Alle Ausgaben erfolgen auf *stdout*
- Keinerlei Ausgaben auf *stderr*
- Der Dateiinhalt, insbesondere das Spielfeld und die Highscore-Liste, müssen
am Heap gespeichert werden
- Das Spielfeld wird als 2-dimensionales Array von `uint8_t` gespeichert
- Die Highscore-Liste wird mit eigenem Datentypen (siehe
[Datentypen -> Highscore](#highscore)) gespeichert
## Abgabe
- Die Abgabe erfolgt per *git* auf das Repository, das durch *Progpipe*
erstellt wurde.
- Hierzu darf **nicht** das Web-Interface von *GitLab* verwendet werden.
- Dateiname: `a3.c`
- Abgabe bis *spätestens*: 09.01.2021 23:59 (in Österreich gültige Zeit)
# Assignment 1 : Anordnung von Löschwasserpumpen
## Lernziel
Datentypen, Kontrollstrukturen, Ein-/Ausgabe, Funktionen, Konstanten
## Spezifikation
* Alle Ausgaben erfolgen auf stdout
* Keinerlei Ausgaben auf stderr
* Abgabe bis *spätestens*: 20.11.2021 23:59 (in Österreich gültige Zeit)
* Abzugebende Datei: a1.c
---
## Aufgabenstellung
Es soll ein Programm geschrieben werden, welches die Anzahl der benötigten Pumpen sowie deren Positionen an einem Hang berechnet, sodass ein Zielpunkt mit ausreichend Löschwasser versorgt werden kann. Dabei wird der Hang vereinfacht als Gerade zwischen einem Start- und Zielpunkt angenommen. Die erste Pumpe (Pumpe0) steht immer an der Position (0, 0).
### Eingabe des Durchflusses
Im ersten Schritt wird die/der Benutzer\*in zur Eingabe des benötigten Durchflusses aufgefordert. Dieser muss zwischen 100 und 1200 Litern liegen. Eine valide Eingabe ist deshalb eine Ganzzahl ≥ 100 und ≤ 1200.
```
Erforderlicher Durchfluss [l/min]: <wert>
```
Dabei wird `<wert>` durch die (mit Enter abgeschlossene) Benutzereingabe ersetzt. Die spitzen Klammern sind *nicht* Teil der Benutzereingabe. Unsere [Beispielausgabe](#beispielausgabe) verdeutlicht, wie die Ausgabe auszusehen hat.
Sollte die Eingabe nicht valide sein, erscheint folgende Fehlermeldung:
```
Invalide Eingabe! Der Durchfluss muss mindestens 100 l/min und maximal 1200 l/min betragen.\n
```
Die hier abgebildeten Zeichen `\` und `n` sind nicht als einzelne Zeichen auszugeben, sondern sind als Newline-Character (`\n`) zu verstehen.
Nach der Fehlermeldung startet das Einlesen von vorne (so lange, bis die Eingabe valide ist).
(Tipp: Bei den Test Cases wird nur auf einzelne Ganzzahlen getestet. Sie müssen sich also keine Gedanken darüber machen, wie das Programm mit anderen Eingaben (z.B. Buchstaben) umgehen soll.)
### Eingabe des Zielpunktes
Der Zielpunkt ist durch die Koordinaten `(x, y)` definiert, wobei `x` den horizontalen und `y` den vertikalen Abstand zum Startpunkt angibt. Der Startpunkt hat daher stets die Koordinaten `(0, 0)`. Dabei ergibt sich ein rechtwinkeliges Dreieck mit `x` und `y` als Katheten. Die Hypotenuse des Dreiecks stellt den Hang dar, auf welchem die Löschwasserschläuche verlegt werden.
#### Horizontale Distanz
Zuerst soll die horizontale Distanz eingelesen werden.
```
Horizontale Distanz [m]: <wert>
```
Auch hier ist `<wert>` ein Platzhalter für die Benutzereingabe, welche eine positive Ganzzahl (größer als 0) sein muss. Bei Falscheingabe soll folgende Fehlermeldung ausgegeben werden:
```
Invalide Eingabe!\n
```
Auch für diesen Wert startet das Einlesen nach der Fehlermeldung von vorne (so lange, bis die Eingabe valide ist).
#### Vertikale Distanz
Die vertikale Distanz soll nach nach dem gleichen Schema eingelesen werden.
```
Vertikale Distanz [m]: <wert>
```
Auch die Behandlung von Falscheingaben ist gleich wie im Fall der horizontalen Distanz (siehe auch [Beispielausgabe](#beispielausgabe)).
### Bestimmung des Reibungsverlustes in Schläuchen
Abhängig vom vorhandenen Durchfluss treten unterschiedliche Reibungsverluste auf. Der Verlustbeiwert ($`\lambda`$), welcher für die folgenden Berechnungen nötig ist, kann anhand folgender Tabelle bestimmt werden.
Durchfluss [l/min] | Verlustbeiwert $`\lambda`$ zufolge Reibung [bar/m] |
------------------ | -------------------------------------------------- |
≤ 200 | 0.001 |
201 - 400 | 0.0025 |
401 - 600 | 0.005 |
601 - 800 | 0.01 |
801 - 1000 | 0.015 |
1001 - 1200 | 0.025 |
### Berechnung der Hangneigung
Außerdem ist die Neigung des Hanges ($`\alpha`$) erforderlich. Diese soll in Radiant berechnet werden. Die benötigten Winkelfunktionen sind in der Standardbibliothek **math.h** zu finden.
```math
\begin{equation}
\alpha = \arctan (\frac{y}{x})
\end{equation}
```
### Berechnung des auftretenden Druckverlustes und der Pumpenanordnung
In diesem Beispiel wird ein **Pumpenausgangsdruck** von **10 bar** sowie ein notwendiger **Pumpeneingangsdruck** von **mindestens 1.5 bar** angenommen. Daher ist ein **Druckverlust** zwischen zwei Pumpen von maximal **8.5 bar** zulässig.
Ein bar entspricht einem Druck von 10m Wassersäule (vertikale Distanz), das heißt der **Druckverlust**(ohne Reibung) beträgt **0.1 bar/m**. Durch Pumpe0 herrscht am **Startpunkt** (0,&nbsp;0) ein Druck von **10 bar**.
Der Druck $`p`$ an einer bestimmten Stelle kann somit folgendermaßen bestimmt werden:
```math
\begin{equation}
p = 10 - (0.1 \cdot \Delta y + \lambda \cdot \frac{\Delta y}{\sin(\alpha)})
\end{equation}
```
Hierbei ist $`\Delta y`$ die Höhendifferenz zwischen einem gegebenen Punkt und der letzten Pumpe, welche sich vor dem gesuchten Punkt befindet.
Damit können wir den vertikalen Abstand zwischen der aktuell letzten Pumpe und der nächsten notwendigen Pumpe berechnen. Dazu setzen wir in obiger Gleichung $`p`$ auf den notwendigen Mindestdruck von 1.5 bar und erhalten:
```math
\begin{equation}
\Delta y = \frac{8.5}{0.1 + \frac{\lambda}{\sin(\alpha)}}
\end{equation}
```
Der horizontale Abstand ergibt sich dann aus dieser errechneten Höhendifferenz und der Neigung des Hanges $`\alpha`$:
```math
\begin{equation}
\Delta x = \frac{\Delta y}{\tan(\alpha)}
\end{equation}
```
Es werden so lang Pumpen eingefügt, bis am Zielpunkt ein Druck von mindestens 6 bar vorhanden ist. Die Pumpen sollen dabei jeweils in der berechneten Distanz gesetzt werden. Sollte diese Distanz das Ziel überschreiten, so soll die letzte Pumpe am Zielpunkt gesetzt werden. Dabei soll eine minimale Menge an Pumpen verwendet werden. Sobald am Ziel ein Druck von ≥ 6 bar erreicht wurde, dürfen also keine weiteren Pumpen mehr eingefügt werden.
Ein Beispiel für die Berechnung kann unter dem Punkt [Beispielberechnung](#beispielberechnung) gefunden werden.
### Ausgabe
Nachdem alle oben beschriebenen Eingaben getätigt wurden, gibt das Programm eine
Übersicht über die Berechnungen aus. Zuerst werden die Eingabewerte und die daraus berechneten Parameter ausgegeben.
```
\n
Ziel: (<x>, <y>)\n
Neigung [rad]: <wert_alpha>\n
Durchfluss [l/min]: <wert_d>\n
Reibungsbeiwert [bar/m]: <wert_lambda>\n
```
---
Danach werden die einzelnen Pumpen mit ihren Koordinaten ausgegeben (Pumpe0 bei (0, 0) wird nicht ausgegeben):
```
Pumpe1: (<x_p1>, <y_p1>)\n
Pumpe2: (<x_p1>, <y_p1>)\n
...
```
Sollte keine weitere Pumpe notwendig sein, soll anstatt der Liste der Pumpen folgende Zeile ausgegeben werden:
```
Keine zusaetzliche Pumpe notwendig!\n
```
*Bitte beachten Sie jeweils die beiden Leerzeichen am Zeilenanfang!*
---
Zu guter Letzt soll auch der Austrittsdruck am Zielpunkt angegeben werden.
```
Austrittsdruck Zielpunkt [bar]: <wert_pZiel>\n
```
---
Die Platzhalter `<XX>` sind durch die entsprechenden Werte zu ersetzen. Beachten Sie bitte folgende Hinweise:
* Der Reibungsbeiwert (<wert_lambda>) sowie die Neigung (<wert_alpha>) sollen auf **4 Nachkommastellen** genau angezeigt werden.
* Die Koordinaten der Pumpen (<x_p>, <y_p>) sowie der Austrittsdruck (<wert_pZiel>) sollen jeweils auf **2 Nachkommastellen** genau angezeigt werden.
* Alle weiteren Werte sollen **ohne Nachkommastellen** angezeigt werden.
## Beispielberechnung
Gegeben ist der Durchfluss mit **1020** [l/min] und der Zielpunkt mit **(150, 100)**.
Zuerst werden der Reibungsbeiwert und die Neigung berechnet.
```math
\begin{equation}
\begin{aligned}
\lambda = 0.0250 \\
\alpha = \arctan (\frac{100}{150}) = 0.5880 \text{ [rad]}
\end{aligned}
\end{equation}
```
---
Danach folgt die Berechnung der ersten Pumpe:
```math
\begin{equation}
p_{\text{Ziel}} = 10 - (0.1 \cdot 100 + 0.0250 \cdot \frac{100}{\sin(0.5880)}) = -4.5069 < 6 \text{ [bar]}
\end{equation}
```
*=> Pumpe nötig*
```math
\begin{equation}
\begin{aligned}
\Delta y = \frac{8.5}{0.1 + \frac{0.0250}{\sin(0.5880)}} = 58.5926 \text{ [m]} \\
\Delta x = \frac{58.5926}{\tan(0.5880)} = 87.8890 \text{ [m]} \\
y_{P1} = 0 + 58.5926 = 58.5926 \text{ [m]} \\
x_{P1} = 0 + 87.8890 = 87.8890 \text{ [m]}
\end{aligned}
\end{equation}
```
**Pumpe 1 an (87.89, 58.59)**
---
Sowie die Berechnung der zweiten Pumpe:
```math
\begin{equation}
\begin{aligned}
y_{Neu} = y - y_{P1} = 100 - 58.5926 = 41.4074 \text{ [m]} \\
p_{\text{Ziel}} = 10 - (0.1 \cdot 41.4074 + 0.0250 \cdot \frac{41.4074}{\sin(0.5880)}) = 3.9931 < 6 \text{ [bar]}
\end{aligned}
\end{equation}
```
*=> weitere Pumpe nötig*
```math
\begin{equation}
\begin{aligned}
y_{P2} = y_{P1} + \Delta y = 58.5926 + 58.5926 = 117.1853 \text{ [m]} \\
y_{P2} > y \Rightarrow y_{P2} = y = 100 \text{ [m]}
\end{aligned}
\end{equation}
```
**Pumpe 2 am Zielpunkt (150.00, 100.00)**
---
Zu guter Letzt wird noch der Druck am Zielpunkt berechnet (hier eigentlich überflüssig, da Pumpe am Zielpunkt).
```math
\begin{equation}
\begin{aligned}
y_{Neu} = y - y_{P2} = 100 - 100 = 0.0000 \text{ [m]} \\
p_{\text{Ziel}} = 10 - (0.1 \cdot 0.0000 + 0.0250 \cdot \frac{0.0000}{\sin(0.5880)}) = 10 \text{ [bar]}
\end{aligned}
\end{equation}
```
**Austrittsdruck = 10 [bar]**
## Beispielausgabe
```
Erforderlicher Durchfluss [l/min]: 50000
Invalide Eingabe! Der Durchfluss muss mindestens 100 l/min und maximal 1200 l/min betragen.
Erforderlicher Durchfluss [l/min]: 300
Horizontale Distanz [m]: 250
Vertikale Distanz [m]: 0
Invalide Eingabe!
Vertikale Distanz [m]: 200
Ziel: (250, 200)
Neigung [rad]: 0.6747
Durchfluss [l/min]: 300
Reibungsbeiwert [bar/m]: 0.0025
Pumpe1: (102.16, 81.73)
Pumpe2: (204.32, 163.46)
Austrittsdruck Zielpunkt [bar]: 6.20
```
# Assignment 2 : Tanz der Zeichenketten
## Lernziele
Strings, Pointer, Dynamische Speicherverwaltung
---
**Achtung:** *<string.h>* darf zur Lösung dieser Aufgabe **nicht** verwendet werden!
---
## Aufgabenstellung - Übersicht
Das Programm erhält über `stdin` mehrere Sätze. Wird ein `\n` gelesen, hört das Programm auf, Sätze einzulesen.
Nun wird ein Auswahlmenü angezeigt:
```
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze verketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl:
```
---
Die Funktionen der Optionen werden anhand der folgenden Eingabe erklärt:
```
Das ist ein unnoetiger Satz. C ist so schwer.
```
---
Wenn die\*der Benutzer\*in `t` eingibt:
```
Text Statistik:
2 Sätze, 37 Zeichen
35 Buchstaben (3 Großbuchstaben, 32 Kleinbuchstaben)
```
Wenn die\*der Benutzer\*in `s` eingibt:
```
Nummer des ersten Satzes: 1 [Anmerkung: 1 wurde eingegeben]
Nummer des zweiten Satzes: 2 [Anmerkung: 2 wurde eingegeben]
```
Nun wird der Satz 1 mit dem Satz 2 vertauscht (Ergebnis: `C ist so schwer. Das ist ein unnoetiger Satz.`).
Wenn die\*der Benutzer\*in `c` eingibt:
```
Nummer des ersten Satzes: 1 [Anmerkung: 1 wurde eingegeben]
Nummer des zweiten Satzes: 2 [Anmerkung: 2 wurde eingegeben]
```
Nun wird der Satz 1 mit dem Satz 2 mit einem `und` verbunden (Ergebnis: `Das ist ein unnoetiger Satz und C ist so schwer.`).
Wenn die\*der Benutzer\*in `p` eingibt:
```
Nr. | Satz
-----+----------------------------------------
1 | Das ist ein unnoetiger Satz.
2 | C ist so schwer.
```
Wenn die\*der Benutzer\*in `o` eingibt:
```
Text:
Das ist ein unnoetiger Satz. C ist so schwer.
```
Wenn die\*der Benutzer\*in `e` eingibt:
```
Programmende!
```
Danach wird das Programm mit dem Rückgabewert `0` beendet.
Bei allen Operationen (außer bei `e` - Programmende) wird danach wieder das Auswahlmenü angezeigt.
---
## Aufgabenstellung - Detailliert
**Hinweis:** Jede ausgegebene Zeile wird mit einem `\n` abgeschlossen. Die Ausnahme bilden Eingaben durch Benutzer\*innen, denn es wird *nur bei der [ersten Eingabe](#einlesen-der-sätze)* (bei `Bitte Text eingeben:`) ein `\n` ausgegeben.
### Einlesen der Sätze
Das Programm startet mit der Ausgabe von:
```
Bitte Text eingeben:
```
Danach kann die\*der Benutzer\*in eine **beliebige Anzahl** von Sätzen eingeben. Ein Satz wird mit eiem Punkt (`.`), Fragezeichen (`?`) oder Rufzeichen (`!`) abgeschlossen. Wird ein `\n` (Enter gedrückt) gelesen, hört das Programm auf, Sätze einzulesen.
---
**Tipp:** Es macht keinen Sinn, bei jedem einzelnen gelesenen Zeichen immer `realloc()` aufzurufen. Reservieren Sie also z.B. immer Platz für 100 Zeichen, wenn dieser Platz nicht mehr ausreicht, wieder für 100 Zeichen usw. (Hinweis: `fgets()`).
Speichern Sie danach die Sätze intern als einzelne Strings (ohne Leerzeichen vor oder nach dem Text)! Das heißt pro Satz verwenden Sie einen String und somit ein Mal `malloc()`.
---
**Fehlermeldungen:**
- Wird in der Eingabe kein Zeichen gefunden, das einen Satz abschließt (`.`, `?`, `!`), so kommt es zu der folgenden Ausgabe
```
Kein Satz gefunden!
```
und das Programm wird mit dem Rückgabewert `1` beendet.
- Sollte sich am Ende des letzten Satzes kein Punkt (`.`), Fragezeichen (`?`) oder Rufzeichen (`!`) befinden, so wird
```
Der Text endet ohne Satzzeichen!
```
ausgegeben und das Programm mit dem Rückgabewert `2` beendet.
- Sollte nicht genügend Speicher vorhanden sein, so lautet die Fehlermeldung
```
Zu wenig Speicher vorhanden!
```
und das Programm wird mit dem Rückgabewert `3` beendet.
---
### Auswahlmenü
Nach erfolgreicher Eingabe der Sätze wird eine leere Zeile ausgegeben und danach wird ein Auswahlmenü angezeigt:
```
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze verketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: <Eingabe>
```
die\*der Benutzer\*in tätigt nun eine Eingabe, um eine Option auszuwählen. Falls die Eingabe ungültig ist (ungleich `t`, `s`, `c`, `p`, `o` oder `e`), wird wieder `Ihre Wahl: ` ausgegeben (*Hinweis:* `getchar()`). Wird ein Leerzeichen vor dem Buchstaben eingegeben, ist die Eingabe ungültig.
---
### Text ohne Zeilennummer ausgeben
Wurde die Auswahl `o` durch die\*den Benutzer\*in getroffen, wird der gespeicherte Text ausgegeben. Nach **jedem** Satz wird genau ein Leerzeichen ausgegeben. Beachten Sie, dass sich der Text während der Laufzeit des Programms verändern kann (z.B. durch die Option `s` - *Zwei Sätze vertauschen*)!
Beispiel-Eingabe:
```
Das ist ein unnoetiger Satz. C ist so schwer.
```
Ausgabe durch Option `o`:
```
Text:
Das ist ein unnoetiger Satz. C ist so schwer.
```
Weitere Beispiel-Ausgabe nach dem Vertauschen von Satz 1 und Satz 2 (Option `s`, danach Option `o`):
```
Text:
C ist so schwer. Das ist ein unnoetiger Satz.
```
---
### Text mit Zeilennummer ausgeben
Wurde die Auswahl `p` durch die\*den Benutzer\*in getroffen, wird der gespeicherte Text mit Satznummer (der erste Satz hat die Nummer 1) ausgegeben. Beachten Sie, dass sich der Text während der Laufzeit des Programms verändern kann (z.B. durch die Option `s` - *Zwei Sätze vertauschen*)!
Beispiel-Eingabe:
```
Das ist ein unnoetiger Satz. C ist so schwer.
```
Ausgabe durch Option `p`:
```
Nr. | Satz
-----+----------------------------------------
1 | Das ist ein unnoetiger Satz.
2 | C ist so schwer.
```
Weitere Beispiel-Ausgabe nach dem Vertauschen von Satz 1 und Satz 2 (Option `s`, danach Option `p`):
```
Nr. | Satz
-----+----------------------------------------
1 | C ist so schwer.
2 | Das ist ein unnoetiger Satz.
```
Bitte beachten Sie auch, dass bei einer zweistelligen Nummer nicht eingerückt wird. Somit könnte man die Satznummer mit `%4d` ausgeben.
---
### Programm beenden
Wurde die Auswahl `e` durch die\*den Benutzer\*in getroffen, wird
```
Programmende!
```
ausgegeben und das Programm mit dem Rückgabewert `0` beendet.
---
### Text-Statistik
Wurde die Auswahl `t` durch die\*den Benutzer\*in getroffen, wird eine Statistik zu den Sätzen angezeigt. Es wird die Anzahl der Sätze, die Anzahl der Zeichen (ohne Leerzeichen), sowie die Anzahl der Groß- und die Anzahl der Kleinbuchstaben ausgegeben. Die Ausgabe sieht so aus (`x` ist dabei jeweils durch die entsprechende Anzahl zu ersetzen):
```
Text Statistik:
x Sätze, x Zeichen
x Buchstaben (x Großbuchstaben, x Kleinbuchstaben)
```
---
**ACHTUNG!**
Wurde zuvor die Option `c` ("Zwei Sätze verketten") gewählt, hat sich die Anzahl der Sätze und auch die Anzahl der Zeichen im Vergleich zu den eingegebenen Sätzen verändert!
---
### Zwei Sätze vertauschen
Wurde die Auswahl `s` durch die\*den Benutzer\*in getroffen, wird zuerst die Anzahl der Sätze überprüft. Sollte der Text nur mehr aus einem Satz bestehen, wird `Nur noch ein Satz vorhanden!`
ausgegeben und danach wieder das Auswahlmenü angezeigt. Anderenfalls werden zuerst die Satznummern der Sätze abgefragt, die vertauscht werden sollen:
```
Nummer des ersten Satzes: <Eingabe>
Nummer des zweiten Satzes: <Eingabe>
```
Wird eine ungültige Zahl oder keine Zahl eingegeben, wird nocheinmal `Nummer des ersten Satzes: ` oder `Nummer des zweiten Satzes: ` ausgegeben.
Die Nummern des ersten und des zweiten Satzes müssen sich unterscheiden. Daher ist bei der Abfrage der zweiten Satznummer die nochmalige Eingabe der ersten Satznummer ungültig! Beispiel:
```
Nummer des ersten Satzes: 2
Nummer des zweiten Satzes: 2
Nummer des zweiten Satzes: 1
```
Nach der Eingabe der Satznummern werden die Sätze in der internen Datenstruktur vertauscht.
---
### Zwei Sätze verketten
Wurde die Auswahl `c` durch die\*den Benutzer\*in getroffen, werden zuerst die Satznummern der Sätze abgefragt, die zusammengefügt werden sollen:
```
Nummer des ersten Satzes: <Eingabe>
Nummer des zweiten Satzes: <Eingabe>
```
Die Eingabe soll exakt so wie bei der Option `s` erfolgen. Denken Sie auch an die Überprüfung, ob noch mindestens 2 Sätze vorhanden sind!
Nach der Eingabe der Satznummern werden die Sätze in der internen Datenstruktur zusammengefügt. Dabei wird das Satzzeichen, das den ersten Satz abgeschlossen hat, durch ein ` und ` ersetzt. (Satzaufbau: Satz mit der Nummer `Nummer des ersten Satzes` (ohne abschließendes Satzzeichen) + ` und ` + Satz mit der Nummer `Nummer des zweiten Satzes`.) Bedenken Sie, dass zwischen den beiden Sätzen mehrere Sätze stehen können z.B. Satz 6 mit Satz 2 verbinden.
Auf die Groß- und Kleinschreibung (Satzanfang) ist keine Rücksicht zu nehmen. In der [Beispielausgabe](#beispielausgabe) sehen sie weitere Beispiele, in welchen Sätze verkettet werden. Diese verdeutlichen auch das Verketten von Sätzen, die nicht aufeinanderfolgen.
---
## Beispielausgabe
```
Bitte Text eingeben:
Das ist ein Text. Hier kommt der zweite Satz. Ich bin der dritte Satz. Ein vierter Satz geht auch noch!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: u
Ihre Wahl: t
Ihre Wahl: t
Ihre Wahl: t
Text Statistik:
4 Sätze, 84 Zeichen
80 Buchstaben (8 Großbuchstaben, 72 Kleinbuchstaben)
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: o
Text:
Das ist ein Text. Hier kommt der zweite Satz. Ich bin der dritte Satz. Ein vierter Satz geht auch noch!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: p
Nr. | Satz
-----+----------------------------------------
1 | Das ist ein Text.
2 | Hier kommt der zweite Satz.
3 | Ich bin der dritte Satz.
4 | Ein vierter Satz geht auch noch!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: s
Nummer des ersten Satzes: 100
Nummer des ersten Satzes: 2
Nummer des zweiten Satzes: 4
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: o
Text:
Das ist ein Text. Ein vierter Satz geht auch noch! Ich bin der dritte Satz. Hier kommt der zweite Satz.
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: p
Nr. | Satz
-----+----------------------------------------
1 | Das ist ein Text.
2 | Ein vierter Satz geht auch noch!
3 | Ich bin der dritte Satz.
4 | Hier kommt der zweite Satz.
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: t
Text Statistik:
4 Sätze, 84 Zeichen
80 Buchstaben (8 Großbuchstaben, 72 Kleinbuchstaben)
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: c
Nummer des ersten Satzes: 4
Nummer des zweiten Satzes: 1
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: p
Nr. | Satz
-----+----------------------------------------
1 | Ein vierter Satz geht auch noch!
2 | Ich bin der dritte Satz.
3 | Hier kommt der zweite Satz und Das ist ein Text.
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: o
Text:
Ein vierter Satz geht auch noch! Ich bin der dritte Satz. Hier kommt der zweite Satz und Das ist ein Text.
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: t
Text Statistik:
3 Sätze, 86 Zeichen
83 Buchstaben (8 Großbuchstaben, 75 Kleinbuchstaben)
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: c
Nummer des ersten Satzes: 3
Nummer des zweiten Satzes: 2
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: p
Nr. | Satz
-----+----------------------------------------
1 | Ein vierter Satz geht auch noch!
2 | Hier kommt der zweite Satz und Das ist ein Text und Ich bin der dritte Satz.
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: c
Nummer des ersten Satzes: 2
Nummer des zweiten Satzes: 1
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: p
Nr. | Satz
-----+----------------------------------------
1 | Hier kommt der zweite Satz und Das ist ein Text und Ich bin der dritte Satz und Ein vierter Satz geht auch noch!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: o
Text:
Hier kommt der zweite Satz und Das ist ein Text und Ich bin der dritte Satz und Ein vierter Satz geht auch noch!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: t
Text Statistik:
1 Sätze, 90 Zeichen
89 Buchstaben (8 Großbuchstaben, 81 Kleinbuchstaben)
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: s
Nur noch ein Satz vorhanden!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: c
Nur noch ein Satz vorhanden!
Wählen Sie eine Option:
t: Text-Statistik
s: Zwei Sätze vertauschen
c: Zwei Sätze zusammenketten
p: Text mit Zeilennummer ausgeben
o: Text ohne Zeilennummer ausgeben
e: Programm beenden
Ihre Wahl: e
Programmende!
```
---
**ACHTUNG!**
Bitte befolgen Sie die Anweisungen zur Ausgabe *genau*, da die Test Cases selbst bei kleinen Fehlern (z.B. ein Leerzeichen
zu wenig oder zu viel) fehlschlagen! Nutzen Sie auch das zur Verfügung gestellte Testsystem, welches wertvolle Hinweise auf Fehler in Ihrem Programm liefert.
---
## Spezifikation
* Alle Ausgaben erfolgen auf stdout
* Keinerlei Ausgaben auf stderr
* string.h darf **nicht** verwendet werden!
* Abgabe bis *spätestens*: 11.12.2021 23:59 (in Österreich gültige Zeit)
* Abzugebende Datei: a2.c
# ESP-Scrabble
## Lernziele
Das Arbeiten mit dynamischem Speicher, `enum`s, `struct`s, File I/O und Command Line Arguments.
## Spezifikation
- Für einen Buchstabenstein – also die Verknüpfung eines Buchstabens mit seinem Wert – ist ein `struct` zu verwenden.
- Spielfeld und Liste der Buchstabensteine müssen am Heap angelegt werden. Es soll dabei nicht mehr Speicher angefordert werden als notwendig ist.
- Alle Ausgaben erfolgen auf *stdout*
- Keinerlei Ausgaben auf *stderr*
- Das LV-Team stellt ein hilfreiches Framework zur Verfügung (siehe [Framework](#framework)). Dieses Framework darf genutzt aber **nicht verändert** werden!
- offizieller Start: 16. Dezember (KU-Stream)
- Deadline: 15. Jänner um 23:59 Uhr (in Österreich gültige Zeit)
- Nachfrist (**mit Punkteabzügen**): 22.Jänner um 23:59 Uhr (in Österreich gültige Zeit)
- Abzugebende Datei: a3.c
## Beschreibung
ESP-Scrabble ist eine Abwandlung des Spiels Scrabble. In der ESP-Version bilden zwei Spieler\*innen aus einer Liste von Buchstabensteinen Wörter auf einem Spielfeld und versuchen damit, einen höheren Punktestand als die\*der Gegenspieler\*in zu erzielen.
## Dateiformat
Die Konfigurationsdatei verwendet ein Textformat. Es kann davon ausgegangen
werden, dass die Datei korrekt formatiert ist, wenn sie mit der korrekten
[Magic-Number](https://de.wikipedia.org/wiki/Magische_Zahl_(Informatik)) beginnt.
Die Reihenfolge der einzelnen Teile der Konfigurationsdatei wird durch folgende Tabelle spezifiziert:
| Inhalt der Konfigurationsdatei |
| ----------------------------------------------------------------------- |
| *Magic-Number* (Muss der ASCII-Text "Scrabble" sein) |
| Spielfeld (Quadrat aus den Zeichen `'A'`-`'Z'` und `' '`) |
| Spieler\*in 1 oder 2 an der Reihe (`'1'`: Spieler\*in 1, `'2'`: Spieler\*in 2) |
| Spielstand Spieler\*in 1 (Zahl in Dezimalschreibweise) |
| Spielstand Spieler\*in 2 (Zahl in Dezimalschreibweise) |
| Auflistung verwendbarer Buchstabensteine (Details unter [Buchstabenstein](#buchstabenstein))|
Die einzelnen Teile der Konfigurationsdatei sind jeweils durch `'\n'` getrennt. Die Auflistung aller verwendbaren Buchstabensteine befindet sich in einer Zeile. Dabei wird ein Buchstabenstein durch einen Buchstaben und eine Ziffer (größer gleich 1 und kleiner gleich 9) repräsentiert, also zum Beispiel `'C1'`. Zwischen den Angaben zu einzelnen Buchstabensteinen befindet sich immer ein Leerzeichen. Ein Beispiel für eine gültige Konfigurationsdatei ist [config.txt](./config.txt).
## Buchstabensteine
| Erforderliche Membervariablen eines Buchstabensteins. (Weitere Membervariablen sind erlaubt.) |
| ------------------------------ |
| Buchstabe (a-z, ohne Umlaute) |
| Wert des Buchstabenstein (1-9) |
Ein Buchstabenstein wird durch einen Buchstaben und eine Ziffer beschrieben. Diese Ziffer bestimmt, wie viele Punkte Spieler\*innen bekommen, wenn sie diesen Buchstabenstein auf das Spielfeld legen. In der Konfigurationsdatei sind die erlaubten Buchstaben mit ihrem Wert aufgelistet. Im Programm soll ein Buchstabenstein durch ein `struct` dargestellt werden.
Jeder Buchstabenstein in der Konfigurationsdatei kann während des Spiels **beliebig oft** eingesetzt werden.
## Spielfeld
Die Größe und der Inhalt des Spielfeldes sind anhand der Konfigurationsdatei ersichtlich. In ESP-Scrabble ist das Spielfeld immer quadratisch, wobei die kleinstmögliche Größe 4x4 und die größtmögliche Größe 26x26 Felder beträgt. Ein Feld wird in der Konfigurationsdatei mithilfe eines ASCII-Characters dargestellt. `'A'``'Z'` stellen dabei die von den Spieler\*innen eingesetzten Buchstaben dar.
> **Wichtig**: Das Spielfeld **muss** bei der Implementierung am Heap gespeichert werden!
### Leeres Beispielspielfeld
Folgendes Beispiel zeigt die Ausgabe eines 15x15 Felder großen, leeren Spielfeldes. Dabei sind die Zeilen- und Spaltenbezeichnungen, sowie die Trennlinien nicht in der Konfigurationsdatei enthalten.
Die Buchstaben, welche die Koordinaten bilden, müssen der Reihenfolge des Alphabets folgen und lassen sich somit berechnen. Bei einem 26x26 Felder großen Spielfeld stellen daher A-Z die Koordinaten dar; bei einem 5x5 Spielfeld wären A-E die Koordinaten.
```
|ABCDEFGHIJKLMNO
-----------------
A|
B|
C|
D|
E|
F|
G|
H|
I|
J|
K|
L|
M|
N|
O|
```
## Programmablauf
### Spielstart
Das Programm wird mit einem Kommandozeilenparameter aufgerufen. Dieser gibt den
Pfad zur Konfigurationsdatei an, die geladen werden soll. Sollte das Programm
- mit mehr oder weniger Parametern aufgerufen werden oder
- die Konfigurationsdatei nicht geöffnet werden können oder
- die Konfigurationsdatei nicht mit der korrekten *Magic-Number* beginnen,
soll die entsprechende Fehlermeldung ausgegeben werden und das Programm mit dem
entsprechenden Rückgabewert beendet werden (siehe
[Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen)).
Anschließend beginnt die\*der in der Konfigurationsdatei genannte Spieler\*in mit dem ersten Spielzug.
### Spielablauf
Zu Beginn jedes Spielzugs wird das Spielfeld mit Zusatzinformationen (Punktestand, verfügbare Buchstabensteine) ausgegeben. (siehe [Beispielausgabe](#beispielausgabe))
Anschließend wird die Befehlszeile mit der Spielernummer (1 oder 2) ausgegeben:
```lang-none
Player 1 >
```
Danach wird auf eine Benutzereingabe gewartet.
Wird nichts (Enter) oder nur *Whitespace* eingegeben, soll die Befehlszeile erneut
ausgegeben werden sowie auf eine neue Benutzereingabe gewartet werden.
Wird ein unbekannter Befehl oder ein bekannter Befehl mit falschen oder ungültigen Parametern
eingegeben, soll die entsprechende Fehlermeldung (siehe
[Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen))
ausgegeben werden und die Befehlszeile erneut ausgegeben werden sowie auf
eine neue Benutzereingabe gewartet werden.
#### Befehl `quit`:
Der Befehl `quit` (alternativ *EOF*, ausgelöst durch z. B. `Ctrl-D`) beendet das
Programm.
#### Befehl `help`:
Der Befehl `help` gibt folgenden Hilfetext aus:
```lang-none
Commands:
- insert <ROW> <COLUMN> <H/V> <WORD>
<H/V> stands for H: horizontal, V: vertical.
- help
Prints this help text.
- quit
Terminates the game.
- save
Saves the game to the current config file.
- load <CONFIGFILE>
load config file and start game.\n
```
Dabei repräsentiert das `\n` am Ende der Ausgabe einen Zeilenumbruch. Nach diesem wird die Befehlszeile erneut ausgegeben.
#### Befehl `insert`:
Mithilfe des `insert`-Befehls kann ein Wort in das Spielfeld eingefügt werden. Dabei werden die Zeile und die Spalte des ersten Buchstabens sowie die Richtung (horizontal/vertikal) und das einzufügende Wort als Parameter angegeben. Um das Wort zu bilden, werden die in der Konfigurationsdatei definierten Buchstabensteine und etwaige bereits am Spielfeld liegende Buchstabensteine verwendet.
Die 4 Parameter lauten wie folgt:
- ROW: Die Zeilenbezeichnung, an der das Wort beginnen soll (Aa-Zz).
- COLUMN: Die Spaltenbezeichnung, an der das Wort beginnen soll (Aa-Zz).
- H/V: Die Orientierung in der das Wort eingefügt wird
- Entweder `H` bzw. `h` für horizontal (von links nach rechts)
- Oder `V` bzw. `v` für vertikal (von oben nach unten).
- WORD: Das einzufügende Wort.
Die Groß-/Kleinschreibung soll für alle Parameter des `insert`-Befehls ignoriert werden; das heißt die Eingabe erfolgt case-insensitive. Auf dem Spielfeld wird jedes Wort in Großbuchstaben dargestellt.
Wurde das Wort erfolgreich eingefügt, so wird die Punktewertung ausgelöst:
Zum Spielstand der aktiven Spielerin bzw. des aktiven Spielers wird die Summe der durch die **neu** gelegten Buchstabensteine erreichten Punkte hinzuaddiert.
Der `insert`-Befehl beendet einen Spielzug, wenn kein Fehler auftritt. Dann beginnt der nächste Spielzug, in welchem die/der nächste Spieler\*in an der Reihe ist (siehe [Spielablauf](#spielablauf)).
##### `insert` Befehle mit falschen Parametern:
Wenn mindestens einer der Parameter ROW, COLUMN und H/V nicht valide ist, wird die entsprechende Fehlermeldung laut [Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen) ausgegeben.
##### Unmögliche Züge:
Bei unmöglichen Spielzügen wird die Fehlermeldung `Error: Impossible move!\n` laut [Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen) ausgegeben. Unmögliche Spielzüge verstoßen gegen mindestens eine der folgenden Bedingungen:
- Das Wort muss am Spielfeld Platz haben.
- Das Wort darf nur Buchstaben von A-Z (a-z) beinhalten.
- Die für die Bildung des Wortes nötigen Buchstaben müssen in der Liste erlaubter Buchstaben vorhanden sein (siehe Konfigurationsdatei).
- Ein neu hinzugefügtes Wort muss mit mindestens einem Wort, das bereits auf dem Spielfeld liegt, verbunden sein (Ausnahme: Erster Spielzug). Zwei Wörter sind verbunden, wenn sie sich zumindest einen Buchstabenstein teilen.
- Das neue Wort darf mit bestehenden Wörtern zu keinem Widerspruch führen. Das heißt, dass das Hinlegen eines Wortes keine bereits ausgelegten Buchstaben mit anderen Buchstaben überschreiben darf.
>Hinweis: Wenn ein bestehendes Wort an der exakt gleichen Stelle noch einmal eingefügt wird, handelt es sich um einen gültigen Zug, der aber keine Punkte bringt, da keine neuen Buchstaben eingefügt wurden.
>Hinweis: Wenn das Spielfeld in einem Config-File bereits ausgelegte Wörter enthält, so müssen diese _nicht_ verbunden sein. Sie können annehmen, dass in solchen Config-Files zumindest ein\*e Spieler\*in bereits Punkte hat. Da bereits ein\*e Spieler\*in über Punkte verfügt, gilt der erste Zug als vergangen. Somit müssen in diesem Fall _alle_ neu hinzugefügten Wörter – also auch das erste nach dem Laden der Config-Datei – mit (zumindest) einem bestehenden Wort verbunden sein.
##### Beispiel für einen gültigen Zug
Im ersten Zug wurde das Wort PLAY auf das Spielfeld gelegt und in diesem Beispiel sind auch die Buchstaben E und S erlaubt.
```
|ABCDEF
--------
A|
B|
C|
D| PLAY
E|
F|
```
PLAY kann im zweiten Zug mit `insert B B V esp` um das Wort ESP erweitert werden:
```
|ABCDEF
--------
A|
B| E
C| S
D| PLAY
E|
F|
```
Das Einfügen ist in diesem Fall erlaubt, weil sich das neue Wort ESP einen Buchstaben (`'P'`) mit dem bereits gelegten Wort PLAY teilt. Für diesen Zug erhält die\*der ziehende Spieler\*in Punkte für die Buchstaben `'E'` und `'S'`. Der letzte Buchstabe des Wortes ESP liefert keine Punkte, weil er bereits auf dem Spielfeld lag.
>Hinweis: Da für diese Scrabble-Version keine Verknüpfung mit einem Wörterbuch besteht, überprüft das Programm nicht, ob das eingegebene Wort existiert.
#### Befehl `save`:
Der `save`-Befehl speichert den Spielstand in der Konfigurationsdatei, von der das Spiel geladen wurde. Dadurch wird das Spielfeld, die\*der als nächste ziehende Spieler\*in sowie die Spielstände überschrieben. Die Liste der verfügbaren Buchstabensteine bleibt gleich.
Kann die Datei nicht geschrieben werden, so wird die Fehlermeldung in [Programm-Rückgabewerte und Fehlermeldungen](#programm-rückgabewerte-und-fehlermeldungen) ausgegeben.
Nach Ende des Befehls wird die Befehlszeile erneut ausgegeben.
### Spielende
Das Spiel wird beendet, sobald ein\*e Spieler\*in einen bestimmten Punktestand erreicht. Der Punktestand für die Siegesbedingung wird folgendermaßen berechnet: (Länge x Breite des Spielfeldes) / 2.
Etwaige Nachkommastellen werden abgeschnitten. Bei einem 9x9 Spielfeld gewinnt somit der\*die Spieler\*in, welche\*r zuerst mindestens 40 Punkte erreicht.
Gewinnt ein\*e Spieler\*in, so wird folgende Nachricht ausgegeben:
```
Player <player_num> has won the game with <score> points!\n
```
Dabei ist der Platzhalter `<player_num>` durch die Nummer der\*des Siegerin\*Siegers und `<score>` durch ihre\*seine Punkte zu ersetzen. Danach wird das Programm beendet.
>Hinweis: Der Fall in welchem alle Felder besetzt werden, ohne dass es eine\*n Gewinner\*in gibt, wird nicht getestet.
## Programm-Rückgabewerte und Fehlermeldungen
Das Programm soll im Verlauf des Spiels auf Fehler mit entsprechenden Fehlermeldungen reagieren. Manche Fehler führen sogar zum Ende des Programms mit einem bestimmten Rückgabewert. Alle Fehler inklusive der entsprechenden Fehlermeldungen und etwaiger Rückgabewerte des Programms sind der folgenden Tabelle zu entnehmen. Aus dieser geht auch hervor, dass das Programm beendet werden soll, wenn nicht genügend Speicher zur Verfügung steht. Daher ist beim Reservieren von Speicher auf dem Heap auch immer zu prüfen, ob das Reservieren erfolgreich war.
| Wert | Fehlermeldung | Bedeutung |
| ---- | ------------------------------------------ | -------------------------------------------------------------- |
| 0 | | Erfolgsfall |
| 1 | `Usage: ./a3 configfile\n` | Falsche Anzahl von Kommandozeilenparametern |
| 2 | `Error: Cannot open file: <CONFIG_FILE>\n` | Konfigurationsdatei kann nicht geöffnet werden |
| 3 | `Error: Invalid file: <CONFIG_FILE>\n` | Konfigurationsdatei beginnt nicht mit korrekter *Magic-Number* |
| 4 | `Error: Out of memory\n` | Kein Speicher kann mehr angefordert werden |
| | `Error: Unknown command: <COMMAND>\n` | Unbekannter Befehl eingegeben |
| | `Error: Insert parameters not valid!\n` | `insert` Befehl mit falschen Parametern / Parameteranzahl|
| | `Error: Impossible move!\n` | Ungültiger `insert` Befehl (für die unter [Unmögliche Züge](#unmögliche-züge) angeführten Fälle)|
| | `Error: Could not save to file!\n`| Fehler beim Speichern |
> Hinweis: Bei `<COMMAND>` wird die Eingabe bis zum letzten Zeichen vor dem ersten Leerzeichen (oder vor dem '\n' falls die Eingabe kein Leerzeichen enthält) in gleicher Form wieder ausgegeben. Bei `<CONFIG_FILE>` wird der Dateiname bzw. Kommandozeilenparameter wieder ausgegeben.
## Beispielausgabe
```
A1, B1, D2, E1, F2, I1, K2, L2, Q3,
S2, T2, U1
P1: 0 Points
P2: 7 Points
|ABCDEFGHIJKLMNO
-----------------
A|
B|
C|
D|
E|
F|
G| S
H| A
I| L
J| T
K|
L|
M|
N|
O|
Player 1 > insert G C H test
A1, B1, D2, E1, F2, I1, K2, L2, Q3,
S2, T2, U1
P1: 5 Points
P2: 7 Points
|ABCDEFGHIJKLMNO
-----------------
A|
B|
C|
D|
E|
F|
G| TEST
H| A
I| L
J| T
K|
L|
M|
N|
O|
Player 2 > insert g c v TELEGRAM
Error: Impossible move!
Player 2 > insert g c v TALL
A1, B1, D2, E1, F2, I1, K2, L2, Q3,
S2, T2, U1
P1: 5 Points
P2: 12 Points
|ABCDEFGHIJKLMNO
-----------------
A|
B|
C|
D|
E|
F|
G| TEST
H| A A
I| L L
J| L T
K|
L|
M|
N|
O|
Player 1 >
```
Die verfügbaren Buchstabensteine werden in der Reihenfolge ausgegeben, in der sie auch in der Konfigurationsdatei angegeben sind. Pro Zeile werden dabei bis zu neun Buchstabensteine ausgegeben, wobei der entsprechende Buchstabe groß geschrieben ist. (Beachten Sie die leere Zeile vor Ausgabe der Liste und das Leerzeichen nach den Kommas!)
### Wertung
In diesem Beispiel wurden für die Buchstaben T und S der Wert 2 und für E der Wert 1 angenommen. Die Werte der einzelnen Buchstabensteine werden aus der Konfigurationsdatei eingelesen. S war schon gelegt; daher ist das Wort TEST in obigem Beispiel
```
2(T) + 1(E) + 2(T) = 5
```
Punkte wert.
## Framework
Ein Framework zum Einlesen der Befehle wird in [framework.h](./framework.h) bereitgestellt. Dieses Framework beinhaltet die Funktion `parseCommand`, die eine Kommandozeileneingabe in eine Datenstruktur vom Typ `Input` (auch in [framework.h](./framework.h) definiert) umwandelt. Der Rückgabewert von `parseCommand` liefert somit nützliche Informationen über die Eingabe eines Befehls. Weitere Informationen hierzu sind der Datei [framework.h](./framework.h) zu entnehmen.
>**Hinweis:** Im Falle des `insert`-Kommandos kann Heap-Speicher alloziert werden. Dieser muss vom Benutzer der Funktion wieder freigegeben werden!
## Bonus - Befehl `load`
Um Bonuspunkte zu bekommen, kann zusätzlich der Befehl `load` implementiert werden.
Der `load`-Befehl lädt eine Konfigurationsdatei wie beim Spielstart. Dafür wird ein Parameter verwendet, der den Pfad zur zu ladenden Konfigurationsdatei angibt. Etwaige Änderungen am derzeitigen Spiel werden *nicht* automatisch gespeichert.
Beim `load`-Befehl kann es zu Fehlermeldungen sowie zum Beenden des Programms kommen. Das Verhalten im Falle eines Fehlers soll jenem zum Start des Programms entsprechen.
Nach dem erfolgreichen Laden wird mit der neuen Konfiguration weitergespielt. (Dadurch kann es zum Beispiel vorkommen, dass auf einem Spielfeld weitergespielt wird, dass eine andere Größe besitzt als das bisherige Spielfeld. Außerdem ist es möglich, dass in der neu geladenen Konfigurationsdatei andere Buchchstabensteine zur Verfügung stehen.)
>Hinweis: Achten Sie auch hier besonders auf den richtigen Umgang mit dem dynamischen Speicher.
### Bonus und Framework
Sollte der [Bonus](#bonus-befehl-load) implementiert und das Framework genutzt werden, so muss der Bonus zuerst mithilfe eines `#define`s aktiviert werden.
Dazu muss `BONUS` **vor** dem `#include` des [framework.h](./framework.h)-Files definiert werden:
```diff
...
+#define BONUS
#include "framework.h"
...
```
Das oben abgebildete `+` ist dabei nicht Teil des Codes sondern soll nur verdeutlichen, dass die entsprechende Zeile für den Bonus hinzugefügt werden muss.
# ESP Assignment Descriptions
This repository contains the assignment descriptions of the CS1 course **Introduction to Programming** (german: "Einführung in die strukturierte Programmierung" (ESP)) at **Graz University of Technology** from winter semester 2020 and winter semester 2021. Student work individually on three assignments an can achieve 100 points.
| | 2020 | 2021 |
| ---- | ------------------------------------------------------- | ------------------------------------------------------- |
| A1 | [Gross-net calculator](2020_a1_gross-net_calculator.md) | [Water pumps](2021_a1_water_pumps.md) |
| A2 | [Playfair](2020_a2_playfair.md) | [Dance of the strings](2021_a2_dance_of_the_strings.md) |
| A3 | [ESPipes](2020_a3_espipes.md) | [ESP-Scrabble](2021_a3_esp_scrabble.md) |
## Contact
For more information contact david.kerschbaumer@tugraz.at
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment