Eloquent JS, Chp2: Exercise 3

Exercise 3: Chess Board

Write a program that creates a string that represents an 8 x 8 grid, using newline characters to separate lines.

At each position of the grid there is either a space or a “#” character.

The characters should form a chess board.  Passing this string to console.log should show something like this:

chess board

When you have a program that generates this pattern, define a variable size = 8 and change the program so that it works for any size, outputting a grid of the given width and height.

Approach

chess board 8 by 8 with arrows

Loop – “Vertical”:

  • This will be the outermost for loop
  • This loop adds height to the output
  • Let i represent the number of iterations
  • i is of type number
  • Let size represent the width and height of the square
  • size is of type number
  • By the end of the loop, i == size

Loop – “Horizontal”:

-Increases characters horizontally per line
-Each new line is a new iteration
-Repeating characters: # and a space
-When i is an even number, the line starts with a # character
– Repeated characters when i is an even number: #_
-When i is an odd number, the line starts with a space (will rep. with _ character in notes)  -Repeated characters when i is an odd number: #_ , but one _ exists before any repeats

  • This will be an inner for loop
  • This loop adds width to the output
  • Let char represent the characters on the line
  • char is of type string
  • char.length returns the length (number of characters) of char
  • By the end of the loop, i == size == char.length

Questions:

1. How do you repeat string characters horizontally when the number of repeats required is unknown? 

You can concatenate strings i.e.

console.log("# " + "# ")
//-> # #

EDIT (after writing Solution Attempt 4 – Final Submission) : You CAN repeat strings horizontally when the number of repeats is unknown.

What is needed: Put console.log outside the for loop (so whatever is printed is the final result of repeated string concatenation).  See the next blog post “Exercise 2.3 Part 2” for this solution. 

But recall that no arithmetic operation can be applied to strings i.e.

var test = "Hi";
test *= 2;
console.log(test); 
//-> NaN

 

I will not be able to repeat characters horizontally using arithmetic multiplication i.e.

var char = "# " * 3; 
console.log(char);
//-> NaN

or

console.log("10" * 2); 
//-> 20 
console.log(typeof("10" * 2));
//-> number

 

Observe string concatenation between string values and number values:

//Example 1
console.log("150" + 1010);
//-> 1501010 
console.log(typeof("150" + 1010));
//-> string  

//Example 2
console.log(150 + "1010");
//-> 1501010
console.log(typeof(150 + "1010")); 
//-> string 

//Example 3
console.log("#" + 10);
//-> #10
console.log(typeof("#" + 10));
//-> string

Keep in mind that the Number and String functions convert a value to type number and type string respectively.

Though that still isn’t helpful in repeating string characters horizontally when the number of repeats required is unknown.

It passed the mind to replace # and space with 1 and 0, and at the end, replace 1 and 0 with # and space again. Using numbers would allow for repetition via arithmetic operations. However, this idea died a swift death upon the realisation that when a string value’s type is converted to type number, (“10” with 10), any arithmetic operation on this value will be governed by mathematical laws i.e. 10 * 2 = 20, not 1010 i.e.

ejs 2.3 repeat test with 10

And why it wouldn’t work with # :

ejs 2.3 repeat test

.
.
.

2. What is the update/final-expression in the inner for loop? 

Can it be empty?

.
.
.

Outside the scope of Chapter 2, there is a JavaScript String repeat() method. Let’s try this out for Solution 1.

// Allow any size to be inputted
 var size = prompt("Enter a positive integer.");

// Convert string value inputted in prompt to type number
 Number(size);

