CS50x Mario

From problem set 1. Both less and more versions.

Guilherme Pirani
5 min readOct 7, 2020
Photo by Cláudio Luiz Castro on Unsplash

On Mario problem set we need to create a terminal version of the famous pyramids from Super Mario World. The catch is that the pyramid must be responsive to the user inputs. He is deciding it’s height.

Take a look at the given output sample.

$ ./mario
Height: -1
Height: 0
Height: 42
Height: 50
Height: 4
#
##
###
####

There are two options for this problem. One for those more comfortable with the code, other for those less comfortable. Preparing our folder:

~/ $ mkdir pset1 (only if you don't yet have the folder)
~/ $ cd pset1
~/pset1/ $ mkdir mario
~/pset1/ $ cd mario
~/pset1/mario/ $ touch mario.c
~/pset1/mario/ $ open mario.c

Which steps do we need to take to reach the example output? Making that clear in pseudocode may help.

// Prompt user for a height value
// Make sure value is valid
// Draw pyramid

Wow, looks simple. How hard can it be to print hashes # to the screen?

We know that the program needs input and output, so definitely stdio is in our header. CS50 is also a must as it simplifies a lot of tasks C doesn’t facilitate to new users. Those are the basic, if we happen to need another we can always add it later. I’m also adding the prototypes for the functions I visualized on the pseudocode, as well their places considering the steps we imagined necessary. So the base…

#include <stdio.h>
#include <cs50.h>
int getValue();
void draw(int height);
int main (void)
{
int height = getValue();
draw(height);
}

For our input, I’m creating a function which returns a valid height value. I’m also preparing the skeleton for the draw function so I can begin testing the code. The problem specifies that the height value must be between 1 an 8, inclusive, so we need to make sure to check that too.

int getValue()
{
int a;
do
{
a = get_int("Height: ");
}
while (a < 1 || a > 8);;

return a;
}
void draw(int height)
{

}

With that in place, we can compile and make sure our getValue function is working properly. I did it, why don’t you do it too? Check it against the expected behavior.

$ make mario

$ ./mario
Height: -1
Height: 0
Height: 42
Height: foo
Height: 4

NICE! That was the easy part, now let’s procced to the draw function. Here’s where the less and more comfortable approaches diverge. Let’s start with less comfy.

for (int row = 0; row < height; row++)
{
for (int spaces = row + 1; spaces < height; spaces++)
{
printf(" ");
}

for (int hashes = height + row + 1; hashes > height; hashes--)
{
printf("#");
}
printf("\n");
}

A bit confusing, but it came from my mind, what’d you expect? I’m going to try to explain.

The “Mother Loop” is our End of Line loop, it has two uses: A. Press Enter; B. Be a number. It starts at 0 and we need it to grow by 1 and stop when it reaches height.

The 1st Nested Loop prints our spaces, so our pyramid can keep the orientation that the problem requires. It is 1 bigger than the Mother Loop, meaning that it’s going to reach height 1 iteration before. So if height is 4, the 1st Nested Loop is going to run 3 times, against 4 from the Mother loop. When the Mother Loop runs again and row becomes 1, the 1st Nested Loop is going to run 2 times. The last time the Mother Loop runs it will simple jump through these lines of code, because the base of the pyramid has no spaces.

The 2nd Nested Loop prints our #, i.e. the actual pyramid. It goes backwards from the 1st loop. Here we want to increase the number of # every time the Mother Loops runs. To make that work we initialize hashes to the value of height + row + 1, being height 4, our first iteration starts at 5 (remember row starts as 0) and in this case we want hashes to decrease by 1 each time it runs. It means that after printing # to our first line, it will check again and see that now hashes and height have the same value, and stop. When the Mother Loop runs again, this time the 2nd Nested Loop is going to print two # before stopping. The last run through will print the same number of # as the value of height.

Here’s the staff tests for the less comfortable version and the full code with comments.

Results generated by style50 v2.7.4
Looks good!
Results for cs50/problems/2020/x/mario/less generated by check50 v3.1.2
:) mario.c exists
:) mario.c compiles
:) rejects a height of -1
:) rejects a height of 0
:) handles a height of 1 correctly
:) handles a height of 2 correctly
:) handles a height of 8 correctly
:) rejects a height of 9, and then accepts a height of 2
:) rejects a non-numeric height of "foo"
:) rejects a non-numeric height of ""

Notice how our main function stayed exactly how we first wrote it.

Proceeding now to the more comfortable version of the problem. Fortunately we can keep working on our less comfortable code, as the harder version is just adding another pyramid besides our old one. As seen in the example:

$ ./mario
Height: -1
Height: 0
Height: 42
Height: foo
Height: 4
# #
## ##
### ###
#### ####

Keep in mind that the problems have the same name, so if you want to keep your old code make a copy of it after submitting. We’re overwriting it now.

The only change we need to make is inside our draw functions. Adding some lines should do the trick. Now we need add more spaces instead of breaking the line (two actually), and to add another loop for the new pyramid. No need for more spaces after the hashes, it’s where our new break line goes.

Between the end of the 2nd Nested Loop and the Printf(“\n”) function, add these lines:

printf("  ");

for (int hashes = height + row + 1; hashes > height; hashes--) {
printf("#");
}

Notice that this new loop is actually just a copy of the 2nd Nested Loop. So we ended up writing just a simple printf function to go from less to more comfortable. It’s true, look:

Results for cs50/problems/2020/x/mario/more generated by check50 v3.1.2
:) mario.c exists
:) mario.c compiles
:) rejects a height of -1
:) rejects a height of 0
:) handles a height of 1 correctly
:) handles a height of 2 correctly
:) handles a height of 8 correctly
:) rejects a height of 9, and then accepts a height of 2
:) rejects a non-numeric height of "foo"
:) rejects a non-numeric height of ""

All right, all right, there’s no fun to it. I know. I won’t even bother uploading the full code for that if you don’t mind.

I’ve been trying to implement recursion on this problem with no success so far.

--

--