JSFiddle - React, Tailwind, and code Playground
by bnickel
HTML
<div class="drawing-area">
<canvas width="500" height="300"></canvas>
</div>
<textarea>
# TurtleScript
set-color green # color (or any valid canvas style)
move 50 # pixels
turn-left 100 # degrees
set-color yellow
move 40
turn-right 150
</textarea>
<button id="execute">Push Commands</button>
<button id="execute10">Push Commands 10 times</button>
<button id="reset">Push <tt>reset</tt></button>
<button id="clear">Push <tt>clear</tt></button>
CSS
body {
width: 500px;
margin: 5px auto;
}
.drawing-area, textarea {
display: block;
width: 502px;
margin: 5px auto;
position: relative;
}
.drawing-area {
border: 1px solid black;
}
#turtle {
position: absolute;
width: 6px;
height: 6px;
margin-top: -3px;
margin-left: -3px;
border-radius: 3px;
border: 1px solid black;
box-sizing: border-box;
}
textarea {
box-sizing: border-box;
height: 10em;
font-family: monospace;
}
JavaScript
/**
* A super-lazy event manager. Internally it uses a HTML element to store events.
*/
function EventManager(el) {
el = el || document.createElement('span');
function dispatchCustomEvent(type, details) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent(type, false, true, details);
this.dispatchEvent(event);
return event;
}
this.addEventListener = el.addEventListener.bind(el);
this.dispatchEvent = el.dispatchEvent.bind(el);
this.dispatchCustomEvent = dispatchCustomEvent;
}
function CommandParser() {
var NOOP_PATTERN = /^\s*(?:#.*)?$/;
var LINE_PATTERN = /^\s*([\w\-]+)(?:\s*([^#]*))?/;
var ARGS_PATTERN = /\s*,\s*/;
function parseCommand(command) {
if (NOOP_PATTERN.test(command)) {
return {
command: 'noop',
args: []
};
}
var components = command.match(LINE_PATTERN);
if (!components) {
return {
command: 'parse-error',
args: [command]
};
}
return {
command: components[1],
args: components[2] ? components[2].trim().split(ARGS_PATTERN) : []
};
}
function parseCommands(commands) {
return commands.split(/\r?\n/).map(parseCommand);
}
this.parseCommand = parseCommand;
this.parseCommands = parseCommands;
}
function StatelessTurtle(eventManager, commandParser) {
eventManager = eventManager || new EventManager();
commandParser = commandParser || new CommandParser();
var running = false;
var pendingCommands = [];
var commandMap;
function trigger(name, details) {
details.resumeExecution = executeNextCommand;
return eventManager.dispatchCustomEvent(name, details);
}
// TODO: It would be really cool if we injected commands.
function reset() {
return trigger('reset', {});
}
function...