// Outer loop to track vertical iteration
 for (var i = 0; i <= size; i++) {

// Inner loop to add characters horizontally per line
 for(var char = ""; char.length <= size; ) {

//If the line number is odd
 if (size % 2 !== 0) {

// Begin the line with a space
 char = " ";
 // How many times does the pattern have to repeat?
 var numRepeats1 = (((size + 1)/2) - 1);
 var pattern1 =  "# ";

// Concatenate the first space with the pattern
 // Use string repeat() method to repeat the pattern the appropriate number of times
 char += pattern1.repeat(numRepeats1);

}

//If the line number is even
 if (size % 2 == 0) {

//Pattern to be repeated
 var pattern2 = "# ";

// Repeat the pattern this amount of times
 var numRepeats2 = size/2;

//Update char value
 char += pattern2.repeat(numRepeats2);
 }

.
.
.

EPIPHANY: I don’t need the second for loop. With the string repeat method, there is no need for a loop to repeat the characters horizontally.

EPIPHANY 2 (after Solution Attempt 1 Test 1): Nevermind, I do need the second loop. Without this loop, a conditional branch would be left out depending on what the value of size is i.e. if size = 2, the odd number if-statement branch is not considered at all, so instead of printing out line 1, line 2, only line 2 with weird stuff is printed.

Solution Attempt 1

var char = ""
var size = prompt("Enter a positive integer.");
Number(size); 

for (var i = 0; i <= size; i++) {
    if (size % 2 !== 0) {
       char = " "; 
       var pattern1 = "# "; 
       var numRepeats1 = (((size + 1)/2) - 1);
       char += pattern1.repeat(numRepeats1); 
       console.log(char);
}

    if (size % 2 == 0) { 
       var pattern2 = "# "; 
       var numRepeats2 = size/2; 
       char += pattern2.repeat(numRepeats2); 
       console.log(char); 
}}

 

chessboard repeatmethod soln1
size = 2

No plan survives first contact with the enemy. I think I’ll become quite fond of that saying.

What I think went wrong:

Firstly, the initial value of i should be set to 1, not zero. This way, the iteration number is equal to the row number (of the output).

ejs 2.3 s1t1 iequals1
size = 2; change is highlighted

 

Secondly, the if-statement conditions are wrong. Variable i instead of variable size should be used. That is:

// for odd-number lines 
 if (i % 2 !== 0) {
  }
// for even-number lines 
  if (i % 2 == 0) {
  }

Why? Because it is the iteration value that tracks the row that we are on. The value of i increases with each iteration, while the value of size stays the same (it is whatever value was inputted in prompt). Size is the maximum width and height of the grid. We just need the current row number of the grid (i).

Let’s say size = 2. The odd-numbered line if-statement branch {check wording} is evaluated to be false since size is an even-numbered value. That’s why char = ” ” didn’t manifest. Execution moves to the even-numbered line if-statement branch, and its statement body is executed.

NB: The value of i is compared to the value of size at the beginning of each iteration to see if another iteration is required. {check wording and understanding: is the updated value compared with the value in the condition at the END or the BEGINNING of each ITERATION (or do we say LOOP)?}

ejs 2.3 s1t2
size = 2; changes are highlighted

What happened?

Look at numRepeats1 and numRepeats2. Are their formulas correct? Seems to be so, yes. Next, look at char +=.

ejs 2.3 s1t4 char +=
size = 2; change is highlighted

QUESTION 1: Why did a change from Line 17 char += pattern2.repeat(numRepeats2); to char = pattern2.repeat(numRepeats2); give the correct output for the 2nd line?

Testing

1)  Line 17 –>  char += re-added
Line 7 –> char = “1”
Changes are to see whether the new value of char bleeds out of its if-statement into the rest of the program. Apparently yes. char = “1” should only affect odd number iterations.

2.3 ejs repeat test char +=
size = 2

ANSWER to QUESTION 1: For some reason, the value of char remains “1# # # … #” even when the iteration is a new, even-numbered iteration. That the iteration is even-numbered means that execution should bypass the first if statement (Line 6) and go on to the second if statement (Line 14). char’s value should be an empty string when execution starts at Line 14, not holding on to whatever value it gained from Line 10.

We must also consider the += operator on Line 17. What happens when it is removed?

2) Line 17 –> = operator replaces += operator

2.3 ejs repeat test char += 2
size = 2

ANSWER to QUESTION 1: When char (whose value seems to cling to the result from Line 10) is not concatenated to pattern2 on Line 17, the output for iteration number 2 looks proper.

 

 

9 repeats
size = 2

if-statement for even-number lines seem to be working properly. Something’s wrong with the if-statement for odd-number lines branch. Suspect are Lines 9 and/or 10.

 

Looking at Line 9 — changed (((size + 1)/2) – 1); to (size):

it's the repeat formula
Line 9, testing the repeat formula

 

Testing the repeat formula:

repeat testing

That means something is wrong with char += or size input, not the formula.

EDIT: At least, for when size holds ODD NUMBERS. How about EVEN NUMBERS?

