Thread: Draw a triangle

  1. #1
    すまん Hikaru's Avatar
    Join Date
    Aug 2006
    Posts
    46

    Draw a triangle

    My book has an exercise that wants me to draw a triangle. Here's the example shape.
    Code:
        *
       ***
      *****
     *******
    *********
    But I have to get the height from the keyboard, so it can't aways be 5 lines. I got the right shape by drawing spaces, but I don't think that's the best way. I mean, it's a lot of code for something that simple. How can I make my program better? Here's the C++ code for it.
    Code:
    #include <iostream>
    
    using std::cout;
    
    int main()
    {
        int lengthRow = 1;
        int lengthLine;
    
        cout << "Height of triangle? ";
        std::cin >> lengthLine;
    
        // loop includes 0, so take 1 away for right number of lines
        --lengthLine;
    
        // draw triangle with lengthLine lines
        for (int line = lengthLine; line >= 0; --line)
        {
            // draw smaller number of spaces each time
            for (int margin = 0; margin < line; ++margin)
            {
                cout << " ";
            }
    
            // draw greater number of stars each time
            for (int row = 0; row < lengthRow; ++row)
            {
                cout << "*";
            }
    
            cout << "\n";
            lengthRow += 2; // add one star to each side
        }
    
        return 0;
    }
    Thank you!

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > cout << "Height of triangle? ";
    > std::cin >> lengthLine;
    So why didn't you call your variable heightOfTriangle ?

    Then derive from that another variable called lengthRow?

    > How can I make my program better?
    Both printing for loops do the same thing, so create a function, say
    Code:
    void draw ( char ch, int len ) {
      for ( int i = 0 ; i < len ; i++ ) cout << ch;
    }
    Which would simplify your main loop to
    Code:
    draw( ' ', line );
    draw( '*', lengthRow );
    Better is subjective, and measured in many different ways rather than just counting how many characters are in your source file.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2006
    Location
    Latvia
    Posts
    102
    You can do with I/O manip too:
    Code:
    #include <iomanip>
    #include <iostream>
    using namespace std;
    int height;
    int chrsk = 1;
    int crntst = 0;
    char chr;
    int i = 0;
    void resetVars(){
    height = 0;
    chr = 0;
    i = 0;
    crntst = 0;
    chrsk = 1;
    }
    int main()
    {
    char endsequence='n';
    do{
    system("cls");
    resetVars();
    cout<<"Enter height: \n";
    cin>>height;
    cin.ignore();
    cout<<"Enter symbol: \n";
    cin>>chr;
    cin.ignore();
    cout<<"Generating triangle...\n";
    do{
    cout<<setfill(' ')<<setw(height-crntst)<<" "<<setfill(chr)<<setw(chrsk)<<chr<<endl;
    crntst++;
    chrsk = chrsk + 2;
    i++;
    }
    while(i!=height);
    cin.ignore();
    cout<<"Again? y/n \n";
    cin>>endsequence;
    cin.ignore();
    }
    while (endsequence=='y');
    }

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    *cough* indent *cough*
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    You can look at the exercise from a conceptual manner too.

    The first thing that can strike you is that you are being asked to draw spaces and asterisks. So in fact you are being asked to draw a rectangle. And you even already have one of the sizes; the number of lines gives you the height. You can then expand on this concept to devise the formula that will enable you to know the width. For that, you now need to look at the triangle itself.

    You need to find a pattern you can use as a formula. For that, why not start with the last line and see what properties we can find as we move up the triangle? We could also start from the top. However, patterns are usually less challenging when working with bigger numbers and they can also break when we work with the number 1 or 0. e.q. More often than not we need to create an exception when the significant element of the formula (the element that grows or shrinks) is 1 or 0. So it's easier to start from the bottom where the bigger numbers are and then see if that exception needs to be created.

    So... the last line in your example is line 5 and it has 9 asterisks. The height of your rectangle is 5 and the width is 9. Next...

    Code:
    (line 5, height = 5, width = 9)
    line 4, height = 4, width = 7
    line 3, height = 3, width = 5
    line 2, height = 2, width = 3 
    line 1, height = 1, width = 1
    What can we see as a pattern? Before you read further on, take some time to try and see it yourself...






    Well, each line width is equal to line_height * 2 - 1. And it even works with 1! Although it will break with 0. You cannot have -1 asterisks.

    So... with that formula you can now easily create your triangle with just one for loop. The best way is to first store the width in an integer before you enter the loop. Each line will be equal to:

    (overall_width - line_width) / 2 in spaces concatenated to,
    line_width in asterisks concatenated to,
    (overall_width - line_width) / 2 in spaces.

    The only other care you will need to have is to either not accept 0 as an input for the height of the triangle or accept it, but output an empty string.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #6
    すまん Hikaru's Avatar
    Join Date
    Aug 2006
    Posts
    46
    Quote Originally Posted by Salem
    > cout << "Height of triangle? ";
    > std::cin >> lengthLine;
    So why didn't you call your variable heightOfTriangle ?

    Then derive from that another variable called lengthRow?
    I added keyboard input after getting the loops to work. I like your name better.
    Quote Originally Posted by Salem
    Both printing for loops do the same thing, so create a function, say
    Code:
    void draw ( char ch, int len ) {
      for ( int i = 0 ; i < len ; i++ ) cout << ch;
    }
    Which would simplify your main loop to
    Code:
    draw( ' ', line );
    draw( '*', lengthRow );
    I think I understand. But doesn't that still do the same thing? I thought that there would be a way to choose where to draw on the screen. Drawing spaces doesn't seem very clean.
    You can do with I/O manip too:
    Sorry, but I don't understand any of that.
    Well, each line width is equal to line_height * 2 - 1. And it even works with 1! Although it will break with 0. You cannot have -1 asterisks.

    So... with that formula you can now easily create your triangle with just one for loop. The best way is to first store the width in an integer before you enter the loop. Each line will be equal to:

    (overall_width - line_width) / 2 in spaces concatenated to,
    line_width in asterisks concatenated to,
    (overall_width - line_width) / 2 in spaces.

    The only other care you will need to have is to either not accept 0 as an input for the height of the triangle or accept it, but output an empty string.
    I see the pattern, but I couldn't figure out how to draw the triangle like you said with just one loop. I remembered reading something about strings in my book, and with the pattern you found, I did this. I had to copy a bunch of stuff from the book though, and I'm not sure I really understand how it works...
    Code:
    #include <iostream>
    #include <string>
    
    using std::cout;
    using std::string;
    
    int main()
    {
        int heightTriangle;
    
        cout << "Height of triangle? ";
        std::cin >> heightTriangle;
    
        // draw triangle with heightTriangle lines
        for (int line = 1; line <= heightTriangle; ++line)
        {
            // Create a string with less spaces each time
            string spaces(heightTriangle - line, ' ');
    
            // Create a string with more stars each time
            string stars(line * 2 - 1, '*');
            string lineToPrint = spaces + stars;
    
            cout << lineToPrint << "\n";
        }
    
        return 0;
    }
    It's not really a square. Is that okay? It also doesn't have any problems with 1 or 0, but how would I not accept 0 if it did?

  7. #7
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Use append(), for instance, and work with the formulas you discovered.

    Code:
    int height = 5 // this value you get from the user input
    int width = height * 2 - 1  // this is the formula you discovered
    
    std::string yourString = "";  // initialize the string
    for(int i = 1; i <= height; ++i ) {
        yourString.append(spaces_formula_result, ' ')
        yourString.append(asterisks_formula_result, '*')
        yourString.append(spaces_formula_result, ' ')
        yourString.append('\n')
    }
    I'm not writing it all to you on purpose. But do let me know if there is anything specific you didn't understand on my previous post.

    EDIT: you don't need to use strings if you don't want to. You can still use std::cout.

    Code:
    #include <iomanip>
    
    for(int i = 1; i <= height; ++i ) {
        std::cout << setw(spaces_formula_result) << setfill(' ');
        std::cout << setw(asterisks_formula_result) << setfill('*');
        std::cout << setw(spaces_formula_result) << setfill(' ');
        std::cout << std::endl;
    }
    Last edited by Mario F.; 08-13-2006 at 09:49 AM.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > But doesn't that still do the same thing?
    Of course it does, the point was to show that you can extract similarity in duplicate code by adding parameters.

    > I thought that there would be a way to choose where to draw on the screen
    But where do you stop?
    - position on screen
    - change the font
    - change colours
    - animation / sound
    Yes you can add all these things (and more), but the code will grow to do this.

    Book exercises test understanding of fundamental ideas, and this one is about loops.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    すまん Hikaru's Avatar
    Join Date
    Aug 2006
    Posts
    46
    I understand, and now I have tons of new stuff to look up. Thank you everyone for your help.

    p.s. I finally managed to get the iomanip stuff to work. Here's what I came up with.
    Code:
    #include <iomanip>
    #include <iostream>
    
    using std::cout;
    using std::setw;
    using std::setfill;
    
    int main()
    {
        int heightTriangle;
    
        cout << "Height of triangle? ";
        std::cin >> heightTriangle;
    
        // highest possible number of spaces
        const int width = (heightTriangle * 2 - 1) / 2;
    
        for (int line = 1; line <= heightTriangle; ++line)
        {
            // number of stars in this line
            const int widthLine = line * 2 - 1;
    
            cout << setw(width - widthLine / 2) << setfill(' ') << "";
            cout << setw(widthLine) << setfill('*') << "";
            cout << "\n";
        }
    
        return 0;
    }
    The only way I could get it to work is by drawing empy strings. If I didn't do that then nothing would happen or the shape would be wrong. Can anyone point me to something that explains why? Thanks!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Recursive Triangle Function
    By w2look in forum C Programming
    Replies: 14
    Last Post: 11-13-2010, 02:31 PM
  2. Right Triangle Program
    By BSmith4740 in forum C# Programming
    Replies: 9
    Last Post: 02-27-2008, 12:24 AM
  3. Which is the better way to draw?
    By g4j31a5 in forum Game Programming
    Replies: 16
    Last Post: 01-22-2007, 11:56 PM
  4. Just in case: "Odd" Triangle Challenge (for me)
    By BB18 in forum C Programming
    Replies: 3
    Last Post: 10-09-2004, 12:02 AM
  5. How to draw an euqilateral triangle.
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 10-20-2001, 05:10 PM