Code Quest: JavaScript Booklet

A Worksheet for Student Coders

Introduction

Welcome to the Code Quest workshop! This guide contains 25 missions across 5 sections to test your JavaScript skills. Each mission uses functions from the "Code Quest" game.

Remember the most important rule: because our game functions have animations, you must use the await keyword before calling them!

// Example
await say("I'm ready to code!");

Read the concept, then the mission, and try to write the code. If you get stuck, check the clues. After you've tried, check your answer in the solutions. Good luck, Coder!

Section 1: Variables & Data Types

Learn to store and use different types of information.

Mission 1: The Greeter Bot

Concept: Variables & Strings
A let variable stores information. A String is text, wrapped in quotes ("Hello"). You can join strings with +.

Your Mission

  1. Asks the user for their name (await ask(...)) and store it in a variable called playerName.
  2. Uses the say() command to greet the user by name (e.g., "Hello, Ada!").
Click to see Clue

To join a string and a variable, use: "Hello, " + playerName

Click to see Solution
let playerName = await ask("What is your name?");
await say("Hello, " + playerName + "!");

Mission 2: The Step Counter

Concept: Numbers & Math
Number data types are just digits (e.g., 50, 100) with no quotes. You can use math operators (+, -, *, /) to calculate new values.

Your Mission

  1. Create a variable baseMove and set it to 50.
  2. Create a variable longMove and set it to baseMove * 3.
  3. Make the robot move right by longMove steps.
  4. Make the robot move down by baseMove steps.
Click to see Clue

Use the variable names, not the numbers, inside the move commands: await moveRight(longMove);

Click to see Solution
let baseMove = 50;
let longMove = baseMove * 3;

await moveRight(longMove);
await moveDown(baseMove);

Mission 3: The Watcher

Concept: Debugging with `watch()`
The await watch(label, value) command prints a variable's value to the "Execution Step" window. It's essential for debugging and seeing what your code is *really* doing.

Your Mission

  1. Create a variable magicNumber and set it to 77.
  2. Use watch() to display this number. The label should be "Magic Number".
  3. Change the robot's color to "purple".
  4. Change magicNumber to magicNumber * 2.
  5. Use watch() again to show its new value, labeled "New Number".
Click to see Clue

The first watch command will look like: await watch("Magic Number", magicNumber);

Click to see Solution
let magicNumber = 77;
await watch("Magic Number", magicNumber);
await changeColor("purple");

magicNumber = magicNumber * 2;
await watch("New Number", magicNumber);

Mission 4: The Annoying Bot

Concept: String Concatenation
You can add (concatenate) strings and variables together multiple times to build complex sentences.

Your Mission

  1. Ask the user for their favorite color. Store it in favColor.
  2. Ask the user for their favorite food. Store it in favFood.
  3. Use say() to say "Your favorite color is [color] and you like [food]!"
  4. Use say() again to say "I don't like [color] or [food]."
Click to see Solution
let favColor = await ask("Favorite color?");
let favFood = await ask("Favorite food?");

await say("Your favorite color is " + favColor + " and you like " + favFood + "!");
await say("I don't like " + favColor + " or " + favFood + ".");

Mission 5: Full Reset

Concept: Reassigning Variables
You can change the value of a let variable at any time by simply assigning it a new value.

Your Mission

  1. Change the character's emoji to "🚀".
  2. Move right 100 steps.
  3. Change the character's emoji to "💥".
  4. Change the color to "red".
  5. Use say() to say "Error! Resetting!".
  6. Change the emoji back to "🤖" and the color back to "gold".
Click to see Solution
await changeCharacter("🚀");
await moveRight(100);
await changeCharacter("💥");
await changeColor("red");
await say("Error! Resetting!");
await changeCharacter("🤖");
await changeColor("gold");

Section 2: Functions

Learn to create reusable, powerful blocks of code.

Mission 6: The Jumper

Concept: Creating Functions
A function is a reusable block of code. If your function uses any await commands, you must declare it as an async function.

Your Mission

  1. Define a new async function called jump().
  2. Inside jump(), make the robot move up 50 steps, then down 50 steps.
  3. Call your await jump() function.
  4. Move right 100 steps.
  5. Call await jump() again.
Click to see Solution
async function jump() {
  await moveUp(50);
  await moveDown(50);
}

await jump();
await moveRight(100);
await jump();

Mission 7: The Square Drawer

Concept: Functions with Parameters
A parameter (e.g., size) is a variable you put in your function's definition. It lets you pass in a value (an "argument") when you call the function, making it flexible.

