Eine umgedrehte Pyramide zeichnen?


  • Gesperrt

    Hi, könntet ihr einmal schauen, ob das so richtig ist?

    Es soll eine umgedrehte Pyramide aus '*'-Zeichen gemalt werden, also zum Beispiel mit 5 Stufen:

    ********* 
     *******  
      *****   
       ***    
        *     
    

    und mit 3 Stufen:

    ***** 
     ***  
      *   
    

    Code:

    #include <iostream>
    #include <vector>
    #include <string>
    using namespace std;
    
    class OneChar {
      public:
        char16_t c;
        OneChar(char16_t c) : c(c) {
        }
    };
    
    class RowComponent {
      public:
        int pos;
        int len;
        OneChar & c;
        RowComponent(int pos, int len, OneChar & c)
        : pos(pos), len(len), c(c) {
        }
    };
    
    class Row {
      public:
        int n;
        int len;
        OneChar & c;
        vector<RowComponent> components;
        Row(int n, int len, OneChar & c)
        : n(n), len(len), c(c) {
          components.push_back(RowComponent(n, len-2*n-1, c));
        }
        string toString() {
          string str(len, ' ');
          for (auto rc : components) {
            for (int i = rc.pos; i < rc.pos + rc.len; i++) {
              str[i] = rc.c.c;
            }
          }
          return str;
        }
    };
    
    class InvertedPyramid {
      public:
        int len;
        OneChar & c;
        vector<Row> rows;
        InvertedPyramid(int len, OneChar & c)
        : len(len), c(c) {
          for (int i = 0; i < len; i++) {
            rows.push_back(Row(i, 2*len, c));
          }
        }
        string toString() {
          string str;
          for (auto row : rows) {
            str += row.toString() + '\n';
          }
          return str;
        }
    };
    
    int main() 
    {
        char16_t c = '*';
        OneChar oc(c);
        int rows = 0;
        cout << "Anzahl der Stufen:\n";
        cin >> rows;
        cout << InvertedPyramid(rows, oc).toString();
        return 0;
    }
    
    

  • Mod

    Ob das richtig ist oder nicht, kannst du ja hoffentlich selbst entscheiden, wenn du es ausführst, oder?

    Wenn du wissen willst, was man besser machen könnte: Übertreibst du es nicht vielleicht ein bisschen mit dem Datenmodell? Leute werfen mir schon immer vor, ich würde es mit der Modellierung übertreiben, und ich bin geschockt wie sehr du es übertreibst. Eine eigene char-Klasse? Die dann wieder in einer eigenen char-Folgenklasse benutzt wird? Und so weiter? Das Problem wäre ein Dreizeiler wenn du es nicht so übertreiben würdest. Meinetwegen 10 Zeilen, wenn du es in einer Klasse haben möchtest, die das Bild als vector<string> speichert.

    PS: Hallo cyborg_beta!


  • Gesperrt

    War mir fast klar.

    Aber es heißt doch immer, SoC sei sehr wichtig, also habe ich so viele Klassen wie sinnvoll hinzugefügt.


  • Mod

    Ist es denn sinnvoll? Macht OneChar etwas, das char nicht leistet? Macht RowComponent irgendetwas, das der Code in Row nicht schon tut? Braucht es die Zwischenspeicherei in Row? Wenn nicht, macht dann Row überhaupt noch etwas?


  • Gesperrt

    In erster Linie ging es mir darum, ob das technisch "sauber" umgesetzt ist - oder nicht. Erst dann sollte man sich Fragen stellen, ob nicht auch ein Vierzeiler genügt. 😃

    for (auto rc : components) {
    

    ... das muss doch

    for (const auto & rc : components) {
    

    oder so was sein - oder nicht?



  • @sepe sagte in Eine umgedrehte Pyramide zeichnen?:

    In erster Linie ging es mir darum, ob das technisch "sauber" umgesetzt ist - oder nicht. Erst dann sollte man sich Fragen stellen, ob nicht auch ein Vierzeiler genügt. 😃

    Overengineered ist nicht dasselbe wie sauber.

    for (auto rc : components) {
    

    ... das muss doch

    for (const auto & rc : components) {
    

    oder so was sein - oder nicht?

    @sepe Das kommt drauf an was du innerhalb der Schleife vorhast. Wenn du, wie hier, nur liest brauchst du keine Kopien.


  • Gesperrt

    @Tyrdal Was ist mit dem Rest? Wer räumt den ganzen Spaß wieder weg?

    @Tyrdal sagte in Eine umgedrehte Pyramide zeichnen?:

    Das kommt drauf an was du innerhalb der Schleife vorhast. Wenn du, wie hier, nur liest brauchst du keine Kopien.

    Nur lesenden Zugriff.

    Ok, dann sagen wir, wie es ist ... scheiße umgesetzt ...

    Wären die toString()-Methoden überhaupt richtig umgesetzt, oder wären sie auch ein No-go?

    Und der Algorithmus an sich ... ist "Eine Pyramide generieren" nicht eigentlich logisch stark zusammenhängend (ich weiß nicht, wie man das nennt, wenn ein Algorithmus eine Einheit darstellt), sodass das sogar falsch wäre? Also ... dass die zyklomatische Komplexität von zwei ineinander geschachtelten Schleifen in Ordnung wäre?

    Welche Metriken nutzt man dafür, um das zu beurteilen?



  • Es geht auch darum Aufgaben so zu lösen, dass man sie nicht unnötig kompliziert umsetzt. Ein Punkt der bei Dir auffällt ist, dass Du zwar char16_t nutzt, aber dann auf std::cout ausgibst. Entweder komplett wchar_t oder komplett char. An dieser Stelle ist es auch nicht notwendig auf char16_t zurückzugreifen, da die Zeichen allesamt in den unteren 16Bit liegen, und man mit wchar_t sowohl auf Windows (UTF-16 Unicode Kodierung) wie auch auf UNIX/Linux (UTF-32 Unicode Kodierung) Codepoints korrekt ausgeben kann.

    Beispielcode von mir ohne Schleifen dafür mit Rekursion und vordefinierten Feldern. Es geht natürlich auch anders und noch deutlich kompakter.

    #include <iostream>
    #include <cstdlib>
    #include <string>
    
    constexpr int SIZE = 255;
    const std::wstring SPACES(SIZE, L' ');
    const std::wstring STARS (SIZE, L'*');
    
    constexpr int
    steps_to_number_symbols (const int step) {
        return (2 * step) + 1;
    }
    
    void
    print_row(const int step, const int spaces) {
        if (-1 == step) return;
    
        std::wcout << SPACES.substr(0, spaces);
        std::wcout << STARS.substr(0, steps_to_number_symbols(step));
        std::wcout << L'\n';
    
        print_row(step - 1, spaces + 1);
    }
    
    int main() {
        int rows = 0;
        int spaces = 0;
    
        std::wcout << L"Anzahl der Stufen:\n";
        std::wcin  >> rows;
        std::wcout << L'\n';
    
        if (steps_to_number_symbols(rows) > SIZE) {
            std::wcerr << L"Zu viele Stufen...\n";
            return EXIT_FAILURE;
        }
    
        if (0 >= rows) {
            return EXIT_SUCCESS;
        }
    
        print_row(rows - 1, spaces);
    
        return EXIT_SUCCESS;
    }
    


  • @john-0

    int main()
    {
    	static constexpr int Steps = 11;
    	
    	for (int i = 0; i < Steps / 2 + 1; i++)
    		std::cout << std::string(i, ' ') << std::string(Steps - 2 * i, '*') << "\n";
    	return 0;
    }
    

  • Gesperrt

    @john-0 sagte in Eine umgedrehte Pyramide zeichnen?:

    constexpr int
    steps_to_number_symbols (const int step) {
    return (2 * step) + 1;
    }

    Feine Sache. 👍🏻



  • @Quiche-Lorraine Die Spitze ist da aber eher stumpf.



  • @Tyrdal
    Habe es gefixt



  • @Tyrdal
    Wäre interresant ob dies auch als Template oder constexpr Funktion geht.


  • Mod

    @Quiche-Lorraine sagte in Eine umgedrehte Pyramide zeichnen?:

    @Tyrdal
    Wäre interresant ob dies auch als Template oder constexpr Funktion geht.

    So etwas liebe ich, aber das hier ist ja nur eine einzelne Schleife und zu einfach:

    #include <iostream>
    
    using namespace std;
    
    template <unsigned line_no, unsigned height> struct pyramide_impl {
      void operator()() {
        std::cout << std::string(height-line_no, ' ') << std::string(2*height - 2 * (height-line_no), '#') << '\n';
        pyramide_impl<line_no-1, height>()();
     }
    };
    
    template <unsigned height> struct pyramide_impl<0, height> {
      void operator()() { }
    };
    
    template <unsigned steps> struct pyramide
    {
      void operator()()
      {
        pyramide_impl<steps, steps>()();
      }
    };
    
    
    int main()
    {
      const unsigned N=6;
      pyramide<N>()();
    }
    

  • Gesperrt

    @Quiche-Lorraine sagte in Eine umgedrehte Pyramide zeichnen?:

    @Tyrdal
    Wäre interresant ob dies auch als Template oder constexpr Funktion geht.

    Gleiches ginge auch in Java! Man muss da aber, IIRC, noch eine kleine Verrenkung machen, wenn es um rekursive Lambda-Funktionen geht...

    c++ hat da mehr Zucker.

    Hier ... Fakultät: https://stackoverflow.com/a/22953285


Anmelden zum Antworten