This series of problem solving exercises are based on problems found on Codewars https://www.codewars.com/ or Hackerank https://www.hackerrank.com/dashboard.
You should have attended the previous two problem solving sessions. You will have learned the outline procedure for solving problems by:
You will get more practice on that today.
No specific tools are required, although you will need to make notes so either pencil and paper or a text editor on your laptop.
You will be presented with a problem. You will learn how to understand the problem and break the problem down into steps that help you work towards a solution.
Todays problem can be found here: https://www.codewars.com/kata/5b4e779c578c6a898e0005c5.
After the class finishes, you should submit a solution to the problem using the link above.
We want to output a drawing of some stairs.
Given a number n, draw stairs using the letter "I", n tall and n wide, with the tallest in the top left.
We are given two examples.
For example, n = 3
would return:
"I\n␣I\n␣␣I"
If you print that string in a console.log
it would look look like this:
I
␣I
␣␣I
(Note that the ␣ character represents a space and \n
is a newline. These characters are part of a group of characters known as "white space" characters and when printed are invisible. Another white space character is a tab, written as \t
in Javascript. The ␣
is only shown here so that we can see and count spaces. A space intended to be printed like this is part of a string in Javascript so should be surrounded by quote characters. Note that ""
is an empty string where as " "
is a string containing one space.
Another example, a 7-step stairs should be drawn like this:
I
␣I
␣␣I
␣␣␣I
␣␣␣␣I
␣␣␣␣␣I
␣␣␣␣␣␣I
function drawStairs(n) {
// your code here
}
n
, representing the number of steps.space
, I
, and \n
.n
occurences of I
in each string.I
except the final one will be followed by a \n
and a number of spaces to correctly format the string.We are given two examples. Here they are again.
For example, n = 3
would return:
"I\n␣I\n␣␣I"
If you print that string in a console.log
it would look look like this:
I
␣I
␣␣I
Another example, a 7-step stairs should be drawn like this:
I
␣I
␣␣I
␣␣␣I
␣␣␣␣I
␣␣␣␣␣I
␣␣␣␣␣␣I
n
is 1
.n
is 5
.Lets put the examples in order of the value of n
.
When n
is equal to 1
, the return string is:
"I"
When n = 3
the return string is:
"I\n␣I\n␣␣I"
When n
is equal to 5
, the returned string is:
"I\n␣I\n␣␣I\n␣␣␣I\n␣␣␣␣I"
When n
is equal to 7, the returned string is:
"I\n␣I\n␣␣I\n␣␣␣I\n␣␣␣␣I\n␣␣␣␣␣I\n␣␣␣␣␣␣I"
There are some patterns to note:
"I"
\n
following EVERY I
EXCEPT the last. Our solution will need a way of knowing when we are adding the last I
so we don't add too many \n
characters.I
, there is ALWAYS a sequence of one or more spaces before the next I
. Our solution will need a way of calculating the correct number of spaces before the next I
. We might note here that there is ONE space after the FIRST I
, TWO spaces after the SECOND I
, THREE spaces after the THIRD I
, and so on.It is useful to note these patterns because we can use them when designing the solution later.
Step 1: There is a simple version of the problem that we can solve first. Ignore all characters except the I
and generate and return a string containing the correct number of I
characters. This will be our version 1.
Step 2: Modify version 1 so that the correct number of \n
characters are added. This will be our version 2.
Step 3: Modify version 2 so that the correct number of spaces are added. This will be our version 3 (final version).
In version 1, we are going to return a string containing only the correct number of I
characters.
n=0
we need to return ""
n=1
we need to return "I"
n=2
we need to return "II"
n=3
we need to return "III"
Here is a design for version 1.
result
which is an empty string ""
. We will append all the subsequent characters to result
.n
is less than 1
, there is nothing to do, so return result
.iCount
to count the number of I
characters we have appended so far, currently its value should be 0
.while
iCount
is less than n
, repeat: I
to result
iCount
by onereturn result
Here is the code for version 1:
function drawStairs(n) {
let result = "";
if (n < 1) return result; // nothing to do, the function returns here
// we only get past the above line when n >= 1, we don't need an else
let iCount = 0;
while (iCount < n) {
// append an I
result = result.concat("I");
// or you could have ...
// result = result + "I";
// update the count
iCount = iCount + 1;
}
return result;
}
If we run version 1 in codewars we will see the following output:
Version 1 passes the test for n=1
. It fails when n=3
and n=5
but we expected that. If you read the message printed for the 3-step test, it says
expected 'III' to equal 'I\n I\n I'
We can see that version 1 is doing exactly what we intended. In the 3-step test, version 1 returns a string containing three I
characters. In the 5-step test, version 1 returns a string containing five I
characters.
Version 2 will return strings containing only I
and \n
characters. Here is what we are aiming at:
n=0
we need to return ""
n=1
we need to return "I"
n=2
we need to return "I\nI"
n=3
we need to return "I\nI\nI"
We note that when we add an I
, if it was not the last I
, we add a \n
. Here is the relevant code with a comment added:
while (iCount < n) {
// append an I
result = result.concat("I");
// update the count
iCount = iCount + 1;
// if that wasn't the last I, append a \n
}
To correctly add a newline when required, we need to add:
if (iCount < n) {
result = result.concat("\n");
}
We should test this and check the output is what we expect.
The final version of our code will include space characters. This is what we are aiming at:
n=0
we need to return ""
n=1
we need to return "I"
n=2
we need to return "I\n␣I"
n=3
we need to return "I\n␣I\n␣␣I"
We should notice that
\n
character for every I
except the last.I
characters we have appended so far.Here is the code to add the right number of spaces:
// add the \n when required
if (iCount < n) {
result = result.concat("\n");
// add the spaces too
let spaceCount = 0;
while (spaceCount < iCount) {
result = result.concat(" ");
spaceCount = spaceCount + 1;
}
}
You might have written the following:
// add the \n when required
if (iCount < n) {
result = result.concat("\n");
}
// now add the spaces
if (iCount < n) {
let spaceCount = 0;
while (spaceCount < iCount) {
result = result.concat(" ");
spaceCount = spaceCount + 1;
}
}
but we don't need the second if
statement because both if
statements test whether (iCount < n)
and the neither if
statement changes iCount
or n
. Therefore we can merge the two into one if
statement.
One if
statement is simpler than two, simpler is almost always better.
The final version of this function is quite complicated:
concat
function.while
statement that contains an if
statement which in turn contains another while
statementOur decomposition of the problem into three different steps really helped us here. It allowed us to solve the problem without really seeing how complex the code was that we were building up. Each version had a small focussed modification to the previous version.