Your Mission

  1. Define an async function called drawSquare(size) that accepts one parameter.
  2. Inside, use the size parameter to move right, down, left, and up.
  3. Call await drawSquare(100); to draw a big square.
  4. Call await drawSquare(25); to draw a small square.
Click to see Solution
async function drawSquare(size) {
  await moveRight(size);
  await moveDown(size);
  await moveLeft(size);
  await moveUp(size);
}

await drawSquare(100);
await drawSquare(25);

Mission 8: The Colorful Mover

Concept: Functions with Multiple Parameters
You can add as many parameters as you need, separated by commas.

Your Mission

  1. Define an async function called moveAndPaint(distance, newColor).
  2. Inside, it should move right by distance, then change color to newColor.
  3. Call it with 100 and "blue".
  4. Call it with 50 and "green".
Click to see Solution
async function moveAndPaint(distance, newColor) {
  await moveRight(distance);
  await changeColor(newColor);
}

await moveAndPaint(100, "blue");
await moveAndPaint(50, "green");

Mission 9: The Prize Giver

Concept: Functions that Return Values
Functions can give data back using the return keyword. If the function *only* does a calculation (no await), it does *not* need to be async.

Your Mission

  1. Create a normal function calculatePrize(name).
  2. Inside, make it return the string "A coin for " + name + "!".
  3. In your main code, await ask() for a name.
  4. Call your calculatePrize() function and store the result in a message variable.
  5. await say() the message.
Click to see Solution
function calculatePrize(name) {
  return "A coin for " + name + "!";
}

let playerName = await ask("What's your name?");
let message = calculatePrize(playerName);
await say(message);

Mission 10: The Smart Calculator

Concept: Combining Return and `await`
You can use await to get values, pass them to a normal function, and then use the returned value in another await command. This mixes async and sync code.

Your Mission

  1. Create a normal function add(num1, num2) that returns num1 + num2.
  2. await ask() for a number. Store it in val1. (It will be a string)
  3. await ask() for a second number. Store it in val2. (It will be a string)
  4. Call add(val1, val2) and store the result in sum.
  5. await say() the sum. (What happens? Is it what you expected?)
Click to see Clue

The ask() function returns a string. When you use + on strings, it joins them ("5" + "5" = "55"). To fix this, you must convert the strings to numbers using Number(val1).

Try making add(Number(val1), Number(val2)).

Click to see Solution
// This function is correct.
function add(num1, num2) {
  return num1 + num2;
}

let val1 = await ask("Enter first number:");
let val2 = await ask("Enter second number:");

// The bug: val1 and val2 are strings!
// "5" + "5" = "55" (concatenation)
let sum = add(val1, val2);
await say("The result is: " + sum);

// The Fix:
// let sum = add(Number(val1), Number(val2));
// await say("The *real* sum is: " + sum);

Section 3: Logic & Conditionals

Teach your robot how to make decisions.

Mission 11: The Bouncer Bot

Concept: `if` Statements
An if (...) { ... } statement only runs the code in the { } if the condition in the (...) is true. We use "comparison operators" like === (is equal to) to check.

Your Mission

  1. Create a variable password and set it to "open sesame".
  2. await ask() the user for the password. Store their answer in guess.
  3. Write an if statement that checks if guess === password.
  4. Inside the if block, make the robot say "Welcome!" and change color to "green".
Click to see Solution
let password = "open sesame";
let guess = await ask("What's the password?");

if (guess === password) {
  await say("Welcome!");
  await changeColor("green");
}

Mission 12: The Bouncer Bot 2.0

Concept: `if...else` Statements
An else { ... } block can be added after an if. The else code runs *only* if the if condition was false.

Your Mission

  1. Use the same code from Mission 11.
  2. Add an else block after the if.
  3. Inside the else block, make the robot say "Go away!" and change color to "red".
Click to see Solution
let password = "open sesame";
let guess = await ask("What's the password?");

if (guess === password) {
  await say("Welcome!");
  await changeColor("green");
} else {
  await say("Go away!");
  await changeColor("red");
}

Mission 13: Wall Detector

Concept: `isTouchingWall()`
The await isTouchingWall() command is special. It's a "boolean" function: it *returns* either true or false. You can use it directly inside an if statement.

Your Mission

  1. Move left by 100 steps (to hit the wall).
  2. Call await isTouchingWall() and store the result in a variable touching.
  3. Write an if statement that checks if (touching === true).
  4. Inside the if, say() "Ouch! A wall!"
