export const lessons = [ { id: 'lesson1', title: '1. Introduction to Python', difficulty: 'easy', content: `
Let's learn some Python..
We'll start with what's called a "Hello World" program to make sure everythings working.
In Python, this is done with the print function.
print("Hello World")Did you try typeing print(Hello World), without the quotation marks?
If you didn't, give it a try now.
Thats what we call a Syntax Error.
Python doesn't know what the term (Hello World) means, the "" we added before tell Python that this is a "string", a series of characters that it doesn't need to try and understand, just to repeat.
String is just one of the many Data Types that Python has. To continue, I want you to print the following all at once, each on a new line:print("Hello World")print(42)print(3.14)print(True)Click the "Run" button to execute your code
`, objectives: [ "Print a string to the console", "Print an int to the console", "Print a float to the console", "Print a boolean (True/False) to the console" ], doneCondition: (() => { const stringRegex = /print\s*\(\s*(['"]).*?\1\s*\)/; const intRegex = /(? { const progress = { stringDone: false, intDone: false, floatDone: false, boolDone: false, // syntaxErrorDone: false, // optional }; if (!codeRanGood) { return { done: false, hint: "Your code had an error — try fixing it and run again." }; } if (!progress.stringDone && stringRegex.test(code)) { progress.stringDone = true; } if (!progress.floatDone && floatRegex.test(consoleText)) { progress.floatDone = true; } if (!progress.intDone && intRegex.test(consoleText)) { progress.intDone = true; } if (!progress.boolDone && boolRegex.test(consoleText)) { progress.boolDone = true; } const missing = []; if (!progress.stringDone) missing.push("string"); if (!progress.floatDone) missing.push("float"); if (!progress.intDone) missing.push("int"); if (!progress.boolDone) missing.push("boolean"); let hint = "I still need you to print a "; if (missing.length === 0) { hint = ""; } else if (missing.length === 1) { hint += missing[0]; } else { hint += missing.slice(0, -1).join(", ") + " and " + missing[missing.length - 1]; } const done = progress.stringDone && progress.intDone && progress.floatDone && progress.boolDone; return { done, progressArray: Object.values(progress), hint }; }; })() }, { id: 'lesson3', title: '3. Arithmetic Operations', difficulty: 'easy', content: `Let's get python to do our math homework for us.
Python can handle basic arithmetic operations like addition, subtraction, multiplication, and division.
Try the following operations in the code editor:
print(5 + 3)print(10 - 2)print(4 * 7)print(20 / 5)It's common for us to need to keep some data or objects over multiple lines, for that we use variables.
Think of a variable as a container that holds an object for us to use later.
To make one, we only need to give it a name, and assign it a value.
bob = 32
In this case, we created a variable called bob and assigned it the value 32.
As far as Python is concerned, bob is just a name for the number 32.
Lets test it
bob = 32print(bob)
A variable will act like any other object of its data type.
For example, if we have a variable called bob with the value 32, we can do math with it:
print(bob + 10) will print 42.
We can also change the value of a variable:
bob = 32
print(bob)
bob = bob + 10
print(bob)
In this example, the first time you print bob it will give his initial value of 32, but the second time we have added 10 to bob.
Give it a try.
`, objectives: [ "Initialize a variable with a value", "Print the variable using print()", "Alter the value of the variable", "Print the variable again using print()", ], doneCondition: (() => { return ({ code, consoleText, codeRanGood }) => { const progress = { varCreated: false, varPrinted: false, varArithmeticDone: false, varPrintedTwice: false, }; if (!codeRanGood) { return { done: false, progressArray: Object.values(progress), hint: "" }; } const assignRegex = /^(\w+)\s*=\s*.+$/m; const assignMatch = assignRegex.exec(code); if (!assignMatch) { return { done: false, progressArray: Object.values(progress), hint: "I still need you to create a variable" }; } const varName = assignMatch[1]; const printRegex = new RegExp(`print\\s*\\(\\s*${varName}\\s*\\)`, "g"); const assignAllRegex = new RegExp(`^${varName}\\s*=.+$`, "gm"); const arithmeticRegex = new RegExp( `^${varName}\\s*=\\s*${varName}\\s*[+\\-*/]\\s*.+$|^${varName}\\s*[+\\-*/]=\\s*.+$`, "gm" ); progress.varCreated = true; const printMatches = [...code.matchAll(printRegex)]; progress.varPrinted = printMatches.length > 0; if (!progress.varPrinted) { return { done: false, progressArray: Object.values(progress), hint: "I still need you to print the variable" }; } progress.varArithmeticDone = arithmeticRegex.test(code); if (!progress.varArithmeticDone) { return { done: false, progressArray: Object.values(progress), hint: "I still need you to alter the variable (e.g. with arithmetic)" }; } const assignMatches = [...code.matchAll(assignAllRegex)]; if (assignMatches.length < 2) { return { done: false, progressArray: Object.values(progress), hint: "I still need you to alter the variable before printing it again" }; } // Debug logs console.log("Variable:", varName); console.log("Assignments found:", assignMatches.length); assignMatches.forEach((m, i) => console.log(`Assign #${i}: index=${m.index}, text=${m[0].trim()}`) ); console.log("Prints found:", printMatches.length); printMatches.forEach((m, i) => console.log(`Print #${i}: index=${m.index}, text=${code.slice(m.index, m.index + 20)}`) ); console.log("Arithmetic detected:", progress.varArithmeticDone); const secondAssignIndex = assignMatches[1].index; progress.varPrintedTwice = printMatches.some((m) => m.index > secondAssignIndex); if (!progress.varPrintedTwice) { return { done: false, progressArray: Object.values(progress), hint: "I still need you to print the variable a second time after altering it", }; } return { done: true, progressArray: Object.values(progress), hint: "", }; }; })() }, { id: 'lesson6', title: '6. Conditionals', difficulty: 'easy', content: `Sometimes we want don't want part of our code to run, or we want it to run differently in different situations. That's when we use conditionals.
bob = 5
if bob > 10:
print("Bob is greater than 10")
In this example, the print function will only run if bob is 11 or higher.
One thing to note here is the formatting. Note that after the if bob > 10: there is a colon (:)
This tells Python that the next line is part of a new block of code.
In Python, we use indentation to define blocks of code, so the next line must be indented.
After the else: we also have a colon, and the next line is indented again.
Try it for yourself:
if statement to check if the variable is greater or less than a valueTo test if two values are equal, you can use the == operator.
eg.
num = 10
if num == 10:
print("num is equal to 10")
`,
objectives: [
"Initialize a variable with a value",
"Create an if statement to check a condition", ,
"Print a message based on the condition",
],
doneCondition: (() => {
return ({ code, consoleText, codeRanGood }) => {
const progress = {
varCreated: false,
ifStatement: false,
printedSomething: false,
};
if (!codeRanGood) {
return {
done: false,
hint: ""
};
}
// Check for variable assignment
const assignRegex = /\b(\w+)\s*=\s*[\d'"]/;
progress.varCreated = assignRegex.test(code);
// Check for if statement
progress.ifStatement = /(^|\n)\s*if\s+.*:/.test(code);
// Check for print() anywhere
progress.printedSomething = /print\s*\(.*\)/.test(code);
// Build hint
const missing = [];
if (!progress.varCreated) missing.push("create a variable");
if (!progress.ifStatement) missing.push("use an if statement");
if (!progress.printedSomething) missing.push("print something");
let hint = "";
if (missing.length > 0) {
hint = "I still need you to " + (missing.length === 1
? missing[0]
: missing.slice(0, -1).join(", ") + " and " + missing[missing.length - 1]);
}
const done = progress.varCreated && progress.ifStatement && progress.printedSomething;
return {
done,
progressArray: Object.values(progress),
hint
};
};
})()
},
{
id: 'lesson7',
title: '7. More Conditionals',
difficulty: 'easy',
content: `
Sometimes we'll want to run one thing OR another, rather than just running something or not. To do this we chain our if statements together with elif and else.
bob = 10
if bob == 10:
print("bob is equal to 10")
elif bob < 10:
print("bob is less than 10")
else:
print("bob is greater than 10")
In this example, only one of the print statements can ever run, elif is short for "else if", and is a second if statement which is only tested it the if above it resolves to False.
The else statement is run if all previous conditions are False.
You can chain as many elif statements as you like, but only one else at the end.
Try it for yourself:
`, objectives: [ "Initialize a variable with a value", "Create an if statement to check a condition", , "Create an elif statement to check another condition", "Create an else statement to catch all other conditions", "Print a message based on each of the conditions", ], doneCondition: (() => { return ({ code, consoleText, codeRanGood }) => { const progress = { varCreated: false, ifStatement: false, elifStatement: false, elseStatement: false, threeDistinctPrints: false, }; if (!codeRanGood) { return { done: false, hint: "" }; } // 1. Variable assignment const assignRegex = /\b(\w+)\s*=\s*[\d'"]/; progress.varCreated = assignRegex.test(code); // 2. Line-by-line block tracking const lines = code.split('\n'); let currentBlock = null; const printContents = { if: null, elif: null, else: null, }; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (/^if\s+.*:/.test(line)) { progress.ifStatement = true; currentBlock = "if"; continue; } if (/^elif\s+.*:/.test(line)) { progress.elifStatement = true; currentBlock = "elif"; continue; } if (/^else\s*:/.test(line)) { progress.elseStatement = true; currentBlock = "else"; continue; } const printMatch = line.match(/print\s*\((.*?)\)/); if (printMatch && currentBlock && !printContents[currentBlock]) { const cleaned = printMatch[1].replace(/\s+/g, '').toLowerCase(); printContents[currentBlock] = cleaned; } } const printedValues = Object.values(printContents).filter(Boolean); const uniqueValues = new Set(printedValues); progress.threeDistinctPrints = uniqueValues.size === 3; // Hint generation const missing = []; if (!progress.varCreated) missing.push("create a variable"); if (!progress.ifStatement) missing.push("use an if statement"); if (!progress.elifStatement) missing.push("use an elif statement"); if (!progress.elseStatement) missing.push("use an else statement"); if (!progress.threeDistinctPrints) missing.push("print different things in the if, elif, and else blocks"); const hint = missing.length > 0 ? "I still need you to " + (missing.length === 1 ? missing[0] : missing.slice(0, -1).join(", ") + " and " + missing[missing.length - 1]) : ""; const done = progress.varCreated && progress.ifStatement && progress.elifStatement && progress.elseStatement && progress.threeDistinctPrints; return { done, progressArray: Object.values(progress), hint }; }; })() }, { id: 'lesson8', title: '8. Loops', difficulty: 'easy', content: `Most of the time we'll want our code to run multiple times, or even endlessly, in that case we need loops.
Python has two main types of loops: for loops and while loops.
The while loop will continue to run as long as a condition is True.
count = 0
while count < 5:
print("Count is:", count)
count = count + 1
print("Done!")
You have to be careful with while loops, if the condition never becomes False, the loop will run forever!