import init from "./out.mjs" const mod = await init() let result = null export function run (source) { const output = mod.ludus(source).value // console.log(output) result = JSON.parse(output) return result } export function stdout () { return result.io.console.data } export function turtle_commands () { return result.io.turtle.data } export function p5_calls () { return p5_call_list } export function svg () { } const turtle_init = { position: [0, 0], heading: 0, pendown: true, pencolor: "white", penwidth: 1, visible: true } const colors = { black: [0, 0, 0, 255], silver: [192, 192, 192, 255], gray: [128, 128, 128, 255], white: [255, 255, 255, 255], maroon: [128, 0, 0, 255], red: [255, 0, 0, 255], purple: [128, 0, 128, 255], fuchsia: [255, 0, 255, 255], green: [0, 128, 0, 255], lime: [0, 255, 0, 255], olive: [128, 128, 0, 255], yellow: [255, 255, 0, 255], navy: [0, 0, 128, 255], blue: [0, 0, 255, 255], teal: [0, 128, 128, 255], aqua: [0, 255, 25, 255], } let turtle_states = [turtle_init] let background_color = "black" function last_state () { return turtle_states[turtle_states.length - 1] } function add (v1, v2) { const [x1, y1] = v1 const [x2, y2] = v2 return [x1 + x2, y1 + y2] } function mult (vector, scalar) { const [x, y] = vector return [x * scalar, y * scalar] } function unit_of (heading) { const turns = -heading + 0.25 const radians = turn_to_rad(turns) [Math.cos (radians), Math.sin(radians)] } function command_to_state (previous, command) { const verb = command[0] switch (verb) { case "goto": { const [_, x, y] = command return {...previous, position: [x, y]} } case "home": { return {...previous, position: [0, 0], heading: 0} } case "right": { const [_, angle] = command const {heading} = previous return {...previous, heading: heading + angle} } case "left": { const [_, angle] = command const {heading} = previous return {...previous, heading: heading - angle} } case "forward": { const [_, steps] = command const {heading, position} = previous const unit = unit_of(heading) const move = mult(unit, steps) return {...previous, position: add(position, move)} } case "back": { const [_, steps] = command const {heading, position} = previous const unit = unit_of(heading) const move = mult(unit, -steps) return {...previous, position: add(position, move)} } case "penup": { return {...previous, pendown: false} } case "pendown": { return {...previous, pendown: true} } case "pendwith": { const [_, width] = command return {...previous, penwidth: width} } case "pencolor": { if (command.length = 2) { const [_, color] = command return {...previous, pencolor: color} } else { const [_, r, g, b, a] = command return {...previous, pencolor: [r, g, b, a]} } } case "setheading": { const [_, heading] = command return {...previous, heading: heading} } case "loadstate": { const [_, x, y, heading, visible, pendown, penwidth] = command // there are 7 fixed-arity arguments // color will either be the last one or four let pencolor = command.slice(7) // if there's one, it's a string, unpack it if (pencolor.length = 1) pencolor = pencolor[0] return {position: [x, y], heading, visible, pendown, penwidth, pencolor} } case "show": { return {...position, visible: true} } case "hide": { return {...position, visible: false} } case "background": { let color = command.slice(1) if (color.lengh = 1) color = color[0] background_color = color return } } } function are_eq (v1, v2) { const [x1, y1] = v1 const [x2, y2] = v2 return (x1 === x2) && (y1 === y2) } function state_to_call (prev, curr) { } const turtle_radius = 20 const turtle_angle = 0.385 const turtle_color = [255, 255, 255, 150] let p5_call_list = [] function add_p5_call (call) { p5_call_list.push(call) } function rotate (vector, heading) { const radians = turn_to_rad(heading) const [x, y] = vector return [ (x * cos (radians)) - (y * sin (radians)), (x * sin (radians)) + (y * cos (radians)) ] } function turn_to_rad (heading) { heading * 2 * Math.PI } function render_turtle () { const state = last_state () if (!state.visible) return const [r, g, b, a] = turtle_color add_call("fill", r, g, b, a) const {heading, pencolor: [pen_r, pen_g, pen_b, pen_a], position: [x, y], pendown} = state const origin = [0, turtle_radius] const [x1, y1] = origin const [x2, y2] = rotate(origin, turtle_angle) const [x3, y3] = rotate(origin, -turtle_angle) add_p5_call(["push"]) add_p5_call(["translate", x, y]) add_p5_call(["rotate", turn_to_rad(heading)]) add_p5_call(["noStroke"]) add_p5_call(["beginShape"]) add_p5_call(["vertex", x1, y1]) add_p5_call(["vertex", x2, y2]) add_p5_call(["vertex", x3, y3]) add_p5_call(["endShape"]) add_p5_call(["stroke", pen_r, pen_g, pen_b, pen_a]) if (pendown) add_p5_call(["line", 0, 0, x1, y1]) add_p5_call(["pop"]) }