xxxxxxxxxx
1167
let img;
let SHEET_PATH = 'assets/iceMazeTiles16.png'
let SWIDTH = 16;
let SHEIGHT = 16;
let ICE_IDX = 0;
let S_PER_ROW = 8;
let SHEET_W = S_PER_ROW * SWIDTH;
let DOOR_IDX = 9;
let ROCK_IDX = 20;
let SNOW_IDX = 6;
let HOLE_IDX = 2;
let START = 'S';
let MAZEEND = 'E';
let ICE = ' ';
let SAND = 'x';
let ROCK = '#';
let VISITED = -1;
let END = -2;
let CONTINUE = -3;
let SKIP = -4;
/*
let pattern = [
" x ",
" # ",
" E ",
" # ",
" # ",
"S #",
" x ",
" # ",
" E ",
" # ",
" # ",
"S #"];
*/
//A simple spiral
/*
let pattern = [
" x ",
" # ",
" E ",
" # ",
" # ",
"S #",
" x ",
" # ",
" E ",
" # ",
" # ",
"S #"];
*/
//Pokemon
/*
let pattern = [
"x x # ",
" # # ",
" ##x E ",
" # x ",
" # # ",
" # x x",
"x # ",
" # # ",
" #x x x",
" # x ",
" # # ",
" # x x # ",
" #x#xx#x# ",
" #x#xx### ",
"x xxxxxx x",
"# xxSxxx #",
"x x # ",
" # # ",
" ##x E ",
" # x ",
" # # ",
" # x x",
"x # ",
" # # ",
" #x x x",
" # x ",
" # # ",
" # x x # ",
" #x#xx#x# ",
" #x#xx### ",
"x xxxxxx x",
"# xxSxxx #"
]
*/
//Random
let pattern = [
" x # # # # x ",
" # ##x ",
" ## # # # # ",
" x # x# # ",
" # # # # # # ",
" ### # S # # ",
" # # # # # ",
"x # # ",
" x# ## # E ",
"# # ## # # #",
" x # # # # x ",
" # ##x ",
" ## # # # # ",
" x # x# # ",
" # # # # # # ",
" ### # S # # ",
" # # # # # ",
"x # # ",
" x# ## # E ",
"# # ## # # #"];
/*
struct History {
int index;
bool left;
bool right;
bool up;
bool down;
History() {
left = false;
right = false;
up = false;
down = false;
}
};
*/
// Field and functions used for the animation
let animatedFrames = [];
let animatedFrameIdx = 1;
let animatedPathIdx = 0;
let lastFrame = 0;
let manuallyStep = false;
let shadowWidth = 2;
let shadowOffset = 3;
let lineWidth = 3;
let fps = 60;
let start = true;
let record = false;
let endFrame = -1;
var capturer = new CCapture({
format: 'png',
framerate: fps
});
function indexesFromPath(start, wh, map, path) {
let result = [];
result.push(new V2(start.x, start.y));
let pos = new V2(start.x, start.y);
let idx = 0;
for (let i = 0; i < path.length; i++) {
switch (path[i]) {
case 'u':
pos.y--;
result.push(new V2(pos.x, pos.y));
while (0 <= pos.y && map[pos.y][pos.x] == ICE) {
pos.y--;
result.push(new V2(pos.x, pos.y));
}
if (0 <= pos.y && map[pos.y][pos.x] == ROCK || pos.y < 0) {
result.pop();
pos.y++;
}
break;
case 'd':
pos.y++;
result.push(new V2(pos.x, pos.y));
while (pos.y < wh.y && map[pos.y][pos.x] == ICE) {
pos.y++;
result.push(new V2(pos.x, pos.y));
}
if (pos.y < wh.y && map[pos.y][pos.x] == ROCK || pos.y >= wh.y) {
result.pop();
pos.y--;
}
break;
case 'r':
pos.x++;
result.push(new V2(pos.x, pos.y));
while (pos.x < wh.x && map[pos.y][pos.x] == ICE) {
pos.x++;
result.push(new V2(pos.x, pos.y));
}
if (pos.x < wh.x && map[pos.y][pos.x] == ROCK || pos.x >= wh.x) {
result.pop();
pos.x--;
}
break;
case 'l':
pos.x--;
result.push(new V2(pos.x, pos.y));
while (0 <= pos.x && map[pos.y][pos.x] == ICE) {
pos.x--;
result.push(new V2(pos.x, pos.y));
}
if (0 <= pos.x && map[pos.y][pos.x] == ROCK || pos.x < 0) {
result.pop();
pos.x++;
}
break;
}
}
return result;
}
function drawPattern() {
let row = 0;
for (let y = 0; y < height; y += SHEIGHT) {
let column = 0;
for (let x = 0; x < width; x += SWIDTH) {
if (pattern[row][column] == ' ')
drawSprite(ICE_IDX, x, y);
else if (pattern[row][column] == ROCK)
drawSprite(ROCK_IDX, x, y);
else if (pattern[row][column] == SAND)
drawSprite(SNOW_IDX, x, y);
else if (pattern[row][column] == MAZEEND)
drawSprite(DOOR_IDX, x, y);
else if (pattern[row][column] == START)
drawSprite(HOLE_IDX, x, y);
else
console.log("I don't know");
column++;
}
row++;
}
}
function drawSprite(index, x, y) {
let sx = (index % S_PER_ROW) * SWIDTH;
let sy = floor(index / S_PER_ROW) * SHEIGHT;
image(img, x, y, SWIDTH, SHEIGHT,
sx, sy, SWIDTH, SHEIGHT);
}
function myline(x1, y1, x2, y2) {
strokeWeight(shadowWidth);
stroke(0, 0, 0, 100);
line(
x1 - shadowOffset,
y1 - shadowOffset,
x2 - shadowOffset,
y2 - shadowOffset);
strokeWeight(lineWidth);
stroke(255, 200, 0);
line(
x1,
y1,
x2,
y2);
}
function myArc(x, y, w, h, start, stop) {
strokeWeight(shadowWidth);
stroke(0, 0, 0, 100);
arc(
x - shadowOffset,
y - shadowOffset,
w,
h,
start,
stop);
strokeWeight(lineWidth);
stroke(255, 200, 0);
arc(
x,
y,
w,
h,
start,
stop);
}
function myCircle(x, y, diameter) {
//strokeWeight(shadowWidth);
stroke(0, 0, 0, 100);
fill(0, 0, 0, 100);
circle(x - shadowOffset,
y - shadowOffset,
diameter);
//strokeWeight(lineWidth);
stroke(255, 200, 0);
fill(255, 255, 255);
circle(x,
y,
diameter);
}
// Solver ported from my C++ version
class History {
constructor() {
this.left = false;
this.right = false;
this.up = false;
this.down = false;
}
}
/*
struct Trip {
int x;
int y;
std::string path;
int distance;
std::map<int, History> history;
Trip() {
x = SKIP;
y = SKIP;
path = "";
distance = 0;
}
Trip(int x, int y, std::string path, int distance) {
this->x = x;
this->y = y;
this->path = path;
this->distance = distance;
}
};
*/
class Trip {
constructor(x, y, path, distance) {
if (x == undefined)
this.x = SKIP;
else
this.x = x;
if (y == undefined)
this.y = SKIP;
else
this.y = y;
if (path == undefined)
this.path = "";
else
this.path = path;
if (distance == undefined)
this.distance = 0;
else
this.distance = distance;
this.history = {};
}
}
/*
struct TripKeyCompare {
bool operator()(const Trip &a, const Trip &b) {
if (a.path.size() < b.path.size()) {
return true;
}
else if (a.path.size() == b.path.size() && a.distance == b.distance) {
return (a.path < b.path); //We want to keep unique paths
}
else if (a.path.size() == b.path.size()) {
return (a.distance < b.distance);
}
else {
return false;
}
}
};
*/
function pathSort(a, b) {
//A doesn't have as many steps. It goes first.
if (a.path.length < b.path.length) {
return -1;
}
//The path string has the same number of steps but not necessarily
//the same values. We've also travelled the same distance
else if (a.path.length == b.path.length && a.distance == b.distance) {
//We want to keep unique paths
if (a.path < b.path)
return -1;
else
return 1;
}
//We've taken the same number of steps but the distance travelled is different
else if (a.path.length == b.path.length) {
if (a.distance < b.distance)
return -1;
else
return 1;
} else {
return 1;
}
}
//C++ gobbledygook: Two keys are considered equivalent if key_comp returns false reflexively (i.e., no matter the order in which the keys are passed as arguments).
//
//Kludge because javascript doesn't have a nice standard set library.
//We should be able to pass in a lambda like we do for sort.
//No nice things! God only knows when lisp introduced (set-difference lst1 lst2 :test 'equal)
function mySetInsert(myset, elem) {
//Yuck, again
let insert = true;
for (let i = 0; i < myset.length; i++) {
if (myset[i].path.length == elem.length && myset[i].distance == elem.distance &&
myset[i].path == elem.path) {
insert = false;
}
}
if (insert) {
myset.push(elem);
}
let result = myset.sort(pathSort);
return result;
}
// I'll need to do some of my own sorting here
/*
struct V2 {
int x;
int y;
};
*/
class V2 {
constructor(x, y, path, distance) {
if (x == undefined)
this.x = 0;
else
this.x = x;
if (y == undefined)
this.y = 0;
else
this.y = y;
}
}
/*
void setHistory(int index, char direction, std::map<int, History> &history) {
switch (direction) {
case 'u': history[index].up = true; break;
case 'd': history[index].down = true; break;
case 'l': history[index].left = true; break;
case 'r': history[index].right = true; break;
}
}
*/
//int index, char direction, std::map<int, History> &history
function setHistory(index, direction, history) {
if (!history.hasOwnProperty(index)) {
history[index] = new History();
}
switch (direction) {
case 'u':
history[index].up = true;
break;
case 'd':
history[index].down = true;
break;
case 'l':
history[index].left = true;
break;
case 'r':
history[index].right = true;
break;
}
return history;
}
/*
Trip performWalk(std::string &map, int x, int y, char direction, int &distance, Trip &pos, V2 wh) {
int idx = getIndex({ x, y }, wh);
if (pos.history.count(idx) > 0) {
if (direction == 'u' && pos.history[idx].up)
return { VISITED, VISITED, pos.path + direction, distance };
else if (direction == 'd' && pos.history[idx].down)
return { VISITED, VISITED, pos.path + direction, distance };
else if (direction == 'l' && pos.history[idx].left)
return { VISITED, VISITED, pos.path + direction, distance };
else if (direction == 'r' && pos.history[idx].right)
return { VISITED, VISITED, pos.path + direction, distance };
}
switch (map[idx]) {
case ICE:
setHistory(idx, direction, pos.history);
return { CONTINUE, CONTINUE, pos.path, ++distance };
case ROCK:
if (direction == 'l')
return { x + 1, y, pos.path + direction, distance };
else if (direction == 'r')
return { x - 1, y, pos.path + direction, distance };
else if (direction == 'u')
return { x, y + 1, pos.path + direction, distance };
else if (direction == 'd')
return { x, y - 1, pos.path + direction, distance };
break;
case SAND:
setHistory(idx, direction, pos.history);
return { x, y, pos.path + direction, ++distance };
case MAZEEND:
return { END, END, pos.path + direction, distance };
case START:
return { VISITED, VISITED, pos.path + direction, distance };
}
}
*/
/*
int getIndex(V2 pos, V2 wh) {
return pos.y * wh.x + pos.x;
}
*/
function getIndex(xy, wh) {
return xy.y * wh.x + xy.x;
}
/*
V2 getStart(std::string map, V2 wh) {
for (int y = 0; y < wh.y; y++) {
for (int x = 0; x < wh.x - 1; x++) {
if (map[getIndex({ x,y }, wh)] == START)
return { x, y };
}
}
return { -1, -1 };
}
*/
function getLocation(map, wh, location) {
for (let y = 0; y < wh.y; y++) {
for (let x = 0; x < wh.x - 1; x++) {
if (map[y][x] == location) {
return new V2(x, y);
}
}
}
return new V2(-1, -1);
}
function getStart(map, wh) {
return getLocation(map, wh, START);
}
function getEnd(map) {
return getLocation(map, wh, END);
}
//Trip performWalk(std::string &map, int x, int y, char direction, int &distance, Trip &pos, V2 wh)
//need to figure out how we're going to update the distance and pos
function performWalk(map, x, y, direction, distance, pos, wh) {
//Get the index for the current position. Why do we need wh here?
//Oh that is that the widht and height
let idx = getIndex(new V2(x, y), wh);
//Have we already visited this index going the same direction?
//If return a trip saying that we've already visited
if (pos.history.hasOwnProperty(idx)) {
if (direction == 'u' && pos.history[idx].up)
return new Trip(VISITED, VISITED, pos.path + direction, distance);
else if (direction == 'd' && pos.history[idx].down)
return new Trip(VISITED, VISITED, pos.path + direction, distance);
else if (direction == 'l' && pos.history[idx].left)
return new Trip(VISITED, VISITED, pos.path + direction, distance);
else if (direction == 'r' && pos.history[idx].right)
return new Trip(VISITED, VISITED, pos.path + direction, distance);
}
//What type of tile are we on?
switch (map[y][x]) {
case ICE:
//Ok, we are going to continue to slide.
setHistory(idx, direction, pos.history);
return new Trip(CONTINUE, CONTINUE, pos.path, ++distance);
case ROCK:
//we're on a rock but we can't be. Move back to the tile before it
if (direction == 'l')
return new Trip(x + 1, y, pos.path + direction, distance);
else if (direction == 'r')
return new Trip(x - 1, y, pos.path + direction, distance);
else if (direction == 'u')
return new Trip(x, y + 1, pos.path + direction, distance);
else if (direction == 'd')
return new Trip(x, y - 1, pos.path + direction, distance);
break;
case SAND:
//We can stand here but we don't keep sliding
setHistory(idx, direction, pos.history);
return new Trip(x, y, pos.path + direction, ++distance);
case MAZEEND:
//Nice, we found the end.
return new Trip(END, END, pos.path + direction, distance);
case START:
//Hey, how did we get back to the start?
return new Trip(VISITED, VISITED, pos.path + direction, distance);
}
}
/*
Trip walkRight(std::string &map, Trip &pos, V2 wh) {
int d = pos.distance;
for (int x = pos.x + 1; x < wh.x - 1; x++) {
Trip trip = performWalk(map, x, pos.y, 'r', d, pos, wh);
if (trip.x != CONTINUE)
return trip;
}
return { wh.x - 2, pos.y, pos.path + 'r', d };//We hit the wall;
}
*/
function walkRight(map, pos, wh) {
let d = pos.distance;
for (let x = pos.x + 1; x < wh.x - 1; x++) {
let trip = performWalk(map, x, pos.y, 'r', d, pos, wh);
d = trip.distance;
if (trip.x != CONTINUE)
return trip;
}
return new Trip(wh.x - 2, pos.y, pos.path + 'r', d); //We hit the wall;
}
/*
Trip walkLeft(std::string &map, Trip pos, V2 wh) {
int d = pos.distance;
for (int x = pos.x - 1; x > -1; x--) {
Trip trip = performWalk(map, x, pos.y, 'l', d, pos, wh);
if (trip.x != CONTINUE)
return trip;
}
return { 0, pos.y, pos.path + 'l', d };//We hit the wall;
}
*/
function walkLeft(map, pos, wh) {
let d = pos.distance;
for (let x = pos.x - 1; x > -1; x--) {
let trip = performWalk(map, x, pos.y, 'l', d, pos, wh);
d = trip.distance;
if (trip.x != CONTINUE)
return trip;
}
return new Trip(0, pos.y, pos.path + 'l', d); //We hit the wall;
}
/*
Trip walkUp(std::string &map, Trip pos, V2 wh) {
int d = pos.distance;
for (int y = pos.y - 1; y > -1; y--) {
Trip trip = performWalk(map, pos.x, y, 'u', d, pos, wh);
if (trip.x != CONTINUE)
return trip;
}
return { pos.x, 0, pos.path + 'u', d };//We hit the wall;
}
*/
function walkUp(map, pos, wh) {
let d = pos.distance;
for (let y = pos.y - 1; y > -1; y--) {
let trip = performWalk(map, pos.x, y, 'u', d, pos, wh);
d = trip.distance;
if (trip.x != CONTINUE)
return trip;
}
return new Trip(pos.x, 0, pos.path + 'u', d); //We hit the wall;
}
/*
Trip walkDown(std::string &map, Trip pos, V2 wh) {
int d = pos.distance;
for (int y = pos.y + 1; y < wh.y; y++) {
Trip trip = performWalk(map, pos.x, y, 'd', d, pos, wh);
if (trip.x != CONTINUE)
return trip;
}
return { pos.x, wh.y - 1, pos.path + 'd', d };//We hit the wall;
}
*/
function walkDown(map, pos, wh) {
let d = pos.distance;
for (let y = pos.y + 1; y < wh.y; y++) {
let trip = performWalk(map, pos.x, y, 'd', d, pos, wh);
d = trip.distance;
if (trip.x != CONTINUE)
return trip;
}
return new Trip(pos.x, wh.y - 1, pos.path + 'd', d); //We hit the wall;
}
/*
std::vector<char> walkMap(std::string map) {
V2 wh = { width(map), height(map) };
std::set<Trip, TripKeyCompare> queue;
std::set<Trip, TripKeyCompare> endings;
std::set<unsigned long long> queueHistory;
V2 start = getStart(map, wh);
queue.insert({ start.x, start.y, "", 0 });
std::vector<char> result;
while (queue.size() > 0) {
Trip p = *queue.begin();
queue.erase(queue.begin());
unsigned long long posKey = p.x;
posKey <<= 32;
posKey |= p.y;
if (queueHistory.count(posKey) > 0)
continue;
queueHistory.insert(posKey);
char lastDir = ' ';
if (p.path.size() > 0) {
lastDir = p.path[p.path.size() - 1];
}
Trip trips[4];
if (lastDir != 'r')
trips[0] = walkLeft(map, p, wh);
if (lastDir != 'l')
trips[1] = walkRight(map, p, wh);
if (lastDir != 'd')
trips[2] = walkUp(map, p, wh);
if (lastDir != 'u')
trips[3] = walkDown(map, p, wh);
for (int i = 0; i < 4; i++) {
if (trips[i].x == SKIP) continue;
if (trips[i].x == END) {
endings.insert(trips[i]);
}
if (!(trips[i].x == p.x && trips[i].y == p.y) && trips[i].x != VISITED && trips[i].x != END) {
queue.insert(trips[i]);
}
}
}
if (endings.size() > 0) {
Trip end = *endings.begin();
for (int j = 0; j < end.path.size(); j++) {
result.push_back(end.path[j]);
}
}
return result;
}
*/
/*std::vector<char> walkMap(std::string map) {*/
function walkMap(map) {
let wh = new V2(patternWidth(map), patternHeight(map));
//Yuck, javascript isn't going to give me away to provide a
//custom comparator for standard sets.
//
// 1) I can create a balanced tree and check for dups in log(n)
// 2) I can just do a brute force lookup
//std::set<Trip, TripKeyCompare> queue;
//std::set<Trip, TripKeyCompare> endings;
//std::set<unsigned long long> queueHistory;
let queue = [];
let endings = [];
let queueHistory = new Set(); //I can use a set here since I'm storing native ints
let start = getStart(map, wh);
//queue.insert({ start.x, start.y, "", 0 });
mySetInsert(queue, new Trip(start.x, start.y, "", 0));
//std::vector<char> result;
result = [];
while (queue.length > 0) {
//I can do something similar to A* here
//and sort the queue by the sortest euclidean
//distance to the goal
//sortByEuclidean(queue, goal);
let p = queue.shift(); // p is a Trip, why did I name it that?
animatedFrames.push(p.path);
//I really should not have done it this way in C++. I could have
//just used the index function that was created. Then I would not
//need a 64 bit int
// let posKey = p.x;
// posKey <<= 32;
// posKey |= p.y;
let posKey = getIndex(new V2(p.x, p.y), wh);
if (queueHistory.has(posKey))
continue;
queueHistory.add(posKey);
let lastDir = ' ';
if (p.path.length > 0) {
lastDir = p.path[p.path.length - 1];
}
let trips = [];
for (let i = 0; i < 4; i++) {
trips.push(new Trip());
}
if (lastDir != 'r')
trips[0] = walkLeft(map, p, wh);
if (lastDir != 'l')
trips[1] = walkRight(map, p, wh);
if (lastDir != 'd')
trips[2] = walkUp(map, p, wh);
if (lastDir != 'u')
trips[3] = walkDown(map, p, wh);
for (let i = 0; i < 4; i++) {
if (trips[i].x == SKIP) continue;
if (trips[i].x == END) {
mySetInsert(endings, trips[i]);
//endings.add(trips[i]);
}
if (!(trips[i].x == p.x && trips[i].y == p.y) && trips[i].x != VISITED && trips[i].x != END) {
mySetInsert(queue, trips[i]);
//queue.insert(trips[i]);
}
}
}
if (endings.length > 0) {
let end = endings[0];
for (let j = 0; j < end.path.length; j++) {
result.push(end.path[j]);
}
}
return result;
}
function drawDirection(dir) {}
function patternWidth(map) {
return map[0].length;
}
function patternHeight(map) {
return map.length;
}
//Processing core functions
function preload() {
img = loadImage(SHEET_PATH);
}
function setup() {
createCanvas(SWIDTH * patternWidth(pattern), SHEIGHT * patternHeight(pattern));
strokeWeight(3);
let shortest = walkMap(pattern);
let finalPath = "";
//String join
for (let i = 0; i < shortest.length; i++) {
finalPath += shortest[i];
}
animatedFrames.push(finalPath);
}
function draw() {
if (start && record){
capturer.start();
start = false;
}
// stroke(255, 200, 0);
if (manuallyStep) {
noLoop();
//animatedFrameIdx = 125;//155, 121
animatedPathIdx = animatedFrames[animatedFrameIdx].length - 1;
}
if (0 > animatedFrameIdx || animatedFrameIdx >= animatedFrames.length){
if (record){
if (endFrame == -1){
endFrame = 60;
}
else if (endFrame > 0){
endFrame--;
}
else {
capturer.stop();
capturer.save();
record = false;
return 0;
}
capturer.capture(document.getElementById('defaultCanvas0'));
}
return; //done
}
if (animatedPathIdx >= animatedFrames[animatedFrameIdx].length) {
//move to the next path and reset to the start
animatedFrameIdx++;
animatedPathIdx = 0;
}
if (animatedFrameIdx >= animatedFrames.length){
if (record){
capturer.stop();
capturer.save();
record = false;
}
return; //done
}
let pathSubString = "";
for (let i = 0; i <= animatedPathIdx; i++) {
pathSubString += animatedFrames[animatedFrameIdx][i];
}
let wh = new V2(patternWidth(pattern), patternHeight(pattern));
let pathIndexes = indexesFromPath(
getStart(pattern, wh),
wh,
pattern,
pathSubString);
//Clear the background
drawPattern();
let diameter = SWIDTH / 2;
//Draw the path we have so far
for (let i = 0; i < pathIndexes.length; i++) {
noFill();
let next = undefined;
let prev = undefined;
let current = pathIndexes[i];
if (i < pathIndexes.length - 1) {
next = pathIndexes[i + 1];
}
if (i > 0) {
prev = pathIndexes[i - 1];
}
if (prev == undefined) {
//Just for now
myCircle(current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT + (SHEIGHT / 2),
diameter);
fill(255, 255, 255);
if (next != undefined) {
if (next.x < current.x) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x - (SWIDTH / 2), y);
} else if (next.x > current.x) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x + (SWIDTH / 2), y);
} else if (next.y > current.y) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x, y + (SHEIGHT / 2));
} else if (next.y < current.y) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x, y - (SHEIGHT / 2));
}
}
circle(current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT + (SHEIGHT / 2),
diameter);
} else if (next == undefined) {
//Just for now
myCircle(current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT + (SHEIGHT / 2),
diameter);
fill(255, 255, 255);
if (prev != undefined) {
if (prev.x < current.x) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x - (SWIDTH / 2), y);
} else if (prev.x > current.x) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x + (SWIDTH / 2), y);
} else if (prev.y > current.y) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x, y + (SHEIGHT / 2));
} else if (prev.y < current.y) {
let y = current.y * SHEIGHT + (SHEIGHT / 2);
let x = current.x * SWIDTH + (SWIDTH / 2);
myline(x, y, x, y - (SHEIGHT / 2));
}
}
circle(current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT + (SHEIGHT / 2),
diameter);
} else {
if (next.y == prev.y) {
myline(
current.x * SWIDTH,
current.y * SHEIGHT + (SHEIGHT / 2),
current.x * SWIDTH + SWIDTH,
current.y * SHEIGHT + (SHEIGHT / 2));
} else if (next.x == prev.x) {
myline(
current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT,
current.x * SWIDTH + (SWIDTH / 2),
current.y * SHEIGHT + SHEIGHT);
} else if (current.x == prev.x && next.x < current.x && prev.y < current.y) {
myArc(
(current.x * SWIDTH),
current.y * SHEIGHT,
SWIDTH,
SWIDTH,
0,
HALF_PI);
} else if (current.x < prev.x && next.x == current.x && next.y > current.y) {
myArc(
(current.x * SWIDTH) + SWIDTH,
current.y * SHEIGHT + SHEIGHT,
SWIDTH,
SWIDTH,
PI,
PI + HALF_PI);
} else if (current.x < prev.x && next.y < current.y && current.y == prev.y) {
myArc(
(current.x * SWIDTH) + SWIDTH,
current.y * SHEIGHT,
SWIDTH,
SWIDTH,
HALF_PI,
PI);
} else if (current.y < prev.y && next.y == current.y && next.x < current.x) {
myArc(
(current.x * SWIDTH),
(current.y * SHEIGHT) + SHEIGHT,
SWIDTH,
SWIDTH,
PI + HALF_PI,
TWO_PI);
} else if (current.x == prev.x && next.x > current.x && current.y < prev.y) {
myArc(
(current.x * SWIDTH) + SWIDTH,
(current.y * SHEIGHT) + SHEIGHT,
SWIDTH,
SWIDTH,
PI,
PI + HALF_PI);
} else if (current.x > prev.x && next.x == current.x && next.y < current.y) {
myArc(
(current.x * SWIDTH),
(current.y * SHEIGHT),
SWIDTH,
SWIDTH,
0,
HALF_PI);
} else if (current.x > prev.x && next.x == current.x && next.y > current.y) {
myArc(
(current.x * SWIDTH),
(current.y * SHEIGHT) + SHEIGHT,
SWIDTH,
SWIDTH,
PI + HALF_PI,
TWO_PI);
} else if (current.x == prev.x && next.x > current.x && current.y > prev.y) {
myArc(
(current.x * SWIDTH) + SWIDTH,
(current.y * SHEIGHT),
SWIDTH,
SWIDTH,
HALF_PI,
PI);
}
}
}
if (abs(frameCount - lastFrame) > 1) {
animatedPathIdx++;
lastFrame = frameCount;
}
if (record){
capturer.capture(document.getElementById('defaultCanvas0'));
}
else {
//console.log("Not capture");
}
}
//Manually walk through the solutions
function keyPressed() {
if (manuallyStep) {
if (keyCode === UP_ARROW) {
animatedFrameIdx++;
} else if (keyCode === DOWN_ARROW) {
animatedFrameIdx--;
}
loop();
}
}
//My Original C++ Solver
/*
//Breadth first search with history kludge
#include <set>
#include <map>
std::vector<char> ice_maze_solver(const std::string &map)
{
return walkMap(map);
}
*/