4
\$\begingroup\$

Problem Statement:

The Christmas tree is comprised of the following Parts Stand Each Part is further comprised of Branches. Branches are comprised of Leaves.

How the tree appears as a function of days should be understood. Basis that print the tree as it appears on the given day. Below are the rules that govern how the tree appears on a given day. Write a program to generate such a Christmas tree whose input is number of days.

Rules

1.If tree is one day old you cannot grow. Print a message "You cannot generate christmas tree"

2.Tree will die after 20 days; it should give a message "Tree is no more"

3.Tree will have one part less than the number of days.

E.g.

On 2nd day tree will have 1 part and one stand.

On 3rd day tree will have 2 parts and one stand

On 4th day tree will have 3 parts and one stand and so on.

4.Top-most part will be the widest and bottom-most part will be the narrowest.

5.Difference in number of branches between top-most and second from top will be 2

6.Difference in number of branches between second from top and bottom-most part will be 1

Below is an illustration of how the tree looks like on 4th day

enter image description here

Input Format:

First line of input contains number of days denoted by N

Output Format:

Print Christmas Tree for given N

OR

Print "You cannot generate christmas tree" if N <= 1

OR

Print "Tree is no more" if N > 20

Constraints:

0<= N <=20

Sample Input and Output

Input: 2

Output:( below)

enter image description here

The code:

#include<stdio.h>

int main(){
    int i,j,leaves=1,day,rest,branches,max_leaves;
    scanf("%d",&day);

    //Check for exceptions
    if(day<=1){
        printf("You cannot generate christmas tree");
        return 0;
    }
    else if(day>20){
        printf("Tree is no more");
        return 0;
    }

    // printf("Heres Your Christmas Tree:\n\n");

    // For first part
    branches=day+1;
    max_leaves = 1+(branches-1)*2; // Arithmetic Progression
    for(i=1;i<=branches;i++){
        for(j=i;j<=max_leaves/2;j++){
            printf(" ");
        }
        for(j=1;j<=leaves;j++){
            printf("*");
        }
        printf("\n");
        leaves=leaves+2;
    }

    // For remaining parts
    branches=branches-2;
    for(rest=1;rest<=day-2;rest++){
        leaves=3;
        for(i=2;i<=branches+1;i++){
            for(j=i;j<=max_leaves/2;j++){
                printf(" ");
            }
            for(j=1;j<=leaves;j++){
                printf("*");
            }
            printf("\n");
            leaves=leaves+2;
        }
        branches--;
    }

    // For stand
    for(i=1;i<=2;i++){
        for(j=1;j<=max_leaves/2;j++){
            printf(" ");
        }
        printf("*\n");
    }

    return 0;
}

The code is working fine as can be checked on IDEOne.

\$\endgroup\$
4
\$\begingroup\$

Keep the scope of variables to a minimum

Since C99 we are allowed to mix declaration and code. At the moment, you have i, j, rest and so on in scope, even if day is out of the specification. That can lead to hard to find errors, for example if we accidentally use i++ where i isn't used.

Late declaration makes it easier to copy our code into other blocks also, but more on that later. So instead, let's push the declaration as late as possible and limit the scope:

#include<stdio.h>

int main(){
    int day;
    scanf("%d",&day);

    //Check for exceptions
    if(day<=1){
        printf("You cannot generate christmas tree");
        return 0;
    }
    else if(day>20){
        printf("Tree is no more");
        return 0;
    }

    // printf("Heres Your Christmas Tree:\n\n");

    // For first part
    int leaves=1;
    int branches=day+1;
    int max_leaves = 1+(branches-1)*2; // Arithmetic Progression
    for(int i=1;i<=branches;i++){
        for(int j=i;j<=max_leaves/2;j++){
            printf(" ");
        }
        for(int j=1;j<=leaves;j++){
            printf("*");
        }
        printf("\n");
        leaves=leaves+2;
    }

    // For remaining parts
    branches=branches-2;
    for(int rest=1;rest<=day-2;rest++){
        leaves=3;
        for(int i=2;i<=branches+1;i++){
            for(int j=i;j<=max_leaves/2;j++){
                printf(" ");
            }
            for(int j=1;j<=leaves;j++){
                printf("*");
            }
            printf("\n");
            leaves=leaves+2;
        }
        branches--;
    }

    // For stand
    for(int i=1;i<=2;i++){
        for(int j=1;j<=max_leaves/2;j++){
            printf(" ");
        }
        printf("*\n");
    }

    return 0;
}

Use whitespace to scan code quickly

Now that we've introduced late declarations, let us add some whitespace between operators. Gone are the days where bytes in source code where expensive. Unless you intend write-only code, make code easy to read. Debugging is much nicer in well-written and spaced code:

#include <stdio.h>

int main() {
    int day;
    scanf("%d", &day);

    // Check for exceptions
    if (day <= 1) {
        printf("You cannot generate christmas tree");
        return 0;
    } else if (day > 20) {
        printf("Tree is no more");
        return 0;
    }

    // printf("Heres Your Christmas Tree:\n\n");

    // For first part
    int leaves = 1;
    int branches = day + 1;
    int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
    for (int i = 1; i <= branches; i++) {
        for (int j = i; j <= max_leaves / 2; j++) {
            printf(" ");
        }
        for (int j = 1; j <= leaves; j++) {
            printf("*");
        }
        printf("\n");
        leaves = leaves + 2;
    }

    // For remaining parts
    branches = branches - 2;
    for (int rest = 1; rest <= day - 2; rest++) {
        leaves = 3;
        for (int i = 2; i <= branches + 1; i++) {
            for (int j = i; j <= max_leaves / 2; j++) {
                printf(" ");
            }
            for (int j = 1; j <= leaves; j++) {
                printf("*");
            }
            printf("\n");
            leaves = leaves + 2;
        }
        branches--;
    }

    // For stand
    for (int i = 1; i <= 2; i++) {
        for (int j = 1; j <= max_leaves / 2; j++) {
            printf(" ");
        }
        printf("*\n");
    }

    return 0;
}

