diff --git a/data/lessons.js b/data/lessons.js index b432f17..0cdbdf7 100644 --- a/data/lessons.js +++ b/data/lessons.js @@ -848,77 +848,6 @@ print("Done!") })() - }, - { - id: 'robot1', - title: '1. Moving the Robot', - tabtitle: 'Importing Modules', - level: 'robot', - content: ` -

This robot simulation is a simplified version of a real robot.

-

It has a single library which you can use to access all its controls and sensors.

-

In a real robot you would have many different libraries for different parts, sensors, and even microcontroller functions.

-
-

We'll start by importing the robot library, and using it to move.

-

-import robot  # Import the robot library
-import time  # Import the time module
-
-robot.move(1) # Move forward at max speed
-time.sleep(2)  # Wait for 2 seconds
-robot.move(-1) # Move backward at max speed
-time.sleep(2)  # Wait for 2 seconds
-robot.move(0) # Stop the robot
-
- `, - objectives: [ - "Reach the first checkpoint", - "Reach the second checkpoint", - - "Code should complete without errors" - ], - - doneCondition: (() => { - return ({ code, consoleText, codeRanGood, gameWorld }) => { - const progress = { - firstCheckpoint: gameWorld.waypointsReached[0], - secondCheckpoint: gameWorld.waypointsReached[1], - codeRanGood: codeRanGood, - - }; - - if (!codeRanGood) { - return { done: false, hint: "" }; - } - - - - // 5. Build hint - const missing = []; - if (!progress.firstCheckpoint) missing.push("reach the first checkpoint"); - if (!progress.secondCheckpoint) missing.push("reach the second checkpoint"); - - let hint = ""; - if (missing.length === 1) { - hint = `I still need you to ${missing[0]}`; - } else if (missing.length > 1) { - hint = `I still need you to ${missing.slice(0, -1).join(", ")} and ${missing.at(-1)}`; - } - - return { - done: - progress.firstCheckpoint && - progress.secondCheckpoint && - progress.codeRanGood, - progressArray: Object.values(progress), - hint, - }; - }; - })() - - - - }, { id: 'lesson10', @@ -1022,5 +951,147 @@ print("Done!") + }, + + { + id: 'robot1', + title: '1. Moving the Robot', + tabtitle: 'Importing Modules', + level: 'robot', + map: 'Level 1', + content: ` +

This robot simulation is a simplified version of a real robot.

+

It has a single library which you can use to access all its controls and sensors.

+

In a real robot you would have many different libraries for different parts, sensors, and even microcontroller functions.

+
+

We'll start by importing the robot library, and using it to move.

+

+import robot  # Import the robot library
+import time  # Import the time module
+
+robot.move(1) # Move forward at max speed
+time.sleep(2)  # Wait for 2 seconds
+robot.move(-1) # Move backward at max speed
+time.sleep(2)  # Wait for 2 seconds
+robot.move(0) # Stop the robot
+
+ `, + objectives: [ + "Reach the first checkpoint", + "Reach the second checkpoint", + + "Code should complete without errors" + ], + + doneCondition: (() => { + return ({ code, consoleText, codeRanGood, gameWorld }) => { + const progress = { + firstCheckpoint: gameWorld.waypointsReached[0], + secondCheckpoint: gameWorld.waypointsReached[1], + codeRanGood: codeRanGood, + + }; + + if (!codeRanGood) { + return { done: false, hint: "" }; + } + + + + // 5. Build hint + const missing = []; + if (!progress.firstCheckpoint) missing.push("reach the first checkpoint"); + if (!progress.secondCheckpoint) missing.push("reach the second checkpoint"); + + let hint = ""; + if (missing.length === 1) { + hint = `I still need you to ${missing[0]}`; + } else if (missing.length > 1) { + hint = `I still need you to ${missing.slice(0, -1).join(", ")} and ${missing.at(-1)}`; + } + + return { + done: + progress.firstCheckpoint && + progress.secondCheckpoint && + progress.codeRanGood, + progressArray: Object.values(progress), + hint, + }; + }; + })() + }, + { + id: 'robot1', + title: '2. Steering the Robot', + tabtitle: 'Importing Modules', + level: 'robot', + map: 'Level 2', + content: ` +

Turning is very similar to moving, we use the robot.turn(amount) function.

+

The amount parameter is a number between -1 and 1, where -1 is full left, 0 is no turn, and 1 is full right.

+ +

+import robot 
+import time
+
+robot.turn(1)
+time.sleep(2) 
+robot.turn(0)
+
+
+

This code causes the robot to turn right at max speed for 2 seconds, then stop.

+ +

You'll need to combine moving, turning, and waiting to reach all the checkpoints.

+

Note: The values for move, turn, and sleep can all be decimal numbers (floats). ie time.sleep(0.5) or robot.move(0.8)

+ `, + objectives: [ + "Reach the first checkpoint", + "Reach the second checkpoint", + + "Code should complete without errors" + ], + + doneCondition: (() => { + return ({ code, consoleText, codeRanGood, gameWorld }) => { + const progress = { + firstCheckpoint: gameWorld.waypointsReached[0], + secondCheckpoint: gameWorld.waypointsReached[1], + codeRanGood: codeRanGood, + + }; + + if (!codeRanGood) { + return { done: false, hint: "" }; + } + + + + // 5. Build hint + const missing = []; + if (!progress.firstCheckpoint) missing.push("reach the first checkpoint"); + if (!progress.secondCheckpoint) missing.push("reach the second checkpoint"); + + let hint = ""; + if (missing.length === 1) { + hint = `I still need you to ${missing[0]}`; + } else if (missing.length > 1) { + hint = `I still need you to ${missing.slice(0, -1).join(", ")} and ${missing.at(-1)}`; + } + + return { + done: + progress.firstCheckpoint && + progress.secondCheckpoint && + progress.codeRanGood, + progressArray: Object.values(progress), + hint, + }; + }; + })() + + + + }, ]; diff --git a/data/levels.json b/data/levels.json index 6f224d3..6d3ed60 100644 --- a/data/levels.json +++ b/data/levels.json @@ -209,7 +209,33 @@ "waypoints": [ { "position": { - "x": 220, + "x": 420, + "y": 200 + }, + "vertices": [ + { + "x": -50, + "y": -50 + }, + { + "x": 50, + "y": -50 + }, + { + "x": 50, + "y": 50 + }, + { + "x": -50, + "y": 50 + } + ], + "strokeColor": "#0000FF", + "fillColor": "#0000CC" + }, + { + "position": { + "x": 420, "y": 500 }, "vertices": [ @@ -230,7 +256,7 @@ "y": 50 } ], - "strokeColor": "#000099", + "strokeColor": "#0000FF", "fillColor": "#0000CC" } ], @@ -255,8 +281,8 @@ } ], "position": { - "x": 200, - "y": 400 + "x": 800, + "y": 300 }, "strokeColor": "#999999", "fillColor": "#CCCCCC" diff --git a/game.js b/game.js index 561bb64..0820d9d 100644 --- a/game.js +++ b/game.js @@ -23,6 +23,21 @@ function showLesson(index) { loadLessonContent(lesson); updateTabs(lessons, index); + if (lesson.map) { + console.log("Loading map for lesson:", lesson.map); + document.getElementById('gameCanvas').style.display = 'block'; + for (let i = 0; i < gameWorld.levelData.length; i++) { + if (gameWorld.levelData[i].name === lesson.map) { + gameWorld.currentLevel = i; + console.log("Setting current level to:", i); + break; + } + } + resetGameWorld(); + } else { + document.getElementById('gameCanvas').style.display = 'none'; + } + document.getElementById('prev-lesson').disabled = index === 0; document.getElementById('next-lesson').disabled = index === lessons.length - 1; @@ -95,6 +110,7 @@ function checkLessonDone() { codeRanGood: codeRanGood, gameWorld: gameWorld }); + console.log(gameWorld.waypointsReached); if (result.done) { markLessonDone(lesson.id); } @@ -221,7 +237,7 @@ function toggleObjective(index, completed = true) { } //clearLessonProgress(); // Clear progress on load for testing -showLesson(9); + const consoleElement = document.getElementById("console"); const gameCanvas = document.getElementById("gameCanvas"); @@ -385,6 +401,8 @@ function resetGame() { document.getElementById("pause-button").innerText = "Pause"; logToConsole("Welcome to the game! Type your Python code in the editor and click 'Compile' to execute it."); + + document.getElementById('compile-button').disabled = false; } const targetFPS = 30; @@ -405,10 +423,10 @@ function gameLoop(timestamp) { ctx.translate(offsetX, offsetY); // Apply panning ctx.scale(scale, scale); // Apply zooming - + gameWorld.update(); gameWorld.draw(ctx); - +console.log(gameWorld.waypointsReached); // if (gameWorld.checkPlayerCompletedTask()) { // logToConsole("✅ Task Completed! ✅"); // togglePause(); @@ -557,16 +575,18 @@ function setupCanvas() { } // Call this function when the page loads - fetch('/data/levels.json') .then(response => response.json()) .then(data => { gameWorld.levelData = data; + setupCanvas(); resetGame(); // Initialize the game and robots // Start game loop gameLoop(); + + showLesson(11); }); diff --git a/pyodide-worker.js b/pyodide-worker.js index 293c638..dbe920a 100644 --- a/pyodide-worker.js +++ b/pyodide-worker.js @@ -31,7 +31,7 @@ async function initializePyodide() { sensorData = sensorArray.map(sensor => ({ "type": sensor.type, // Individual sensor's type "angle": sensor.angle, // Individual sensor's angle - "distance": sensor.distance, // Individual sensor's distance + "distance": Math.round(sensor.distance * 100) / 100, // Individual sensor's distance "hitpoint": sensor.hitpoint // Whatever other attributes you need })); //console.log(sensorData["x"]); @@ -69,6 +69,12 @@ class RobotModule: sensor_data = json.loads(get_sensor_data(name)) return sensor_data + def get_distance_left(self): + return self.get_sensors()[0]["distance"] + + def get_distance_right(self): + return self.get_sensors()[1]["distance"] + def get_sensors(self): return json.loads(get_sensor_data("sensors")) # Returns list of sensor dicts diff --git a/readme.md b/readme.md index e4c0417..99842aa 100644 --- a/readme.md +++ b/readme.md @@ -29,4 +29,24 @@ while True: robot.turn(-0.01) else: robot.turn(0) - time.sleep(0.1) \ No newline at end of file + time.sleep(0.1) + + + + + + + + + + +import time +import robot + +robot.move(1) +time.sleep(1.6) +robot.move(0) +robot.turn(1) +time.sleep(2.2) +robot.turn(0) +robot.move(1) \ No newline at end of file