Can you repeat that?

We now discuss what a computer does best: repeat something over and over again. The looping mechanism, or ability to repeat, allows a computer to perform mindless tasks time and again that would otherwise render you bored to tears. Let me repeat again: repetition is good.

Looping with for

One of the looping mechanisms most programming languages provide is the for statement, otherwise known as the for loop. In JavaScript, the for statement is structured as follows:

1
2
3
for (initialization; condition; update) {
    // run code
}

The structure of the for loop is illustrated in the image below:

for The for loop

The initialization is an expression that is evaluated before the loop begins. You often want the initialization to declare a variable whose sole purpose is to be the loop counter. The condition is an expression that is evaluated prior to each iteration of the loop. The condition should evaluate to a boolean. If the condition evaluates to true, then code within the loop body would be executed. In case the condition evaluates to false, the loop ends and execution picks up from the first code statement following the closing brace } of the for statement. Finally, the update is an expression that is evaluated at the end of each iteration of the loop. The update typically increments (or decrements) the loop counter.

Let’s use a simple example to help us understand the above description of the for loop. Consider the following program to output the integers from 0 to 9 to the terminal.

for-int.js

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Print 10 integers to the terminal.
 *
 * @param {NS} ns The Netscript API.
 */
export async function main(ns) {
    const max = 10;
    for (let i = 0; i < max; i++) {
        ns.tprintf(`${i}`);
    }
    ns.tprintf(`Printed ${max} integers.`);
}

The initialization is the expression let i = 0. The condition is the expression i < max, where the variable max has been declared to hold the integer 10. Finally, the update is the expression i++. Prior to entering the first iteration of the loop, the condition i < max is evaluated to determine whether it results in a true value. The value of i is initially 0, hence the expression i < max evaluates to true. We now enter the loop body for the first time and the code inside the loop body prints the value of i to the terminal. We have executed all code we can within the loop body, so we now evaluate the update expression i++. The expression increments i by 1 and i now takes on the value 1. Control then jumps to the condition again, where we evaluate the expression i < max. Again the expression evaluates to true because 1 is indeed less than 10. We enter the loop body for the second time, print the integer 1 to the terminal, and the update expression increments the variable i to 2. Control jumps to the condition and we repeat the above process. The loop ends when i < max evaluates to false, which occurs when i holds the value 10. The last value of i printed to the terminal is therefore 9.

Let’s make the above program more interesting. Let’s modify the program to sum all integers from 0 to 9, inclusive. You need a variable to keep track of the cumulative sum. Declare such a variable outside of, and before, the loop. No need to modify the initialization, condition, and update portions of the loop. Each time you enter the loop body, you add the value of i to the cumulative sum. The program below should do what we wanted.

sum9.js

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Sum of integers from 0 to 9, inclusive.
 *
 * @param {NS} ns The Netscript API.
 */
export async function main(ns) {
    const max = 10;
    let sum = 0;
    for (let i = 0; i < max; i++) {
        sum += i;
    }
    ns.tprintf(`Sum is ${sum}`);
}

The keywords let and const

In the script sum9.js , why did we declare max as const max and sum as let sum? Why not const max and const sum? Or let max and let sum? When you use the keyword const to declare a variable and immediately assign a value to the variable, JavaScript prohibits you from reassigning the const variable. It does not matter if you reassign the same (or a different) value to the const variable. Think of const as constant. A constant does not change its value. Thus max is a constant. (Does that mean max is a constant variable? Sounds like an oxymoron does it not?)

Being the inquisitive learner that you are, you modify the program as follows:

sum9-error.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * Sum of integers from 0 to 9, inclusive.
 *
 * @param {NS} ns The Netscript API.
 */
export async function main(ns) {
    const max = 10;
    max = 11; // <-- Error here.
    let sum = 0;
    for (let i = 0; i < max; i++) {
        sum += i;
    }
    ns.tprintf(`Sum is ${sum}`);
}

You execute the modified script. Then Bitburner (and ultimately JavaScript) yells something like this at you:

Hey, didn’t you give max the value 10 and told me that you don’t want to change the value of max? Why are you giving max a different value now? Can’t you make up your mind? That’s it. I quit.

That is not really far from the truth. JavaScript does not like the modified program, gives you the cryptic message shown in the image below, and stops running the rest of your script. A variable declared using const should stick to one and only one value.