Click to see Solution
await moveLeft(100);

let touching = await isTouchingWall();

if (touching === true) {
  await say("Ouch! A wall!");
}

Mission 14: The Escape Artist

Concept: `else if` Statements
You can chain multiple checks together. if (check 1), then else if (check 2), then else (if neither was true).

Your Mission

  1. await ask() "Which way? (up, down, or side)". Store in direction.
  2. If direction === "up", then moveUp(100).
  3. else if direction === "down", then moveDown(100).
  4. else (if it's not up or down), say("I can't go that way!").
Click to see Solution
let direction = await ask("Which way? (up, down, or side)");

if (direction === "up") {
  await moveUp(100);
} else if (direction === "down") {
  await moveDown(100);
} else {
  await say("I can't go that way!");
}

Mission 15: The Treasure Hunter

Concept: Logical `&&` (AND)
Use && (AND) to check if *two* conditions are true at the same time. if (condition1 && condition2).

Your Mission

  1. await ask() for a password. Store in pass.
  2. await ask() for a key number. Store in key.
  3. Write an if statement that checks if pass === "open" AND key === "123".
  4. If both are true, say("Treasure unlocked!").
  5. else, say("You're missing something.").
Click to see Solution
let pass = await ask("Password?");
let key = await ask("Key number?");

if (pass === "open" && key === "123") {
  await say("Treasure unlocked!");
} else {
  await say("You're missing something.");
}

Section 4: For Loops

Learn to repeat your actions automatically.

Mission 16: The Annoying Bot 2.0

Concept: `for` Loops
A for loop repeats a block of code a specific number of times. The code for (let i = 0; i < 4; i++) { ... } runs the code in the { } exactly 4 times.

Your Mission

  1. Write a for loop that runs 5 times.
  2. Inside the loop, make the robot say("Are we there yet?").
Click to see Solution
for (let i = 0; i < 5; i++) {
  await say("Are we there yet?");
}

Mission 17: The Square Dance

Concept: Loops & Functions
You can put any code inside a loop, including other functions you've made. This is how you combine concepts!

Your Mission

  1. Write a for loop that runs 4 times.
  2. Inside the loop, move right 100, then move down 100.
  3. (What shape does this draw? Is it a square?)
Click to see Clue

This will draw a staircase, not a square! To draw a square, you need moveRight(100), moveDown(100), moveLeft(100), and moveUp(100). You could put all 4 in the loop, but then... why run the loop 4 times?

A true "square" loop is: moveRight(100), moveDown(100)... and repeat. This is what your loop does. It just makes a 4-step staircase.

Click to see Solution
// This draws a 4-step staircase
for (let i = 0; i < 4; i++) {
  await moveRight(100);
  await moveDown(100);
}

Mission 18: The REAL Square Dance

Concept: Loop-ception
You can nest loops inside of other loops, but a simpler way is to just put more commands inside one loop.

Your Mission

  1. This time, draw a *true* 100x100 square.
  2. Write a for loop that runs 4 times.
  3. Inside the loop, you will need to move and... turn. How do you turn?
  4. (Hint: A square is moveRight, moveDown, moveLeft, moveUp... Can you put all four commands inside a loop that runs once?)
Click to see Clue

This is a trick question! You don't need a loop to draw *one* square. You would just write the 4 commands. You would use a loop if you wanted to draw *multiple* squares.

Click to see Solution
// You don't need a loop for one square.
await moveRight(100);
await moveDown(100);
await moveLeft(100);
await moveUp(100);

// But if you made a function for it...
async function drawSquare() {
  await moveRight(100);
  await moveDown(100);
  await moveLeft(100);
  await moveUp(100);
}

// You could use a loop to draw 3 squares!
for (let i = 0; i < 3; i++) {
  await drawSquare();
}

Mission 19: The Growing Steps

Concept: Using the Loop Variable `i`
The variable i in your loop (let i = 0) isn't just a counter. It's a real number you can use! It will be 0, then 1, then 2, etc. You can use it in your math.

Your Mission

  1. Write a for loop that runs 5 times.
  2. Inside the loop, move right by i * 25 steps.
  3. (What happens? The first move is 0*25=0, the second is 1*25=25, etc.)
Click to see Solution
for (let i = 0; i < 5; i++) {
  // i will be 0, 1, 2, 3, 4
  await watch("i is", i);
  await moveRight(i * 25);
  await moveDown(25); // Add this to see it better
}

Mission 20: The Wall Banger

Concept: `while` Loops (Not `for`)
A for loop runs a set number of times. A while(condition) { ... } loop runs *forever* until the condition becomes false. This is great for using with sensors!

Your Mission

  1. Start a loop: while (true) { ... }. This loop will run forever!
  2. Inside the loop, move left by 25 steps.
  3. Check if (await isTouchingWall()).
  4. If it is, say("I hit it!") and use the break; command to stop the loop.
Click to see Clue

The break; keyword is the only way to escape a while(true) loop. Make sure it's inside your if statement!

Click to see Solution
while (true) {
  await moveLeft(25);
  
  let touching = await isTouchingWall();
  
  if (touching === true) {
    await say("I hit it!");
    break; // Stop the loop
  }
}

Section 5: Arrays & Objects

Store and manage complex collections of data.

Mission 21: The Rainbow Bot

Concept: Arrays
An Array is a list of items stored in a single variable, using square brackets [ ]. E.g., let colors = ["red", "green", "blue"];

Your Mission

  1. Create an array colorList containing: "red", "orange", "yellow", "green", "blue".
  2. Use await changeColor() to change the robot's color to the *first* item in the list.
  3. Use await changeColor() again to change to the *third* item.
Click to see Clue

Access array items with [ ]. Remember: counting starts at 0! The first item is colorList[0]. The third item is colorList[2].

Click to see Solution
let colorList = ["red", "orange", "yellow", "green", "blue"];

await changeColor(colorList[0]); // red
await moveRight(50);
await changeColor(colorList[2]); // yellow

Mission 22: The Rainbow Road

Concept: Looping Through Arrays
This is the most common pattern in programming. Use a for loop from 0 to the array's .length. Inside the loop, use the counter i to get each item: myArray[i].

Your Mission

  1. Create the colorList array from the last mission.
  2. Write a for loop that runs colorList.length times.
  3. Inside the loop:
    • Get the current color: let color = colorList[i];
    • await changeColor(color)
    • await moveRight(50)
Click to see Solution
let colorList = ["red", "orange", "yellow", "green", "blue"];

for (let i = 0; i < colorList.length; i++) {
  let color = colorList[i];
  await changeColor(color);
  await moveRight(50);
}

Mission 23: The Enemy Bot

Concept: Objects
An Object stores related data in key: value pairs, using curly braces { }. It's like a custom variable container. You access data with "dot notation" (e.g., myObject.key).

Your Mission

  1. Create an object enemy.
  2. Give it three keys: name: "Goblin", color: "green", emoji: "👺".
  3. Use the object's properties to:
    • await say("A " + enemy.name + " appears!")
    • await changeColor(enemy.color)
    • await changeCharacter(enemy.emoji)
Click to see Solution
let enemy = {
  name: "Goblin",
  color: "green",
  emoji: "👺"
};

await say("A " + enemy.name + " appears!");
await changeColor(enemy.color);
await changeCharacter(enemy.emoji);

Mission 24: The Enemy Horde

Concept: Arrays of Objects
This is the ultimate data structure! It's an array [ ] where each item in the list is a complex object { }. This lets you store your entire game's data.

Your Mission

  1. Create an enemyList array.
  2. Inside it, put two objects:
    • { name: "Slime", color: "lime" }
    • { name: "Bat", color: "purple" }
  3. Loop through the enemyList (using .length).
  4. Inside the loop, get the let currentEnemy = enemyList[i];
  5. await say(currentEnemy.name)
  6. await changeColor(currentEnemy.color)
  7. await moveRight(75)
Click to see Solution
let enemyList = [
  { name: "Slime", color: "lime" },
  { name: "Bat", color: "purple" }
];

for (let i = 0; i < enemyList.length; i++) {
  let currentEnemy = enemyList[i];
  await say(currentEnemy.name);
  await changeColor(currentEnemy.color);
  await moveRight(75);
}

Mission 25: The Coin Hunter

Concept: Functions Returning Objects
The await getCoinPos() command returns an object with x and y properties, like { x: 150, y: 200 }. You can store this and use its properties.

Your Mission

  1. Call await getCoinPos() and store the result in a variable coin.
  2. await say("The coin is at x: " + coin.x).
  3. await moveRight(coin.x).
  4. await moveDown(coin.y).
  5. await say("Got the coin!").
Click to see Solution
// Reset position just in case
await moveRight(0);
await moveDown(0);

let coin = await getCoinPos();

await say("The coin is at x: " + coin.x);
await watch("Coin", coin); // Good for debugging!

await moveRight(coin.x);
await moveDown(coin.y);

await say("Got the coin!");