/* built with Studio Sketchpad:
* https://sketchpad.cc
*
* observe the evolution of this sketch:
* https://studio.sketchpad.cc/sp/pad/view/ro.OyQtf99prDW/rev.4145
*
* authors:
* J.D. Zamfirescu
* J.D. Zamfirescu
* J.D. Zamfirescu
* license (unless otherwise specified):
* creative commons attribution-share alike 3.0 license.
* https://creativecommons.org/licenses/by-sa/3.0/
*/
init();
// level 1
down();
down();
down();
down();
down();
down();
down();
right();
right();
right();
up();
up();
right();
right();
right();
right();
// level 2
var doSeven = function(dir) {
dir();
dir();
dir();
dir();
dir();
dir();
dir();
}
down();
doSeven(down);
right();
right();
doSeven(up);
right();
right();
doSeven(down);
right();
right();
doSeven(up);
right();
right();
doSeven(down);
right();
// level 3
right();
right();
if (color() == "blue") {
down();
} else {
up();
}
right();
right();
if (color() == "blue") {
down();
} else {
up();
}
right();
right();
if (color() == "blue") {
down();
} else {
up();
}
right();
right();
right();
// level 4
goUntilColor = function(dir, c) {
if (color() != c) {
dir()
goUntilColor(dir, c);
}
}
goUntilColor(down, "red");
right();
right();
goUntilColor(up, "red");
right();
right();
goUntilColor(down, "red");
right();
right();
goUntilColor(up, "red");
right();
right();
goUntilColor(down, "red");
right();
// ROBOT CODE
size(340, 340);
background(255);
var MOVETIME = 200;
var position = null;
function init() {
window.sim = {
position: null,
levels: [],
simulation: [],
level: 0
};
with(window.sim) {
levels = [
{trash: new PositionSet([ {x: 5, y: 5}, {x: 7, y: 5} ]),
obstacles: makeObstacles(2, 0, 1, 7) },
{trash: new PositionSet([ {x: 9, y: 8 } ]),
obstacles: makeObstacles(1,0,1,8).concat(makeObstacles(3,2,1,8)).concat(makeObstacles(5,0,1,8)).concat(makeObstacles(7,2,1,8)).concat(makeObstacles(9,0,1,8)) },
level3(),
level4()
];
position = levels[level].start || {x: 0, y: 0};
simulation.push({type: "level", level: level, pos: position});
console.log("done!", window.sim);
}
}
var position = window.sim.position;
var levels = window.sim.levels;
var simulation = window.sim.simulation;
var level = window.sim.level;
console.log("simulation: ", simulation);
function color() {
with (window.sim) {
if (! levels[level].colors) { return false; }
var c = levels[level].colors.contains(position.x, position.y);
return c ? c.hue : false;
}
}
function level3() {
var holes = [5];
for (var i = 1; i <= 3; ++i) {
holes.push(holes[i-1]+(Math.random()<0.5 ? -1 : 1));
}
var start = 1;
var obstacles = new PositionSet([]);
var colors = new PositionSet([]);
for (var i = 0; i < holes.length; ++i) {
obstacles = obstacles
.concat(makeObstacles(start+i*2, 0, 1, holes[i]))
.concat(makeObstacles(start+i*2, holes[i]+1, 1, (9-holes[i])));
if (i > 0) {
colors.push({x: (start-1)+i*2, y: holes[i-1], hue: holes[i] < holes[i-1] ? "red" : "blue"});
}
}
var ret = {
start: { x: 0, y: 5 },
trash: new PositionSet([ { x:9, y: holes[holes.length-1] } ]),
obstacles: obstacles,
colors: colors
};
return ret;
}
function level4() {
var holes = [
Math.floor(Math.random()*5+5),
Math.floor(Math.random()*5),
Math.floor(Math.random()*5+5),
Math.floor(Math.random()*5)
];
var start = 1;
var obstacles = new PositionSet([]);
var colors = new PositionSet([{x:8, y:9, hue:"red"}]);
for (var i = 0; i < holes.length; ++i) {
obstacles = obstacles
.concat(makeObstacles(start+i*2, 0, 1, holes[i]))
.concat(makeObstacles(start+i*2, holes[i]+1, 1, (9-holes[i])));
colors.push({x: (start-1)+i*2, y: holes[i], hue: "red"});
}
var ret = {
start: { x: 0, y: 0 },
trash: new PositionSet([ { x:9, y: 9 } ]),
obstacles: obstacles,
colors: colors
};
return ret;
}
function addCommand(op) {
with (window.sim) {
var newPos = applyCommand(op);
if (newPos) {
position = newPos;
simulation.push({type: "move", pos: position});
var trash = levels[level].trash.contains(position.x, position.y);
if (trash) {
trash.found = true;
simulation.push({type: "found-trash", pos: position});
}
if (levels[level].trash.count("found", true) == levels[level].trash.list.length) {
// advance level
level++;
if (level < levels.length) {
position = levels[level].start || {x: 0, y: 0};
simulation.push({type: "level", level: level, pos: position});
}
}
} else {
simulation.push({type: "move", pos: position});
}
}
}
function left() {
addCommand('left');
}
function right() {
addCommand('right');
}
function up() {
addCommand('up');
}
function down() {
addCommand('down');
}
function applyCommand(command) {
with (window.sim) {
var np = null;
switch(command) {
case 'right':
np = {x: position.x+1, y: position.y};
break;
case 'left':
np = {x: position.x-1, y: position.y};
break;
case 'up':
np = {x: position.x, y: position.y-1};
break;
case 'down':
np = {x: position.x, y: position.y+1};
break;
default:
println("unknown command: "+command);
}
if (np && ! levels[level].obstacles.contains(np.x, np.y)) {
return np;
} else {
return false;
}
}
}
var GRIDWIDTH=30;
var MARGIN=20;
function makeObstacles(x, y, width, height) {
var out = [];
for (var i = 0; i < width; ++i) {
for (var j = 0; j < height; ++j) {
out.push({x: x+i, y: y+j});
}
}
return new PositionSet(out);
}
function ellipseAtLoc(loc) {
ellipse(MARGIN+(loc.x+0.5)*GRIDWIDTH, MARGIN+(loc.y+0.5)*GRIDWIDTH, GRIDWIDTH/2, GRIDWIDTH/2);
}
var obstacleGrid;
var nextPosition;
var programCounter = 0;
var moveStart = 0;
function drawCurrentPosition() {
var p = position;
var np = nextPosition;
fill(238, 0, 0); // red
ellipseAtLoc({
x: p.x+(np.x-p.x)*Math.min(MOVETIME, millis()-moveStart)/MOVETIME,
y: p.y+(np.y-p.y)*Math.min(MOVETIME, millis()-moveStart)/MOVETIME
});
}
function updatePosition() {
if (millis()-moveStart > MOVETIME) {
console.log("next!");
if (programCounter >= simulation.length) {
clearInterval(interval);
return;
}
position = nextPosition;
var resume = false;
while (! resume && programCounter < simulation.length) {
var cmd = simulation[programCounter++];
switch (cmd.type) {
case 'level':
nextPosition = position = cmd.pos;
level = cmd.level;
break;
case 'found-trash':
levels[level].trash.contains(cmd.pos.x, cmd.pos.y).hide = true;
break;
case 'move':
console.log("moving to", cmd.pos.x+","+cmd.pos.y);
nextPosition = cmd.pos;
resume = true;
break;
default:
break;
}
}
moveStart = millis();
}
}
function PositionSet(list, grid) {
var posRegex = new RegExp("(\\d+),(\\d)");
if (list && ! grid) {
grid = {};
list.forEach(function(pos) {
grid[pos.x+","+pos.y] = pos;
});
}
if (grid && ! list) {
list = [];
for (var k in grid) {
var obj = grid[k];
var parts = posRegex.exec(k);
if (parts) {
obj.x = parts[1];
obj.y = parts[2];
list.push(obj);
}
}
}
if (! grid || ! list) {
return null;
}
this.list = list;
this.grid = grid;
this.contains = function(x, y) {
return this.grid[x+","+y];
}
this.count = function(property, value) {
return this.list.filter(function(x) { return x[property] == value; }).length;
}
this.push = function(pos) {
this.list.push(pos);
this.grid[pos.x+","+pos.y] = pos;
}
this.concat = function(positionSet) {
return new PositionSet(this.list.concat(positionSet.list));
}
this.forEach = function(f) {
return this.list.forEach(f);
}
}
function setFill(hue) {
switch (hue) {
case "red":
fill(255, 220, 220);
break;
case "blue":
fill(200, 200, 255);
break;
case "green":
fill(200, 255, 200);
break;
default:
break;
}
}
function drawColors() {
if (levels[level].colors) {
levels[level].colors.forEach(function(c) {
setFill(c.hue);
rect(MARGIN+c.x*GRIDWIDTH+1,
MARGIN+c.y*GRIDWIDTH+1,
GRIDWIDTH-1, GRIDWIDTH-1);
});
}
}
function drawObstacles() {
fill(204);
levels[level].obstacles.forEach(function(o) {
rect(MARGIN+o.x*GRIDWIDTH,
MARGIN+o.y*GRIDWIDTH,
GRIDWIDTH, GRIDWIDTH);
});
}
function redraw() {
background(255);
PFont fontA = loadFont("Courier New");
textFont(fontA, 12);
textAlign(LEFT);
trashFound = levels[level].trash.list.length - levels[level].trash.count("hide", true);
text("Trash remaining: "+trashFound, 5, 15);
stroke(204);
for (var i = 0; i <= (width-MARGIN/2)/GRIDWIDTH; ++i) {
line(MARGIN+i*GRIDWIDTH, MARGIN, MARGIN+i*GRIDWIDTH, height-MARGIN);
}
for (var i = 0; i <= (height-MARGIN*2)/GRIDWIDTH; ++i) {
line(MARGIN, MARGIN+i*GRIDWIDTH, width-MARGIN, i*GRIDWIDTH+MARGIN);
}
noStroke();
drawColors();
drawObstacles();
fill(0, 238, 0); // green
levels[level].trash.list.filter(function(x) { return ! x.hide; }).forEach(ellipseAtLoc);
drawCurrentPosition();
}
function draw() {
updatePosition();
redraw();
}
var interval = setInterval(draw, 30);