odd formula doesn't work with even numbers

EPIPHANY: Whenever size is an odd number, the repeating formula in the first if-statement works fine. But the repeating formula in the second if-statement doesn’t work properly. AND VICE VERSA. All because of variable size, which is used in the repeating formula. FIX THE FORMULAS.

 

Repeating a string 2.5 times doesn’t happen. It repeats 2 times.

even and odd repeating formula testing

But the if-statement for odd-number and the if-statement for even numbers should filter incoming numbers, and slide them into their respective formulas.

 

 

The String repeat() method and char += … seems to be working fine.

what's wrong is the loop or lack of one

 

 

 

Testing prompt input:

it's the prompt input that's the problem omg
size = 3 ; highlighted is the output you’re supposed to have gotten

 

Something’s wrong with the prompt input.

More proof:

2.3 ejs no prompt9 repeats

 

By process of elimination, these are the remaining potential errors:

  • Repeating formulas — fix both the odd and even one; use something other than size or adjust the numbers to accommodate variable size
  • REPEATING PATTERN ISSUE and discrepancy between value of i and value of size
  • Don’t cheat with using blanks as noncharacters. Spaces count as characters and you want to print the specified character amount, no more no less.
  •  Prompt input
  • for loop? lack of a secondary loop?

 

 

THE BIG EPIPHANY

When size holds an odd number value, the numRepeats1 formula works properly. But the numRepeats2 formula does not. When size holds an even number value, the numRepeats2 formula works properly, but the numRepeats1 formula does not.

chessboard big epiphany

The solution: 

if size = odd number { 
   if i = odd number 
     Adjust repeating formula accordingly
   if i = even number 
     Adjust repeating formula accordingly 
}
else if size = even number {
   if i = odd number
     Adjust repeating formula accordingly
   if i = even number
     Adjust repeating formula accordingly 
}

Place these if statements after the for loop. Each if statement will have a nested if statement (for i = odd number) and else-if statement (for i = even number).

Solution Attempt 2

var char = "";
var size = 2;
Number(size);

for (var i = 1; i <= size; i++) {
  // if size is an odd number
  if (size % 2 !== 0) {
    //if the row number (iteration) is an odd number 
    if (i % 2 !== 0) {
      char = " ";
      var pattern1 = "# ";
      var numRepeats1 = (((size + 1)/2) - 1);
      char += pattern1.repeat(numRepeats1);
      console.log(char);
    }
    //if the row number is an even number 
    if (i % 2 == 0) {
      char = "#"
      var pattern2 = " #";
      var numRepeats2 = ((size -1)/2);
      char += pattern2.repeat(numRepeats2);
      console.log(char);
}}
  //If size is an even number 
  else if (size % 2 == 0) {
    //if the row number is odd
    if (i % 2 !== 0) {
      var pattern1 = " #";
      var numRepeats1 = (size/2);
      char += pattern1.repeat(numRepeats1);
      console.log(char);
     }
  //if the row number is even 
  if (i % 2 == 0) {
     var pattern2 = "# ";
     var numRepeats2 = (size/2);
     char += pattern2.repeat(numRepeats2);
     console.log(char);
 }}}

^Makes more structural sense for the currently outermost for loop to be inside “if size is odd” and “if size is even” statements. Is the structure causing the following problem though? This structure, while disorganized, should still work properly.
** “if size is odd” if statement branch is working properly. Something’s wrong with the “if size is even” statement

2.3 ejs size is even if statements
size = 2

 

Get rid of += on Line 33:
Highlighted yellow is the change:

2.3 ejs size is even if statements rid of +=
size = 2

Why this change when += was replaced by = , on Line 33?

 

Now there are issues with the += on Line 26:

2.3 why why why

The pattern marked “2” is the pattern on Line 24, repeated twice. But where did the pattern marked “1” come from?

char += pattern1.repeat(numRepeats1); 
//equivalent to:
char = char + pattern1.repeat(numRepeats1);

char should be an empty string, until it is concatenated with pattern1.

Highlighted yellow is the change from += to + on Line 26:

2.3 what is char in the else if statement

So char = “# # ” when execution hit upon Line 26? QUESTION 2: How?

 

Using other values for size i.e. 3, 5, 6, 8, 10, the program now displays the proper output. On Line 2, I re-added prompt(), which also works fine now.

