# Mario

Quelle: https://dev.inf.zone/exercises/02/mario/

[Video auf YouTube](https://www.youtube.com/watch?v=cWOkHQXw0JQ)

## Aufgabe

**Auf einen Blick**

- **Was:** Ein Programm, das eine rechtsbündige Pyramide aus `#` in der Höhe ausgibt, die der Benutzer eingibt.
- **Datei:** `mario.c` in einem Ordner `mario`.
- **Eingabe:** die Höhe als ganze Zahl (`Height: 3`). Bei einer Zahl kleiner als 1 oder einer Eingabe, die gar keine Zahl ist, fragt das Programm erneut.
- **Ausgabe:** die Pyramide, eine Zeile pro Stufe: bei Höhe 3 also drei Zeilen mit 1, 2 und 3 Steinen.

### So ist die Pyramide aufgebaut

Gegen Ende von Welt 1-1 in Nintendos [Super Mario Bros.](https://de.wikipedia.org/wiki/Super_Mario_Bros.) muss Mario eine solche Pyramide aus Steinen erklimmen. Im Terminal wird jeder Stein zu einem `#`.

![Bildschirmfoto von Mario, der eine rechts ausgerichtete Pyramide hochspringt](https://dev.inf.zone/exercises/02/mario/pyramid.png)

Für eine Pyramide der Höhe \(h\) gilt:

1. Die Pyramide hat \(h\) Zeilen.
2. In Zeile \(i\) (von oben gezählt, beginnend bei 1) stehen \(i\) Steine `#`.
3. Davor stehen \(h - i\) Leerzeichen. So ist jede Zeile genau \(h\) Zeichen breit, und die Steine stehen rechtsbündig.
4. Nach dem letzten `#` einer Zeile folgt nur der Zeilenumbruch, kein Leerzeichen.

**Beispiel** mit Höhe \(h = 4\) (`·` steht hier für ein Leerzeichen):

| Zeile \(i\) | Leerzeichen \(4 - i\) | Steine \(i\) | Ausgabe |
| ----------- | --------------------- | ------------ | ------- |
| 1           | 3                     | 1            | `···#`  |
| 2           | 2                     | 2            | `··##`  |
| 3           | 1                     | 3            | `·###`  |
| 4           | 0                     | 4            | `####`  |

## Demo

[Terminal-Aufzeichnung ansehen](https://asciinema.org/a/WPrv7PFVLaLkJ2BU96uTEQKuA)

## Ordner und Datei anlegen

Wie bei [Hello, It's Me](https://dev.inf.zone/exercises/01/hello-me/#schritt-für-schritt), nur mit anderem Namen. Mit `cd` kommen Sie zuerst aus dem Ordner `me` zurück in Ihr Homeverzeichnis (Eingabeaufforderung `$`):

```bash
cd
mkdir mario
cd mario
code mario.c
```

## Hilfestellung

Klicken Sie auf die folgenden Tipps, um einige Ratschläge zu erhalten. Versuchen Sie aber zunächst, selbst so weit wie möglich zu kommen.

**Nützliche Funktionen**

-   Einen `int` vom Benutzer bekommen Sie mit `get_int`, deklariert in `cs50.h` (siehe [manual.cs50.io](https://manual.cs50.io/3/get_int)). Wie verhält sich die Funktion laut Handbuch, wenn kein `int` eingegeben wird?
-   Einen `string` geben Sie mit `printf` aus, deklariert in `stdio.h`.

**Beginnen Sie mit Code, der kompilierbar ist**

Auch wenn dieses Programm noch nichts tut, sollte es zumindest mit `make` kompiliert werden können!

```c
#include <cs50.h>
#include <stdio.h>

int main(void)
{

}
```

Denken Sie daran, dass Sie jetzt `cs50.h` und `stdio.h` eingebunden haben, zwei „Header-Dateien“, die Ihnen Zugang zu Funktionen geben, die Ihnen bei der Lösung dieses Problems helfen könnten.

**Versuchen Sie das Problem in Pseudocode zu beschreiben**

Wenn Sie unsicher sind, wie Sie das eigentliche Problem lösen können, unterteilen Sie es in kleinere Probleme, die Sie wahrscheinlich einfacher lösen können. Im Kern besteht diese Aufgabe eigentlich aus zwei Problemen:

1. Die Aufforderung an den Benutzer, die Höhe der Pyramide einzugeben.
2. Das Ausgeben einer Pyramide mit dieser Höhe.

Fügen Sie die identifizierten Probleme nun in Form von Pseudocode als Kommentare ein, um sie dann nacheinander bearbeiten zu können.

```c
#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Prompt the user for the pyramid's height

    // Print a pyramid of that height
}
```

> [!WARNING]
> Der letzte Tipp zeigt Ihnen Schritt für Schritt den Großteil einer möglichen Lösung. Idealerweise schauen Sie sich diesen erst an, nachdem Sie die Aufgabe bearbeitet haben - oder zumindest ernsthaft versucht haben, die Aufgabe zu bearbeiten.

**Wandeln Sie den Pseudocode in Code um**

Überlegen Sie zunächst, wie Sie den Benutzer nach der Höhe der Pyramide fragen können. Erinnern Sie sich daran, dass eine `do while`-Schleife hilfreich ist, wenn Sie etwas mindestens einmal und möglicherweise immer wieder tun wollen, wie in dem folgenden Beispiel:

```c
#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
}
```

Überlegen Sie sich nun, wie Sie eine Pyramide mit dieser Höhe von **oben** nach **unten** ausgeben könnten. Beachten Sie, dass die erste Reihe (von oben betrachtet) aus einem Stein bestehen sollte, die zweite Reihe aus zwei Steinen und so weiter. Wahrscheinlich denken Sie bereits an eine Schleife, auch wenn Sie (noch!) nicht wissen, was Sie in diese Schleife einfügen sollen. Fügen Sie also erst einmal etwas mehr Pseudocode als Kommentar hinzu:

```c
#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
    for (int i = 0; i < height; i++)
    {
        // Print row of bricks
    }
}
```

Wie kann man diese Reihe von Steinen ausdrucken? Nun, wäre es nicht schön, wenn es eine Funktion namens `print_row` gäbe, die genau das tun könnte? Nehmen wir an, es gäbe sie (vergessen Sie nicht den Funktionsprototypen oberhalb der `main`-Funktion einzufügen, wenn Sie die Funktion unterhalb der `main`-Funktion definieren):

```c
#include <cs50.h>
#include <stdio.h>

void print_row(int bricks);

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
    for (int i = 0; i < height; i++)
    {
        // Print row of bricks
    }
}

void print_row(int bricks)
{
    // Print row of bricks
}
```

Wir können diese Funktion dann von `main` aus innerhalb der `for`-Schleife aufrufen, wie im Folgenden gezeigt:

```c
#include <cs50.h>
#include <stdio.h>

void print_row(int bricks);

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
    for (int i = 0; i < height; i++)
    {
        // Print row of bricks
        print_row(i + 1);
    }
}

void print_row(int bricks)
{
    // Print row of bricks
}
```

Warum aber `i + 1`?

Versuchen wir zuerst einmal `print_row` zu implementieren:

```c
#include <cs50.h>
#include <stdio.h>

void print_row(int bricks);

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
    for (int i = 0; i < height; i++)
    {
        // Print row of bricks
        print_row(i + 1);
    }
}

void print_row(int bricks)
{
    for (int i = 0; i < bricks; i++)
    {
        printf("#");
    }
    printf("\n");
}
```

Wissen Sie, wofür ein `\n` am Ende ausgegeben wird?

Leider gibt dieser Code eine linksbündige Pyramide aus. Wir wollen aber eine rechtsbündige! Vielleicht könnten wir vor einige der Steine ein paar Leerzeichen setzen, um sie nach rechts zu verschieben? Ergänzen wir also `print_row` wie folgt (vergessen Sie nicht den Funktionsprototypen oberhalb der `main`-Funktion entsprechend zu ergänzen):

```c
#include <cs50.h>
#include <stdio.h>

void print_row(int spaces, int bricks);

int main(void)
{
    // Prompt the user for the pyramid's height
    int height;
    do
    {
        height = get_int("Height: ");
    }
    while (height < 1);

    // Print a pyramid of that height
    for (int i = 0; i < height; i++)
    {
        // Print row of bricks
    }
}

void print_row(int spaces, int bricks)
{
    // Print spaces

    // Print bricks
}
```

Überlegen Sie sich nun also noch, wie Sie möglichst geschickt die Leerzeichen übergeben und ausgeben können. Und überlegen Sie sich zusätzlich, ob Sie nicht auch einen Teil des Codes in `main` in eine `get_height`-Funktion auslagern könnten, die den benötigten `int` zurückgibt!

## Testen

Testen Sie Ihr Programm von Hand mit diesen Eingaben:

| Eingabe                              | erwartetes Verhalten       |
| ------------------------------------ | -------------------------- |
| `-1` oder eine andere negative Zahl  | fragt erneut nach der Höhe |
| `0`                                  | fragt erneut nach der Höhe |
| Buchstaben oder Wörter, z. B. `cat`  | fragt erneut nach der Höhe |
| gar nichts, nur Enter                | fragt erneut nach der Höhe |
| `1`                                  | eine Zeile: `#`            |
| `8`                                  | die Pyramide unten         |

```
Height: 8
       #
      ##
     ###
    ####
   #####
  ######
 #######
########
```

### 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/mario
```

### Style

Führen Sie den folgenden Befehl aus, um den Stil Ihres Codes mit `style50` zu analysieren:

```bash
style50 mario.c
```

## Abgeben

Geben Sie im Ordner `mario` ab:

```bash
inf upload mario
```

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