Mario

Aufgabe

Gegen Ende von Welt 1-1 in Nintendos Super Mario Bros. muss Mario eine rechts ausgerichtete Pyramide aus Steinen erklimmen, wie in der folgenden Abbildung.

Bildschirmfoto von Mario, der eine rechts ausgerichtete Pyramide hochspringt

Wir wollen in dieser Aufgabe eine solche Pyramide über die Konsolenausgabe eines Programmes nachbilden, indem wir Hashes (#) für die Steine verwenden, wie im Folgenden gezeigt:

       #
      ##
     ###
    ####
   #####
  ######
 #######
########

Allerdings sollte der Benutzer gebeten werden, die tatsächliche Höhe der Pyramide mit int anzugeben, damit das Programm auch kürzere Pyramiden ausgeben kann. Zum Beispiel eine dreistufige:

  #
 ##
###

Wenn die Eingabe des Benutzers nicht größer als 0 oder kein int ist, fordern Sie ihn immer wieder erneut auf, eine passende Eingabe zu tätigen.

Implementieren Sie dieses Programm in C in einer Datei namens mario.c in einem Ordner namens mario.

ℹ️
Prüfen Sie vor der Erstellung eines neuen Ordners mittels mkdir mario mit dem Befehl pwd, in welchem Verzeichnis Sie aktuell befinden. Wenn Sie diese Aufgabe im Anschluss an Hello, It’s Me bearbeiten, befinden Sie sich vermutlich noch in me. Um in der Verzeichnisstruktur wieder nach oben zu gelangen, können Sie cd ../ eingeben. Anschließend können Sie alle Schritte für die Erstellung von Ordner und Datei analog zu Hello, It’s Me wiederholen.
Tipps
  • Erinnern Sie sich, dass Sie einen int von einem Benutzer mit get_int erhalten können, das in cs50.h deklariert ist (siehe manual.cs50.io). Wie verhält sich die Funktion laut Beschreibung im Handbuch, wenn kein int eingegeben wird?
  • Erinnern Sie sich, dass Sie einen string mit printf ausgeben können, das in stdio.h deklariert ist.

Demo

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.

Beginnen Sie mit Code, der kompilierbar ist

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

#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.

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

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

    // Print a pyramid of that height
}
⚠️
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:

#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:

#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):

#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:

#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:

#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):

#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

Funktioniert Ihr Code wie vorgesehen, wenn Sie folgendes eingeben:

  • -1 oder andere negative Zahlen?
  • 0?
  • 1 oder andere positive Zahlen?
  • Buchstaben oder Wörter?
  • überhaupt keine Eingabe, wenn Sie nur Enter drücken?

Korrektheit

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

check50 -l cs50/problems/2024/x/mario/less

Style

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

style50 mario.c