EDIT (during Solution Attempt 3): Oh no, prompt() doesn’t work fine for odd numbers.

 

Solution Attempt 3 

1     var char = "";
2     var size = prompt("Enter a positive integer.");
3     Number(size);
4
5     for (var i = 1; i <= size; i++) {
6         if (size % 2 !== 0) {
7             if (i % 2 !== 0) {
8                 char = " ";
9                 var pattern1 = "# ";
10                var numRepeats1 = (((size + 1)/2) - 1);
11                char += pattern1.repeat(numRepeats1);
12                console.log(char);
13            }
14
15            if (i % 2 == 0) {
16                char = "#";
17                var pattern2 = " #";
18                var numRepeats2 = ((size -1)/2);
19                char += pattern2.repeat(numRepeats2);
20                console.log(char);
21    }}
22        else if (size % 2 == 0) {
23            if (i % 2 !== 0) {
24                var pattern1 = " #";
25                var numRepeats1 = (size/2);
26                char = pattern1.repeat(numRepeats1);
27                console.log(char);
28            }
29
30            if (i % 2 == 0) {
31               var pattern2 = "# ";
32               var numRepeats2 = (size/2);
33               char = pattern2.repeat(numRepeats2);
34               console.log(char);
35    }}}

I celebrated too soon.

When size = 11 without prompt(), we get this:

i celebrated too soon 2.3 ejs
Output is proper as expected

 

When size = 11 via prompt(), we get this mess:

wtf 2.3 ejs prompt

Inputting size values into prompt() that are even and greater than 10 i.e. 12, 14, 16, etc., the output is proper as expected. However, when inputting size values into prompt() that are ODD and greater than 10 i.e. 11, 13, 15, 17, etc., the output is all wrong.

EDIT: Nope, odd-numbers below 10, when inputted via prompt() for size, also do not work properly.

Therefore, we’re dealing with either an error(s) with 1)  Lines 5 – Line 18 (when size is an odd number) or 2) the prompt() method or 3) both or 4) something else.

Note that the even-numbered rows do show the expected output. The odd-numbered rows show more than the expected characters. So the error is somewhere in Lines 6-11 if we’re looking at option 1).

Suspects:

  • Indentation? Line 13 if statement is indented more than it should be? This is unlikely to be the problem. (Check: Yeah, it isn’t the issue.)
  • prompt()       The main suspect
  • The += operator on Line 10  (Check: Not the issue.)
  • usage of same variable for different values i.e. char (Line 7, Line 10) ?? (Check:Not an issue.)

Tentative conclusion: It looks like a prompt() issue, because inputting any value manually gives the correct output. RETURN TO THIS.

 

Cleaning up the code:

see Solution Attempt 4

  • defined the variable char, but did not initialize it –> its value is undefined; will give char a value depending on the nested if statement
  • declared and initialized variables patternsharp and patternspace outside of the for loop –> prevents re-writing these four times inside the loop’s nested if and else if statement bodies
  • renamed numRepeats1 and numRepeats2 –> under one variable name: numRepeats (see Line 9), because they are contained within their nested if statements
  • under the else-if statement on Line 19, pulled two numRepeats out of their nested if-statements, and placed it as one numRepeats statement (Line 20) –> this applied to both nest if-statements and saves space (no need to rewrite numRepeats twice since they have the same formula of size/2)

 

Solution Attempt 4: Final Submission

using String repeat() method

still having issues with prompt()

2.3 solution 1 final

Solution Attempt 4 with Comments

var char; var patternsharp = "# "; var patternspace = " #"; 
var size = 3;
Number(size);

    for (var i = 1; i <= size; i++) {
         // size is an odd number
         if (size % 2 !== 0) {
             // row number is an odd number
             if (i % 2 !== 0) { 
                //odd rows start with a space
                char = " "; 
                // the number of times patternsharp shoud be repeated
                var numRepeats = (((size + 1)/2) - 1);
                /*concatenating " " and patternsharp however 
                many times it's repeated*/ 
                char += patternsharp.repeat(numRepeats); 
                console.log(char); 
             }
            //row number is an even number
            if (i % 2 == 0) {
               //even rows start with a sharp
               char = "#";
               //the number of times patternspace should be repeated
               numRepeats = ((size-1)/2);
               char += patternspace.repeat(numRepeats);
               console.log(char);
 }}
        //size is an even number 
        else if (size % 2 == 0) {
             /*the number of times patternsharp or patternspace 
             should be repeated */
             numRepeats = (size/2);
            //row number is odd
            if (i % 2 !== 0) {
                char = patternspace.repeat(numRepeats); 
                console.log(char); 
        }
            //row number is even
            if (i % 2 == 0) {
               char = patternsharp.repeat(numRepeats);
               console.log(char);
 }}}

 