Error Can’t modify a constant

Let’s talk about let. A variable declared with the keyword let can have its value changed. That is it, really. Short and sweet.

Looping with while

While we are on the topic of looping, let’s consider another means of repeating things in JavaScript. The while statement is structured as follows:

1
2
3
while (condition) {
    // run code
}

The structure of the while loop is illustrated in the image below:

while The while loop

The loop body is delimited by the open brace { and closing brace }. The condition should be an expression that evaluates to a boolean. First, the condition is run. If the condition evaluates to true, then code within the loop body would run. If the condition evaluates to false, execution would jump to the code after the closing brace. After running code within the loop body, the condition would be evaluated again. If the condition evaluates to true, the above process would be repeated. Otherwise the loop ends.

The for and while loops are similar to each other, so similar in fact that you can convert code written using one loop statement to code that uses the other loop statement. By way of example, consider the script for-int.js above. The for loop of the script can be written using a while loop like so:

while-int.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * A while loop equivalent of for-int.js.
 *
 * Print 10 integers to the terminal.
 *
 * @param {NS} ns The Netscript API.
 */
export async function main(ns) {
    const max = 10;
    let i = 0;
    while (i < max) {
        ns.tprintf(`${i}`);
        i++;
    }
    ns.tprintf(`Printed ${max} integers.`);
}

String along some characters

Let’s use the while statement to process strings. Recall that each string has the length property, which counts the number of characters in the string. Each character in a string is associated with an index, an integer starting from 0. The next character has an index that is 1 greater than the previous character. The maximum index of any character in the string is the value of length minus 1. The following illustrates the relationship between the string "abcdef" and the index of each character.

1
2
0 1 2 3 4 5
a b c d e f

The first character a has index 0. The next character is b, which has index 1, etc. The last character f has index 5, which is 1 less than the number of characters in the string.

Suppose you declare a string like so const s = "Mississippi";. As M is the first character, its index is 0 and you can access this character like so s[0]. Notice the index is between the opening [ and closing ] square brackets. How would you access the second character? The second character has index 1 because indexing in JavaScript starts from 0. The second character can therefore be accessed as s[1].

How would you use the string index to count the number of times the character "i" appears in the string "Mississippi"? You iterate over each character one at a time. If k is the current index, then the character at index k is s[k]. Compare s[k] with "i". If the result of the comparison is true, then you know that "i" occurs at index k. Otherwise "i" does not occur at index k. Increment the index k, move on to the next character, and perform the comparison. Repeat the above process until you have considered all characters of the string. How do you know when to end the process? The maximum index of the string is the value of the string property length minus 1. Use this fact as your loop condition. Here is a program that counts the number of times the character "i" appears in the above string.

mississippi.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * Count the number of times i appears in a string.
 *
 * @param {NS} ns The Netscript API.
 */
export async function main(ns) {
    const s = "Mississippi";
    let k = 0;
    let n = 0; // Count number of i.
    while (k < s.length) {
        if (s[k] === "i") {
            n++;
        }
        k++;
    }
    ns.tprintf(`"i" occurs ${n} times`);
}

Exercises

Exercise 1. Read more about the for and while loops here and here.

Exercise 2. JavaScript has the do...while statement as a third means of looping. In some cases you might find this looping mechanism useful if you need to execute some code at least once. Read more about the do...while statement here.

Exercise 3. Use a while loop to rewrite the script sum9.js .

Exercise 4. Use a for loop to rewrite the script mississippi.js .

Exercise 5. Use a for loop to write a program that sums all integers between 1 and 100, inclusive. Provide a while loop equivalent of your script.

Exercise 6. Print the following pattern to the terminal.

1
2
3
4
######
######
######
######

Do so in three different ways. One of them must not use a loop.

Exercise 7. Use a loop to output the following pattern to the terminal.

1
2
3
4
5
#
##
###
####
#####

Exercise 8. Use a loop to print the multiplication table (from 1 to 12) to the terminal.

Exercise 9. The factorial of a positive integer $n$ is defined as $n! = 1 \times 2 \times 3 \times \cdots \times n$. Use a loop to calculate the factorial of 10.

Exercise 10. Write a program to calculate the sum of all numeric digits in the string "3141592653".