# Check: Stadt, Land, Fluss (2)

Quelle: https://dev.inf.zone/exercises/08/stadt-land-fluss-2/

**Wozu das Ganze?**

Dies ist ein [Check](https://dev.inf.zone/faq/uebung-checks/), also eine Lernzielkontrolle: Er bringt nichts Neues, sondern prüft, ob Sie die Konzepte aus den bisherigen Übungen selbstständig anwenden und eine Problemstellung in eigene Funktionen zerlegen können. Deshalb gibt es keine Hilfestellung und keine Lösung. Der Check ist freiwillig und zählt nicht für die Bonuspunkte. Bearbeiten Sie den Check erst, wenn Sie die vorangegangenen Übungen bearbeitet haben; sonst holen Sie zuerst diese nach. Er baut nicht auf dem ersten Check [Stadt, Land, Fluss](https://dev.inf.zone/exercises/05/stadt-land-fluss/) auf; wenn Sie den noch nicht gemacht haben, fangen Sie trotzdem besser dort an.

Bei dem Spiel "Stadt, Land, Fluss" ([Wikipedia](https://de.wikipedia.org/wiki/Stadt,_Land,_Fluss)) muss vor jeder Runde ein Buchstabe bestimmt werden. Bei der gängigsten Methode geht ein Spieler das Alphabet im Kopf durch, bis ein zweiter Spieler "Stopp" ruft. Um dem Spieler, der das Alphabet durchgeht, weniger Manipulationsmöglichkeit zu geben, kann auch ein Computerprogramm einen zufällig ausgewählten Buchstaben ausgeben.

Erstellen Sie ein Programm, das für das oben beschriebene Szenario für jede Runde einer Spielesession (d.h. eines Programmdurchlaufs) "auf Knopfdruck" einen zufällig ausgewählten Buchstaben ausgibt. Beachten Sie, dass für dieses Szenario jeder Buchstabe höchstens **ein Mal** pro Spielesession (d.h. Programmdurchlauf) ausgegeben werden darf.

> [!NOTE]
> Lesen Sie vor dem Bearbeiten der Aufgabe die Informationen in den folgenden Abschnitten.

## Details zur Umsetzung

### Verhalten bei Ein- und Ausgabe

Wird das Programm ausgeführt, soll der Nutzer zunächst zu einer Eingabe über `get_string()` aufgefordert werden:
```plaintext
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
```

Drückt der Nutzer auf die Eingabetaste, d.h. übergibt eine leere *Eingabe*, soll ein Buchstabe generiert und auf der Konsole zusammen mit der aktuellen Rundenanzahl ausgegeben werden, z.B.:
```plaintext
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 1: F
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 2: S
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
[...]
```

Eine Überprüfung der Eingabe ist jedoch nicht erforderlich. Wenn ein Nutzer z.B. "sdfjhk" eingibt, kann auch einfach ein neuer Buchstabe ausgegeben werden:
```plaintext
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: sdfjhk
Runde 1: T
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: Hallo
Runde 2: I
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
[...]
```

Gibt der Nutzer vor dem Drücken der Eingabetaste jedoch "Ende" oder "x" ein, soll das Programm beendet werden:
```plaintext
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 1: A
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: Ende
stadtlandfluss2/ $
```

Das Programm sollte auch dann beendet werden, wenn jeder Buchstabe im Alphabet, d.h. in unserem Fall `26`, einmal ausgegeben wurde. Das bedeutet, dass die maximale Anzahl der Runden in unserem Fall `26` ist:
```plaintext
[...]
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 25: U
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 26: Q
stadtlandfluss2/ $
```

Skizzieren Sie eine erste grobe Vorgehensweise in Pseudocode, um ein solches Programm zu erstellen. Sie können dabei annehmen, dass Sie bereits eine Funktion `get_letter()`, die einen Buchstaben basierend auf einer *pseudo-zufälligen* Zahl zurückgibt, zur Verfügung haben. So können Sie sich zunächst auf das Grundgerüst, d.h. den grundlegenden Programmablauf, konzentrieren. Wie Sie eine derartige Funktion konkret implementieren, können Sie sich später überlegen.

### Hinweise zum Generieren von zufälligen Zahlen

In der Aufgabe [Vererbung](https://dev.inf.zone/exercises/08/inheritance/) haben Sie bereits einen sogenannten pseudo-zufälligen Zahlengenerator kennengelernt. Vermutlich werden Sie die zufällig generierte Zahl, die von diesem zurückgegeben wird, in eine Zahl zwischen 0 und 25 umwandeln wollen.

Überlegen Sie anhand der Verwendung von `rand()` und `srand()` in [Vererbung](https://dev.inf.zone/exercises/08/inheritance/), wie Sie das dortige Vorgehen für diese Aufgabe adaptieren können. Sie können sich alternativ auch den [Handbucheintrag](https://manual.cs50.io/3/random) zur Verwendung von `rand()` anschauen. Dort finden Sie ein alternatives Vorgehen. Wichtig: Vor dem Aufrufen von `rand()` sollte einmalig [`srand()`](https://manual.cs50.io/3/srandom) aufgerufen werden. Beachten Sie insbesondere, mit welchem Wert `srand()` im gezeigten [Beispiel](https://manual.cs50.io/3/srandom#example) aufgerufen wird.

> [!WARNING]
> **Achtung: Die Links verweisen jeweils auf den Handbucheintrag zu `random()` und `srandom()`, da diese vom CS50 Team zur besseren Zugänglichkeit bereits aufbereitet worden sind. Die relevanten Informationen treffen sowohl auf `random()`/`rand()` als auch auf `srandom()`/`srand()` zu. Einziger Unterschied abgesehen von dem Namen: `random()` gibt einen `long` zurück, `rand()` einen `int`. Zudem ist für die Verwendung von [`rand()`](https://manual.cs50.io/3/rand) und [`srand()`](https://manual.cs50.io/3/srand) lediglich eine Einbindung von `<stdlib.h>` erforderlich.**

### Das Problem der Einmaligkeit

Nun zum *etwas* schwierigeren Teil: Das Problem mit zufällig bestimmten Zahlen bzw. Buchstaben ist, dass diese nun einmal zufällig bestimmt sind. D.h. es ist nahezu ausgeschlossen, dass der wiederholte Aufruf einer Funktion wie `get_letter()`, die auf einem pseudo-zufälligen Zahlengenerator basiert, dazu führt, dass jeder Buchstabe *genau* **ein Mal** zurückgegeben wird. Dieses Verhalten müssen Sie erzwingen. Ihr Programm muss sich also *merken*, welche Buchstaben bereits ausgegeben wurden und sicherstellen, dass ein bereits gemerkter Buchstabe kein zweites Mal ausgegeben wird. Überlegen Sie sich mit Ihrem vorhandenen Wissen aus den vorhergehenden Übungen ein dazu geeignetes Vorgehen.

### Hinweise zur Implementierung

Implementieren Sie das Programm in C in einer Datei namens `stadtlandfluss2.c` in einem Ordner namens `stadtlandfluss2`.

Achten Sie auf gutes Design und angemessene Abstraktion, indem Sie zusammengehörige Funktionalität in Funktionen kapseln. Sie sollten im Rahmen dieser Aufgabe *mindestens* eine Funktion schreiben. Wenn Ihr Programm funktioniert, überprüfen Sie, ob Sie Ihren Code in Bezug auf Struktur und Lesbarkeit verbessern können.

> [!WARNING]
> Aufgrund der Charakteristik der Aufgabe besteht die Gefahr, bei Fehlern in der Implementierung in eine Endlosschleife zu geraten. Wenn das Terminal nach dem Ausführen Ihres Programms hängen bleibt, können Sie das laufende Programm mit `STRG+C` beenden.

## Testen

Ihr Programm sollte sich hinsichtlich der Ein- und Ausgabe wie unter [Verhalten bei Ein- und Ausgabe](#verhalten-bei-ein--und-ausgabe) gezeigt verhalten.

Wichtig ist auch, dass die Buchstaben, die nacheinander ausgegeben werden, nicht bei jedem Programmaufruf gleich sind. So sieht es aus, wenn das nicht klappt:
```plaintext
stadtlandfluss2/ $ ./stadtlandfluss2
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 1: N
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 2: W
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 3: L
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: x
stadtlandfluss2/ $ ./stadtlandfluss2
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 1: N
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 2: W
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 3: L
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: x
stadtlandfluss2/ $ ./stadtlandfluss2
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 1: N
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 2: W
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: 
Runde 3: L
Eingabetaste --&gt; Nächste Runde starten, &#39;Ende&#39; oder &#39;x&#39; --&gt; Programm beenden: x
stadtlandfluss2/ $ 
```

Schauen Sie sich in diesem Fall noch einmal die Verwendung von `srand()` im [Handbuch](https://manual.cs50.io/3/srandom) an.

Lassen Sie das Programm die Buchstaben für alle 26 Runden ausgeben und achten Sie darauf, ob Sie mehrfach ausgegebene Buchstaben bemerken. Wiederholen Sie dies gegebenenfalls einige Male. Wenn Sie ein sinnvolles Vorgehen gefunden und implementiert haben, um die Einmaligkeit der ausgegebenen Buchstaben zu erzwingen, sollte Ihr Programm - wenn es kompiliert und bei der Ausführung nicht in einer Endlosschleife hängen bleibt - auch in dieser Hinsicht normalerweise korrekt funktionieren, so dass Sie nicht alle 26 ausgegebenen Buchstaben genauestens auf Einmaligkeit vergleichen müssen.

### Korrektheit

Führen Sie in Ihrem Terminal den folgenden Befehl aus, um die Korrektheit Ihrer Arbeit zu überprüfen:

```bash
check50 -l inf-zone/exercises/2026/stadtlandfluss/random
```

## Abgeben

Geben Sie im Ordner `stadtlandfluss2` ab:

```bash
inf upload stadtlandfluss/random
```

Die Abgabe ist freiwillig und zählt nicht für die Bonuspunkte. Sie sehen danach, welche Tests Ihr Programm besteht. Wie Sie `inf` installieren und sich anmelden, steht unter [Abgeben mit `inf`](https://dev.inf.zone/faq/uebung-solutions/#inf-installieren).