By the way, your text editor should provide some automatic format feature. I formatted the code with clang-format -style="{BasedoNStyle: llvm, IndentWidth: 4}", since that's very similar to your variant.

Don't repeat yourself

Now that we have easy to read code, we can see that there are repeating patterns, namely

for(int k = init; k <= stop; k++) {
    printf("some string");
}

We have at least five occurrences. So let's write a small function:

void repeat_string(int times, const char* str) {
    for(int i = 0; i < times; ++i) {
        printf("%s",str);
    }
}

Let's replace all occurrences of your loop with the function:

#include <stdio.h>

void repeat_string(int times, const char* str) {
    for(int i = 0; i < times; ++i) {
        printf("%s",str);
    }
}

int main() {
    int day;
    scanf("%d", &day);

    // Check for exceptions
    if (day <= 1) {
        printf("You cannot generate christmas tree");
        return 0;
    } else if (day > 20) {
        printf("Tree is no more");
        return 0;
    }

    // printf("Heres Your Christmas Tree:\n\n");

    // For first part
    int leaves = 1;
    int branches = day + 1;
    int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression

    for (int i = 1; i <= branches; i++) {
        repeat_string(max_leaves / 2 - i, " ");
        repeat_string(leaves, "*");
        printf("\n");
        leaves = leaves + 2;
    }

    // For remaining parts
    branches = branches - 2;
    for (int rest = 1; rest <= day - 2; rest++) {
        leaves = 3;
        for (int i = 2; i <= branches + 1; i++) {
            repeat_string(max_leaves / 2 - i, " ");
            repeat_string(leaves, "*");
            printf("\n");
            leaves = leaves + 2;
        }
        branches--;
    }

    // For stand
    for (int i = 1; i <= 2; i++) {
        repeat_string(max_leaves / 2; " ");
        printf("*\n");
    }

    return 0;
}

Again, it's easier too read. Also, any optimization we find for repeat_string will now help at all five call sites. Great.

Exercises:

  1. Write repeat_character(int n, char c), which prints a single character c a total of n times.
  2. If we look closely, we can see that the branches look very similar:

    for (int i = 1; i <= branches; i++) {           // <---
        repeat_string(max_leaves / 2 - i, " ");     // <---
        repeat_string(leaves, "*");                 // <---
        printf("\n");                               // <---
        leaves = leaves + 2;                        // <---
    }
    
    // For remaining parts
    branches = branches - 2;
    for (int rest = 1; rest <= day - 2; rest++) {
        leaves = 3;                                 
        for (int i = 2; i <= branches + 1; i++) {   // <---
            repeat_string(max_leaves / 2 - i, " "); // <---
            repeat_string(leaves, "*");             // <---
            printf("\n");                           // <---
            leaves = leaves + 2;                    // <---
        }
        branches--;
    }
    

    Write a function that draws a single part, e.g. a trapezoid or pyramid width a given width, height, and so on.

Mark read-only values and locations with const

We denoted the str as const char* in order to make sure that we don't accidentally change string's contents. In the same spirit, we can add const to max_leaves:

…
const int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
…

Now typos like max_leaves /= 2 will get cought by the compiler.

Use 0…(n-1) as range, not 1…n

Your ranges use start = 1; i <= end; start++. Since we often work with arrays in C++ and arrays start with 0, it's more common to work with start = 0; start < end; start++. Keep that in mind for future code.

Other remarks

You mix leaves, branches and max_leaves, but their exact meanings are lost for the unprepared reader. Some additional comments can be helpful.

Other than that, the missing whitespace and therefore code structuring was my biggest criticism, but that's a minor point that can get fixed quickly.

Here's the complete code:

#include <stdio.h>

void repeat_string(int times, const char *str) {
    for (int i = 0; i < times; i++) {
        printf("%s", str);
    }
}

void repeat_character(int times, char c) {
    // Exercise 1
}

void draw_part(int height, int start_width, int max_width) {
    // Exercise 2
}

int main() {
    int day;
    scanf("%d", &day);

    // Check for exceptions
    if (day <= 1) {
        printf("You cannot generate christmas tree");
        return 0;
    } else if (day > 20) {
        printf("Tree is no more");
        return 0;
    }

    // printf("Heres Your Christmas Tree:\n\n");

    // For first part
    int branches = day + 1;
    const int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression

    // For first part
    draw_part(branches, 1, max_leaves);

    // For remaining parts
    branches -= 2;
    for (int rest = 0; rest < day - 2; rest++) {
        draw_part(branches, 3, max_width);
        branches--;
    }

    // For stand
    for (int i = 0; i < 2; i++) {
        repeat_string(max_leaves / 2; " ");
        printf("*\n");
    }

    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ For an arbitrary string printf(str); is a problem should the string contain a %. Suggest printf("%s", str); or fputs(str, stdout); \$\endgroup\$ – chux Jul 30 '18 at 17:55
  • \$\begingroup\$ The "Mark read-only variables with const" has merit, yet the discussion mixes up theconst-ness of what a pointer references to and the object itself. const int max_leaves is like char* const str, not const char* str. \$\endgroup\$ – chux Jul 30 '18 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.