From c602113cdb101e4664037eed3771559c0770f1c5 Mon Sep 17 00:00:00 2001
From: Carl Worth <cworth@cworth.org>
Date: Fri, 23 Dec 2022 09:52:22 -0800
Subject: [PATCH] Assign different default code to each boy

Also, draw the solution text in white on top, (so if they generate
their picture frequently, they can just make out the letters and
numbers).
---
 bus.html                  | 21 ++++-------
 index.js                  | 75 ++++++++++++++++++++++++++++++++++++++-
 interpret-cairo-to-svg.py | 73 +++++++++++++++++++++++++++++++++++--
 3 files changed, 151 insertions(+), 18 deletions(-)

diff --git a/bus.html b/bus.html
index f16a509..5760786 100644
--- a/bus.html
+++ b/bus.html
@@ -117,23 +117,10 @@
     </div>
 
     <div id="program" style="visibility: hidden">
-      <h1>
-	Magic School Bus Central Processor
+      <h1>Magic School Bus</h1>
       </h1>
       <form id="form">
-	<textarea id="code" rows="10" width="100%">def random_dot():
-  x = 200 * random()
-  y = 200 * random()
-  radius = 4 + 6 * random()
-  circle(x, y, radius)
-  fill()
-
-for i in range(100):
-  if i %2 == 0:
-    set_color('red')
-  else:
-    set_color('blue')
-  random_dot()</textarea>
+	<textarea id="code" rows="15" width="100%"></textarea>
 	<button type="submit">Run code</button>
       </form>
       <img id="output"></img>
@@ -185,6 +172,10 @@ for i in range(100):
 	students.textContent = count.toString();
     });
 