QUESTION 3: 

I defined and initialized the variable numRepeats on Line 9. The later usage of numRepeats on Lines 15, 21, and 27 do no require being defined again, even when they are inside different if/else-if statements. QUESTION: Was that defining a variable ‘locally’? Versus ‘globally’ before the for loop?

var numRepeats inside a nested if statement
still works properly

 

QUESTION 4: 

What happens when you take out the console.log(char); from the if statement body, and place it outside of it? See Line 13.

console 2.3 ejs

 

 

For the Future

  • I didn’t try a solution without String repeat() method. Try that.
  • Answer Questions 1-4 properly.
  • Figure out what is wrong with prompt() or Lines 6-11.
  • Consider other methods to solve Chess Board — replace(), a second for loop, newline character, etc.
  • Then check your solutions with the Book Solutions.

TBC 

Eloquent JS, Chp2: Exercise 1

Exercise 1: Looping a Triangle

Write a loop that makes seven calls to console.log to output the following triangle:

#
##
###
####
#####
######
#######

Useful to know: You can find the length of a string by writing .length after it.

Example:

var abc = "abc";
console.log(abc.length);
//-> 3

Approach:

Given info: 
– need a loop
– seven calls to console.log
– the sharp/number symbol (#) is the string text that needs to be repeated

What do I know? :
– conditional statements (if, else, switch)
– looping statements (while, do…while, for)
– .length after a string gives me the length of the string
– need to concatenate # incrementally

Questions:
-How do I choose which kind of looping statement to use?

Putting together info: 
– counter variable starts at 0 (there is no # yet)
EDIT – encountered epiphany during first line of  Solution Attempt 1: # is of type string. So counter variable should hold an empty string initially.
EDIT 2 – after writing out Solution Attempt 1, I realize that starting at an “” string is unnecessary. It will not be outputted. Counter variable should hold “#” initially.

– condition: counter variable holds a value less than seven
EDIT – same epiphany time: the length of the string value of the counter variable should hold a value … less than 8? less than or equal to 7? less than 7? NOT SURE YET
EDIT 2: At the end of everything — should have given this more thought.

– update/final-expression: counter variable = counter variable + “#”

Didn’t consider:
-what the counter variable represents, and its value type in this exercise — length of the sign/word/symbol (type number)? Number of repeats (type number)? Type string?
EDIT: so the counter variable represents the value to be repeated; since it will be displayed, it is the base symbol of the whole triangle;  it is of type string. At the same time, its length is what keeps track of the number of iterations.

(I actually wrote this down under Given Information, but then forgot about it.)

 

Solution Attempt 1:

for (var signLength = ""; signLength.length < 8; signLength = signLength + "#") {
    console.log(signLength);
}

Checking Understanding: 

First iteration–
The variable signLength holds an empty string.
The length of an empty string is 0.
This means that the condition holds.
The statement inside the loop body is executed {right wording?}.
Nothing is shown as output, because counter variable holds an empty string.
signLength’s value is ‘updated’ from “” to “#”.
Execution goes to the beginning of the loop for the next iteration {right wording?} 

Issues:
– nothing is outputted for the first iteration if I start the counter variable as holding the value of an empty string —> let the counter variable grasp “#” as its initial value
– signLength as the variable name doesn’t make sense, and is made redundant in the condition signLength.length < 8 —> change the variable name to reflect that it holds the base symbol for the whole triangle, but the symbols continue to expand

Questions:
-Would the update shortcut work with strings? i.e. signLength = signLength + “#” becomes signLength += “#” ?
Remember that it’s string concatenation though, not arithmetic addition.
ANSWER – after writing out everything up to “Solution with symbol <= 7”, I checked Hints, and yes, += “#” is usable.

 

Solution Attempt 2

for (var symbol = "#"; symbol.length < 8; symbol = symbol + "#") {
    console.log(symbol);
}

Checking Understanding:

First iteration–
The variable symbol holds a string character “#”.
The length of symbol is 1.
This means that the condition holds.
The statement inside the loop body is executed.
# is outputted.
symbol’s value is ‘updated’ from “#” to “##”.
Execution goes to the beginning of the loop for the next iteration.

Second iteration–
The variable symbol holds the string text “##”.
The length of symbol is 2.
This means that the condition holds.
The statement inside the loop body is executed.
## is outputted. (as a whole, it goes underneath the # from the first iteration)
symbol’s value is ‘updated’ from “##” to “###”.

Third iteration–
The variable symbol holds the string text “###”.
The length of symbol is 3.
This means that the condition holds.
The statement inside the loop body is executed.
### is outputted.
symbol’s value is ‘updated’ from “###” to “####”.

Fourth iteration–
The variable symbol holds the string text “####”.
The length of symbol is 4.
This means that the condition holds.
The statement inside the loop body is executed.
#### is outputted.
symbol’s value is ‘updated’ from “####” to “#####”.

Fifth iteration–
The variable symbol holds the string text “#####”.
The length of symbol is 5.
This means that the condition holds.
The statement inside the loop body is executed.
##### is outputted.
symbol’s value is ‘updated’ from “#####” to “######”.

Sixth iteration–
The variable symbol holds the string text “######”.
The length of symbol is 6.
This means that the condition holds.
The statement inside the loop body is executed.
###### is outputted.
symbol’s value is ‘updated’ from “######” to “#######”.

Seventh iteration–
symbol holds the string text “#######”.
Length of symbol is 7.
Condition holds.
Statement is executed.
####### is outputted.
symbol’s value is ‘updated’ from “#######” to “########”.

Eighth iteration–
symbol holds the string text “########”.
Length of symbol is 8.
Condition evaluates to false.
Execution jumps outside the for loop.
Nothing is outputted (as a whole, the triangle should be outputted).

CONCLUSION: Solution Attempt 2 should work properly.

Issues:
-Should place something outside the loop body? Not sure if the whole triangle is outputted??
EDIT: after testing it in JS console, yes it works.

looping triangle less than 8
Solution with symbol < 8 works properly

Solution with symbol <= 7

looping triangle less than and equal to 7
Also works properly

Sixth iteration–
The variable symbol holds the string text “######”.
The length of symbol is 6.
This means that the condition holds.
The statement inside the loop body is executed.
###### is outputted.
symbol’s value is ‘updated’ from “######” to “#######”.

Seventh iteration–
symbol holds the string text “#######”.
Length of symbol is 7.
Condition holds (symbol.length <= 7).
Statement is executed.
####### is outputted.
symbol’s value is ‘updated’ from “#######” to “########”.

Eighth iteration–
symbol holds the string text “########”.
Length of symbol is 8.
Condition evaluates to false.
Execution jumps outside the for loop.
Nothing is outputted (as a whole, the triangle should be outputted).

 

Solution with symbol < 7

looping triangle less than 7
Does not work properly

Sixth iteration–
The variable symbol holds the string text “######”.
The length of symbol is 6.
This means that the condition holds.
The statement inside the loop body is executed.
###### is outputted.
symbol’s value is ‘updated’ from “######” to “#######”.

Seventh iteration–
symbol holds the string text “#######”.
Length of symbol is 7.
Condition evaluates to false (symbol.length < 7).
Execution jumps outside the for loop.
Nothing is outputted (as a whole, a triangle with six levels is outputted).

 

CONSIDER: Both Solution with symbol.length < 8 and symbol.length <= 7 outputs the desired result. But which one is processed more quickly?

 

Solution Attempt 3: Final submission

for (var symbol = "#"; symbol.length < 8; symbol += "#") {
    console.log(symbol);
}

NB: Changed from symbol = symbol + “#” to symbol += “#”

looping triangle update shortcut
symbol += “#”     works properly

.
.
.

BOOK SOLUTION

 

 ejs chp3 e2 soln

  • variable name is line, which seems more reasonable than symbol, since the string value’s length is used to keep track of the progress of the program
  • the condition – < 8 is used, instead of <= 7
  • my solution is more or less the same to the book solution