253 lines
8.6 KiB
JavaScript
253 lines
8.6 KiB
JavaScript
export const lessons = [
|
|
{
|
|
id: 'lesson1',
|
|
title: '1. Introduction to Python',
|
|
difficulty: 'easy',
|
|
content: `
|
|
<p>Let's learn some Python..</p>
|
|
<p>We'll start with what's called a "Hello World" program to make sure everythings working.</p>
|
|
<p>In Python, this is done with the <code>print</code> function.</p>
|
|
<ol>
|
|
<li>In the code editor below, type <code>print("Hello World")</code></li>
|
|
<li>Click the "Run" button to execute your code</li>
|
|
<li>You should see "Hello World" printed in the output area</li>
|
|
</ol>
|
|
`,
|
|
doneCondition: (consoleText) => consoleText.includes("Hello World")
|
|
},
|
|
{
|
|
id: 'lesson2',
|
|
title: 'Data Types and Variables',
|
|
difficulty: 'easy',
|
|
content: `
|
|
<p>Did you try typeing <code>print(Hello World)</code>, without the quotation marks?</p>
|
|
<p>If you didn't, give it a try now.</p>
|
|
</br>
|
|
<p>Thats what we call a <strong>Syntax Error</strong>.</p>
|
|
<p>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.</p>
|
|
</br>
|
|
String is just one of the many <strong>Data Types</strong> that Python has.</p>
|
|
To continue, I want you to print the following all at once, each on a new line:
|
|
<ol>
|
|
<li>String: <code>print("Hello World")</code></li>
|
|
<li>Integer: <code>print(42)</code></li>
|
|
<li>Float: <code>print(3.14)</code></li>
|
|
<li>Boolean: <code>print(True)</code></li>
|
|
</ol>
|
|
<p>Click the "Run" button to execute your code</p>
|
|
`,
|
|
doneCondition: (consoleText => {
|
|
// Persistent tracking object inside closure
|
|
const progress = {
|
|
stringDone: false,
|
|
intDone: false,
|
|
floatDone: false,
|
|
boolDone: false,
|
|
syntaxErrorDone: false,
|
|
};
|
|
|
|
//const syntaxErrorRegex = /SyntaxError/i;
|
|
const stringRegex = /(["'])(?:(?=(\\?))\2.)*?\1/; // optional improvement based on context
|
|
const intRegex = /(?<![\d.])[-+]?\d+(?![\d.])/;
|
|
const floatRegex = /[-+]?(?:\d+\.\d*|\.\d+)(?:[eE][-+]?\d+)?/;
|
|
const boolRegex = /\b(True|False|true|false)\b/;
|
|
|
|
return (text) => {
|
|
|
|
|
|
// if (!progress.syntaxErrorDone && syntaxErrorRegex.test(text)) {
|
|
// progress.syntaxErrorDone = true;
|
|
// }
|
|
if (!progress.stringDone && stringRegex.test(text)) {
|
|
progress.stringDone = true;
|
|
}
|
|
if (!progress.floatDone && floatRegex.test(text)) {
|
|
progress.floatDone = true;
|
|
}
|
|
if (!progress.intDone && intRegex.test(text)) {
|
|
progress.intDone = true;
|
|
}
|
|
if (!progress.boolDone && boolRegex.test(text)) {
|
|
progress.boolDone = true;
|
|
}
|
|
|
|
let missing = [];
|
|
|
|
//if (!progress.syntaxErrorDone) missing.push("syntax error");
|
|
//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 {
|
|
// Join all but last with comma, then add 'and' + last
|
|
hint += missing.slice(0, -1).join(", ") + " and " + missing[missing.length - 1];
|
|
}
|
|
|
|
|
|
const done = progress.intDone && progress.floatDone && progress.boolDone;
|
|
|
|
return { done, hint };
|
|
};
|
|
})()
|
|
},
|
|
{
|
|
id: 'lesson3',
|
|
title: '3. Arithmetic Operations',
|
|
difficulty: 'easy',
|
|
content: `
|
|
<p>Let's get python to do our math homework for us.</p>
|
|
<p>Python can handle basic arithmetic operations like addition, subtraction, multiplication, and division.</p>
|
|
<p>Try the following operations in the code editor:</p>
|
|
<ol>
|
|
<li>Addition: <code>print(5 + 3)</code></li>
|
|
<li>Subtraction: <code>print(10 - 2)</code></li>
|
|
<li>Multiplication: <code>print(4 * 7)</code></li>
|
|
<li>Division: <code>print(20 / 5)</code></li>
|
|
</ol>
|
|
`,
|
|
doneCondition: (consoleText => {
|
|
// Persistent tracking object inside closure
|
|
const progress = {
|
|
addDone: false,
|
|
subDone: false,
|
|
mulDone: false,
|
|
divDone: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
return (text) => {
|
|
|
|
|
|
// if (!progress.syntaxErrorDone && syntaxErrorRegex.test(text)) {
|
|
// progress.syntaxErrorDone = true;
|
|
// }
|
|
if (!progress.addDone && text.includes("+")) {
|
|
progress.addDone = true;
|
|
}
|
|
if (!progress.subDone && text.includes("-")) {
|
|
progress.subDone = true;
|
|
}
|
|
if (!progress.mulDone && text.includes("*")) {
|
|
progress.mulDone = true;
|
|
}
|
|
if (!progress.divDone && text.includes("/")) {
|
|
progress.divDone = true;
|
|
}
|
|
|
|
let missing = [];
|
|
|
|
//if (!progress.syntaxErrorDone) missing.push("syntax error");
|
|
//if (!progress.stringDone) missing.push("string");
|
|
if (!progress.addDone) missing.push("addition");
|
|
if (!progress.subDone) missing.push("subtraction");
|
|
if (!progress.mulDone) missing.push("multiplication");
|
|
if (!progress.divDone) missing.push("division");
|
|
let hint = "I still need you to do some ";
|
|
|
|
if (missing.length === 0) {
|
|
hint = "";
|
|
} else if (missing.length === 1) {
|
|
hint += missing[0];
|
|
} else {
|
|
// Join all but last with comma, then add 'and' + last
|
|
hint += missing.slice(0, -1).join(", ") + " and " + missing[missing.length - 1];
|
|
}
|
|
|
|
|
|
const done = progress.addDone && progress.subDone && progress.mulDone && progress.divDone;
|
|
return { done, hint };
|
|
};
|
|
})()
|
|
},
|
|
{
|
|
id: 'lesson4',
|
|
title: '4. Variables',
|
|
difficulty: 'easy',
|
|
content: `
|
|
<p>It's common for us to need to keep some data or objects over multiple lines, for that we use <strong>variables</strong>.</p>
|
|
<p>Think of a variable as a container that holds an object for us to use later.</p>
|
|
<p>To make one, we only need to give it a name, and assign it a value.</p>
|
|
<p><code>bob = 32</code></p>
|
|
<p>In this case, we created a variable called <code>bob</code> and assigned it the value <code>32</code>.</p>
|
|
<p>As far as Python is concerned, <code>bob</code> is just a name for the number <code>32</code>.</p>
|
|
<p>Lets test it</p>
|
|
<ol>
|
|
<li>Initialize bob with the value 32: <code>bob = 32</code></li>
|
|
<li>Print the value of bob: <code>print(bob)</code></
|
|
</ol>
|
|
`,
|
|
steps: [
|
|
{
|
|
content: `<p>First, try printing an addition: <code>print(2 + 3)</code></p>`,
|
|
doneCondition: (text) => text.includes("5"),
|
|
},
|
|
{
|
|
content: `<p>Nice! Now try subtraction: <code>print(5 - 2)</code></p>`,
|
|
doneCondition: (text) => text.includes("3"),
|
|
},
|
|
{
|
|
content: `<p>Now try multiplication: <code>print(4 * 2)</code></p>`,
|
|
doneCondition: (text) => text.includes("8"),
|
|
}
|
|
],
|
|
doneCondition: (code => {
|
|
const progress = {
|
|
varCreated: false,
|
|
varPrinted: false,
|
|
varName: null,
|
|
};
|
|
|
|
return (text) => {
|
|
// Extract variable name from current text each time
|
|
const assignMatch = text.match(/^\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=/m);
|
|
if (assignMatch) {
|
|
progress.varName = assignMatch[1];
|
|
progress.varCreated = true;
|
|
} else {
|
|
// No variable assignment found this run
|
|
progress.varCreated = false;
|
|
progress.varName = null;
|
|
progress.varPrinted = false; // reset printed too because no var
|
|
}
|
|
|
|
// Check if variable is printed in this run (only if varName exists)
|
|
if (progress.varCreated && progress.varName) {
|
|
const printRegex = new RegExp(`print\\s*\\(\\s*${progress.varName}\\s*\\)`);
|
|
if (printRegex.test(text)) {
|
|
progress.varPrinted = true;
|
|
} else {
|
|
progress.varPrinted = false; // reset if print no longer found
|
|
}
|
|
}
|
|
|
|
// Build hint
|
|
let missing = [];
|
|
if (!progress.varCreated) missing.push("create a variable");
|
|
if (progress.varCreated && !progress.varPrinted) missing.push("print the variable");
|
|
|
|
let hint = "I still need you to ";
|
|
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.varCreated && progress.varPrinted;
|
|
return { done, hint };
|
|
};
|
|
})()
|
|
|
|
|
|
},
|
|
];
|