+    socket.on('code', (code_string) => {
+	code.value = code_string;
+    });
+
     socket.on('timer', (value) => {
 	timer_div.style.visibility = "visible";
 	timer.textContent = value.toString();
diff --git a/index.js b/index.js
index 6aef48c..606fba7 100644
--- a/index.js
+++ b/index.js
@@ -180,6 +180,52 @@ function start_bus_timer() {
     bus_interval = setInterval(emit_bus_timer, 1000);
 }
 
+bus_code = [
+    `def random_dot():
+  x = random_within(512)
+  y = random_within(512)
+  radius = 4 + random_within(6)
+  circle(x, y, radius)
+  fill()
+
+for i in range(400):
+  set_color('midnight blue' if i % 2 == 0 else 'navy blue')
+  set_opacity(0.5)
+  random_dot()`,
+
+    `def random_line():
+  x = random_within(512) - 60
+  y = random_within(512) - 60
+  dx = 60 + random_within(20)
+  dy = 40 + random_within(20)
+  set_opacity(random_within(0.5))
+  line(x, y, dx, dy)
+  stroke()
+
+for i in range(200):
+  set_color('black')
+  random_line()`,
+
+    `def random_blob():
+  move_to(random_within(512), random_within(512))
+  wiggle()
+  set_opacity(random_within(1.0))
+  fill()
+
+for i in range(100):
+  set_random_color()
+  random_blob()`,
+
+    `def random_curve():
+  move_to(random_within(512), random_within(512))
+  wiggle()
+  stroke()
+
+for i in range(200):
+  set_color('pink' if i % 2 == 0 else 'lime green')
+  random_curve()`
+];
+
 io_bus.on("connection", (socket) => {
     if (! socket.request.session.name) {
 	console.log("Error: Someone showed up at the Magic School Bus without a name.");
@@ -188,6 +234,7 @@ io_bus.on("connection", (socket) => {
 
     const name = socket.request.session.name;
     const bus = state.bus;
+    var player_number;
 
     // Let the new user know the state of the bus
     socket.emit("state", bus.state);
@@ -196,6 +243,32 @@ io_bus.on("connection", (socket) => {
 	start_bus_timer();
     }
 
+    // Assign each boy a different portion of the solution
+    switch (name[0]) {
+    case 'C':
+    case 'c':
+	player_number = 0;
+	break;
+    case 'H':
+    case' h':
+	player_number = 1;
+	break;
+    case 'A':
+    case 'a':
+	player_number = 2;
+	break;
+    case 'S':
+    case 's':
+	player_number = 3;
+	break;
+    default:
+	player_number = Math.floor(Math.random()*4);
+	break;
+    }
+
+    // And send them different code based on their number
+    socket.emit("code", bus_code[player_number]);
+
     if (! bus.students.names.includes(name)) {
 	bus.students.count = bus.students.count + 1;
 	io_bus.emit('students', bus.students.count);
@@ -204,7 +277,7 @@ io_bus.on("connection", (socket) => {
 
     socket.on('run', code => {
 	try {
-	    output = child_process.execFileSync(python_path, [interpret_cairo_script, code], { input: code });
+	    output = child_process.execFileSync(python_path, [interpret_cairo_script, player_number], { input: code });
 	    // Grab just first line of output
 	    const nl = output.indexOf("\n");
 	    if (nl === -1)
diff --git a/interpret-cairo-to-svg.py b/interpret-cairo-to-svg.py
index bc0c6b1..99edf1b 100755
--- a/interpret-cairo-to-svg.py
+++ b/interpret-cairo-to-svg.py
@@ -26,6 +26,13 @@ if "import" in input:
 os.close(fd)
 os.chmod(filename, 0o644)
 
+if len(sys.argv) < 2:
+    sys.stderr.write("This script requires a single argument (value, 1 - 4)")
+    sys.exit(1)
+
+user = int(sys.argv[1])
+stderr = sys.stderr
+
 # Also delete our import for some more safety
 del tempfile
 del os
@@ -791,10 +798,38 @@ COLORS = {
     'yellowgreen': (0x9a/0xff, 0xcd/0xff, 0x32/0xff)
 }
 
+hint = [
+    "WAT", "ER ", "PLA", "NET"
+]
+
+code = [
+    "304", "570", "325", "6"
+]
+
+r = 0
+g = 0
+b = 0
+a = 1.0
+
 with cairo.SVGSurface(filename, 512, 512) as surface:
+
     cr = cairo.Context(surface);
+    cr.set_font_size(190)
+    cr.select_font_face("sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
     del cairo
 
+    def random_within(max):
+        return max * random()
+
+    def wiggle():
+        delta = 200
+        cr.rel_curve_to(-delta/2 + random_within(delta),
+                        -delta/2 + random_within(delta),
+                        -delta/2 + random_within(delta),
+                        -delta/2 + random_within(delta),
+                        -delta/2 + random_within(delta),
+                        -delta/2 + random_within(delta))
+ 
     def arc(x, y, r, a1, a2):
         cr.arc(x, y, r, a1, a2)
 
@@ -804,18 +839,52 @@ with cairo.SVGSurface(filename, 512, 512) as surface:
     def fill():
         cr.fill()
 
+    def stroke():
+        cr.stroke()
+
     def set_color(color):
+        global r, g, b, a
         if color in COLORS:
             (r,g,b) = COLORS[color]
         else:
             (r,g,b) = (0,0,0)
-        cr.set_source_rgb(r, g, b)
+        cr.set_source_rgba(r, g, b, a)
+
+    def set_random_color():
+        global r, g, b, a
+        (r,g,b) = rand.choice(list(COLORS.values()))
+        cr.set_source_rgba(r, g, b, a)
+
+    def set_opacity(opacity):
+        global a
+        a = opacity
+        cr.set_source_rgba(r, g, b, a)
+
+    def move_to(x, y):
+        cr.move_to(x, y)
 
-    cr.set_line_width(6)
+    def line_to(x, y):
+        cr.line_to(x, y)
+
+    def line(x, y, dx, dy):
+        cr.move_to(x, y)
+        cr.rel_line_to(dx, dy)
+
+    def set_line_width(width):
+        cr.set_line_width(width)
 
     # Run the submitted code
     exec(input)
 
+    # After the submitted code, draw the solution in white, (so it will
+    # only be clearly visible if they've made their drawing big enough).
+    cr.set_source_rgb(1, 1, 1)
+    cr.move_to(0,250)
+    cr.show_text(hint[user])
+    cr.set_font_size(240)
+    cr.move_to(0,480)
+    cr.show_text(code[user])
+
 web_file = filename.removeprefix(OUTPUT_DIR_PREFIX)
 
 print(web_file)
-- 
2.45.2