initial commit

This commit is contained in:
Baipyrus 2022-05-15 16:36:38 +02:00
commit 43c1a9aa73
13 changed files with 1056 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
Export-IncludesJava/*

Binary file not shown.

Binary file not shown.

BIN
Export-NoJava/lib/core.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,369 @@
import processing.core.*;
import processing.data.*;
import processing.event.*;
import processing.opengl.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
public class breadthFirstSearch extends PApplet {
// Note #1: This version works using 'intersecting Lines' as a detection for Walls.
// Note #2: The ratio of constants 'cellsInWidth' and 'cellsInHeight' must remain the same as that of your screen.
// final int cells = 60;
final int cellsInWidth = 16;
final int cellsInHeight = 9;
final float verticalWall = .5f;
final float horizontalWall = .5f;
final int frameRate = 30; // Can't go above 60 or below 0 FPS!
final float timeout = 5;
int cIW = cellsInWidth, cIH = cellsInHeight;
float scl = 0, diameter = 0;
boolean solvedMaze = false, reachedOrigin = false;
ArrayList<Wall> walls = new ArrayList<Wall>();
ArrayList<Mover> movers = new ArrayList<Mover>();
ArrayList<Mover> visited = new ArrayList<Mover>();
ArrayList<Mover> finalPath = new ArrayList<Mover>();
Mover origin, pathFinder;
boolean outputToggle = false;
int previousUnsolvableMazes = 0;
int solvedFrameCountCapture = -1;
public void setup() {
generateMaze();
frameRate(frameRate);
}
public void draw() {
background(0);
/*
translate(width / 2 - height / 2, 0);
fill(0);
stroke(0);
rect(0, 0, height, height);
*/
// Display Walls
noFill();
stroke(255);
for (Wall w : walls) {
w.show();
}
// Display spots that are to be moved to
fill(0,255,0);
stroke(0,255,0);
for (Mover m : movers) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
// Display origin spot
fill(255,0,0);
stroke(255,0,0);
ellipse(origin.position.x, origin.position.y, diameter, diameter);
if (!solvedMaze) {
/*
// Display previously visited spots
fill(255,255,0);
stroke(255,255,0);
for (Mover m : visited) {
if (!m.equals(origin)) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
}
*/
// As long as the maze isn't solved, keep stepping the algorithm
breadthFirstSearchStep();
} else {
// When the maze is solved, display the last position and the path to get from the origin to there.
fill(0,0,255);
stroke(0,0,255);
final Mover last = visited.get(visited.size()-1);
ellipse(last.position.x, last.position.y, diameter, diameter);
// Display path from origin to last visited.
fill(255,255,0);
stroke(255,255,0);
for (Mover m : finalPath) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
if (!outputToggle) {
println("Previously genereted '" + previousUnsolvableMazes + "' mazes which were unsolvable.");
outputToggle = true;
}
// Trace back the path from last visited to origin.
if (!reachedOrigin) {
for (Mover v : visited) {
if (pathFinder.isNextOf(v)) {
if (v.steps == 0) {
reachedOrigin = true;
break;
}
finalPath.add(v.copy());
pathFinder = v.copy();
break;
}
}
} else {
if (solvedFrameCountCapture == -1) {
solvedFrameCountCapture = frameCount;
} else if (frameCount-solvedFrameCountCapture == frameRate*timeout) {
// Possible Error: 'frameCount-solvedFrameCountCapture' could be a negative number or similar.
// Note: frameCount, as the name implies, counts how many frames has passed. At one point, it has to reset to 0 (?).
// -> when resetting, no matter the result, the difference will never equal the wanted window or take too long to get there.
outputToggle = false;
solvedFrameCountCapture = -1;
resetMaze(false);
previousUnsolvableMazes = 0;
generateMaze();
}
}
}
}
public void breadthFirstSearchStep() {
// Idea: Move to every accessable (no walls inbetween the two) neighbor, when reaching the bottom, you have a path.
// Note: I don't actually know if this is the same working principle as Breadth-First Search.
ArrayList<Mover> nextGen = new ArrayList<Mover>();
for (Mover m : movers) {
visited.add(m.copy());
if (m.position.y == height-scl/2) {
solvedMaze = true;
nextGen = new ArrayList<Mover>();
pathFinder = m.copy();
break;
}
final ArrayList<Mover> neighbors = m.getNeighbors();
for (Mover n : neighbors) {
boolean alreadyVisited = false;
for (Mover v : visited) {
if (n.equals(v)) {
alreadyVisited = true;
break;
}
}
for (Mover s : nextGen) {
if (n.equals(s)) {
alreadyVisited = true;
break;
}
}
if (!alreadyVisited) {
nextGen.add(n);
}
}
}
movers = new ArrayList<Mover>(nextGen);
}
public void generateMaze() {
while (true) {
// While loop to reset when previous maze is unsolvable (from origin position).
int randomScalor = floor(random(3,8));
cIW *= randomScalor;
cIH *= randomScalor;
scl = (float) height / cIH;
diameter = scl / 2;
for (float i = 0; i < /*height*/width; i += scl) {
for (float j = 0; j < height; j += scl) {
if (random(1) <= verticalWall && i != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i, j+scl)
));
}
if (random(1) <= horizontalWall && j != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i+scl, j)
));
}
}
}
origin = new Mover((floor(random(/*cells*/cellsInWidth))+.5f) * scl, scl/2, 0);
movers.add(origin);
// Check if maze is solvable by stepping through until solved.
// Note: If there are no movers while the maze is unsolved, it means there are no spots to be visited and it's unsolvable.
boolean isSolvable = false;
while (!solvedMaze) {
breadthFirstSearchStep();
if (solvedMaze) {
isSolvable = true;
break;
} else if (movers.size() == 0) {
break;
}
}
resetMaze(isSolvable);
if (isSolvable) {
break;
}
}
}
public void resetMaze(boolean iS) {
// Resetting variables depending on solvability of the maze.
cIW = cellsInWidth;
cIH = cellsInHeight;
solvedMaze = false;
reachedOrigin = false;
movers = new ArrayList<Mover>();
visited = new ArrayList<Mover>();
finalPath = new ArrayList<Mover>();
if (iS) {
movers.add(origin);
} else {
previousUnsolvableMazes++;
walls = new ArrayList<Wall>();
}
}
class Mover {
PVector position;
int steps;
Mover(float x, float y, int s) {
position = new PVector(x, y);
steps = s;
}
public boolean isNextOf(Mover other) {
return ((other.steps == steps-1) && maxDistFrom(other, scl) && other.canMoveTo(position));
}
public boolean maxDistFrom(Mover other, float maxDist) {
return (PVector.dist(position, other.position) <= maxDist);
}
public Mover copy() {
return new Mover(position.x, position.y, steps);
}
public boolean equals(Mover other) {
return pointEquals(position, other.position);
}
public boolean canMoveTo(PVector newPos) {
if ((newPos.x < 0 || newPos.x > /*height*/width) || (newPos.y < 0 || newPos.y > height)) { return false; }
final Wall path = new Wall(position, newPos);
boolean noIntersects = true;
for (Wall w : walls) {
if (w.intersect(path)) {
noIntersects = false;
break;
}
}
return noIntersects;
}
public ArrayList<Mover> getNeighbors() {
ArrayList<Mover> neighbors = new ArrayList<Mover>();
for (int i = 0; i < 4; i++) {
final PVector converted = convertDirection(i);
if (converted == null) { continue; }
final PVector newPosition = PVector.add(position, converted);
if (canMoveTo(newPosition)) {
neighbors.add(new Mover(newPosition.x, newPosition.y, steps+1));
}
}
return neighbors;
}
}
public PVector convertDirection(int direction) {
if (direction < 0 || direction > 3) { return null; }
switch (direction) {
case 0:
return new PVector(-scl, 0);
case 1:
return new PVector(scl, 0);
case 2:
return new PVector(0, -scl);
case 3:
return new PVector(0, scl);
}
return null;
}
class Wall {
PVector start, end;
Wall(PVector a, PVector b) {
start = new PVector(a.x, a.y);
end = new PVector(b.x, b.y);
}
public void show() {
line(start.x, start.y, end.x, end.y);
}
public boolean intersect(Wall other) {
final PVector a = start.copy();
final PVector b = end.copy();
final PVector c = other.start.copy();
final PVector d = other.end.copy();
if ((pointEquals(a,c) && pointEquals(b,d)) || (pointEquals(a,d) && pointEquals(b,c))) { return true; }
final float t = (a.x-c.x) * (c.y-d.y) - (a.y-c.y) * (c.x-d.x);
final float u = (b.x-a.x) * (a.y-c.y) - (b.y-a.y) * (a.x-c.x);
final float D = (a.x-b.x) * (c.y-d.y) - (a.y-b.y) * (c.x-d.x);
if (D == 0) { return false; }
final float td = t / D;
final float ud = u / D;
if (td >= 0 && td <= 1 && ud >= 0 && ud <= 1) { return true; }
return false;
}
}
public boolean pointEquals(PVector A, PVector B) {
return (A.x == B.x && A.y == B.y);
}
public void settings() { fullScreen(); }
static public void main(String[] passedArgs) {
String[] appletArgs = new String[] { "breadthFirstSearch" };
if (passedArgs != null) {
PApplet.main(concat(appletArgs, passedArgs));
} else {
PApplet.main(appletArgs);
}
}
}

View File

@ -0,0 +1,232 @@
// Note #1: This version works using 'intersecting Lines' as a detection for Walls.
// Note #2: The ratio of constants 'cellsInWidth' and 'cellsInHeight' must remain the same as that of your screen.
// final int cells = 60;
final int cellsInWidth = 16;
final int cellsInHeight = 9;
final float verticalWall = .5;
final float horizontalWall = .5;
final int frameRate = 30; // Can't go above 60 or below 0 FPS!
final float timeout = 5;
int cIW = cellsInWidth, cIH = cellsInHeight;
float scl = 0, diameter = 0;
boolean solvedMaze = false, reachedOrigin = false;
ArrayList<Wall> walls = new ArrayList<Wall>();
ArrayList<Mover> movers = new ArrayList<Mover>();
ArrayList<Mover> visited = new ArrayList<Mover>();
ArrayList<Mover> finalPath = new ArrayList<Mover>();
Mover origin, pathFinder;
boolean outputToggle = false;
int previousUnsolvableMazes = 0;
int solvedFrameCountCapture = -1;
void setup() {
fullScreen();
generateMaze();
frameRate(frameRate);
}
void draw() {
background(0);
/*
translate(width / 2 - height / 2, 0);
fill(0);
stroke(0);
rect(0, 0, height, height);
*/
// Display Walls
noFill();
stroke(255);
for (Wall w : walls) {
w.show();
}
// Display spots that are to be moved to
fill(0,255,0);
stroke(0,255,0);
for (Mover m : movers) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
// Display origin spot
fill(255,0,0);
stroke(255,0,0);
ellipse(origin.position.x, origin.position.y, diameter, diameter);
if (!solvedMaze) {
/*
// Display previously visited spots
fill(255,255,0);
stroke(255,255,0);
for (Mover m : visited) {
if (!m.equals(origin)) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
}
*/
// As long as the maze isn't solved, keep stepping the algorithm
breadthFirstSearchStep();
} else {
// When the maze is solved, display the last position and the path to get from the origin to there.
fill(0,0,255);
stroke(0,0,255);
final Mover last = visited.get(visited.size()-1);
ellipse(last.position.x, last.position.y, diameter, diameter);
// Display path from origin to last visited.
fill(255,255,0);
stroke(255,255,0);
for (Mover m : finalPath) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
if (!outputToggle) {
println("Previously genereted '" + previousUnsolvableMazes + "' mazes which were unsolvable.");
outputToggle = true;
}
// Trace back the path from last visited to origin.
if (!reachedOrigin) {
for (Mover v : visited) {
if (pathFinder.isNextOf(v)) {
if (v.steps == 0) {
reachedOrigin = true;
break;
}
finalPath.add(v.copy());
pathFinder = v.copy();
break;
}
}
} else {
if (solvedFrameCountCapture == -1) {
solvedFrameCountCapture = frameCount;
} else if (frameCount-solvedFrameCountCapture == frameRate*timeout) {
// Possible Error: 'frameCount-solvedFrameCountCapture' could be a negative number or similar.
// Note: frameCount, as the name implies, counts how many frames has passed. At one point, it has to reset to 0 (?).
// -> when resetting, no matter the result, the difference will never equal the wanted window or take too long to get there.
outputToggle = false;
solvedFrameCountCapture = -1;
resetMaze(false);
previousUnsolvableMazes = 0;
generateMaze();
}
}
}
}
void breadthFirstSearchStep() {
// Idea: Move to every accessable (no walls inbetween the two) neighbor, when reaching the bottom, you have a path.
// Note: I don't actually know if this is the same working principle as Breadth-First Search.
ArrayList<Mover> nextGen = new ArrayList<Mover>();
for (Mover m : movers) {
visited.add(m.copy());
if (m.position.y == height-scl/2) {
solvedMaze = true;
nextGen = new ArrayList<Mover>();
pathFinder = m.copy();
break;
}
final ArrayList<Mover> neighbors = m.getNeighbors();
for (Mover n : neighbors) {
boolean alreadyVisited = false;
for (Mover v : visited) {
if (n.equals(v)) {
alreadyVisited = true;
break;
}
}
for (Mover s : nextGen) {
if (n.equals(s)) {
alreadyVisited = true;
break;
}
}
if (!alreadyVisited) {
nextGen.add(n);
}
}
}
movers = new ArrayList<Mover>(nextGen);
}
void generateMaze() {
while (true) {
// While loop to reset when previous maze is unsolvable (from origin position).
int randomScalor = floor(random(3,8));
cIW *= randomScalor;
cIH *= randomScalor;
scl = (float) height / cIH;
diameter = scl / 2;
for (float i = 0; i < /*height*/width; i += scl) {
for (float j = 0; j < height; j += scl) {
if (random(1) <= verticalWall && i != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i, j+scl)
));
}
if (random(1) <= horizontalWall && j != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i+scl, j)
));
}
}
}
origin = new Mover((floor(random(/*cells*/cellsInWidth))+.5) * scl, scl/2, 0);
movers.add(origin);
// Check if maze is solvable by stepping through until solved.
// Note: If there are no movers while the maze is unsolved, it means there are no spots to be visited and it's unsolvable.
boolean isSolvable = false;
while (!solvedMaze) {
breadthFirstSearchStep();
if (solvedMaze) {
isSolvable = true;
break;
} else if (movers.size() == 0) {
break;
}
}
resetMaze(isSolvable);
if (isSolvable) {
break;
}
}
}
void resetMaze(boolean iS) {
// Resetting variables depending on solvability of the maze.
cIW = cellsInWidth;
cIH = cellsInHeight;
solvedMaze = false;
reachedOrigin = false;
movers = new ArrayList<Mover>();
visited = new ArrayList<Mover>();
finalPath = new ArrayList<Mover>();
if (iS) {
movers.add(origin);
} else {
previousUnsolvableMazes++;
walls = new ArrayList<Wall>();
}
}

View File

@ -0,0 +1,111 @@
class Mover {
PVector position;
int steps;
Mover(float x, float y, int s) {
position = new PVector(x, y);
steps = s;
}
boolean isNextOf(Mover other) {
return ((other.steps == steps-1) && maxDistFrom(other, scl) && other.canMoveTo(position));
}
boolean maxDistFrom(Mover other, float maxDist) {
return (PVector.dist(position, other.position) <= maxDist);
}
Mover copy() {
return new Mover(position.x, position.y, steps);
}
boolean equals(Mover other) {
return pointEquals(position, other.position);
}
boolean canMoveTo(PVector newPos) {
if ((newPos.x < 0 || newPos.x > /*height*/width) || (newPos.y < 0 || newPos.y > height)) { return false; }
final Wall path = new Wall(position, newPos);
boolean noIntersects = true;
for (Wall w : walls) {
if (w.intersect(path)) {
noIntersects = false;
break;
}
}
return noIntersects;
}
ArrayList<Mover> getNeighbors() {
ArrayList<Mover> neighbors = new ArrayList<Mover>();
for (int i = 0; i < 4; i++) {
final PVector converted = convertDirection(i);
if (converted == null) { continue; }
final PVector newPosition = PVector.add(position, converted);
if (canMoveTo(newPosition)) {
neighbors.add(new Mover(newPosition.x, newPosition.y, steps+1));
}
}
return neighbors;
}
}
PVector convertDirection(int direction) {
if (direction < 0 || direction > 3) { return null; }
switch (direction) {
case 0:
return new PVector(-scl, 0);
case 1:
return new PVector(scl, 0);
case 2:
return new PVector(0, -scl);
case 3:
return new PVector(0, scl);
}
return null;
}
class Wall {
PVector start, end;
Wall(PVector a, PVector b) {
start = new PVector(a.x, a.y);
end = new PVector(b.x, b.y);
}
void show() {
line(start.x, start.y, end.x, end.y);
}
boolean intersect(Wall other) {
final PVector a = start.copy();
final PVector b = end.copy();
final PVector c = other.start.copy();
final PVector d = other.end.copy();
if ((pointEquals(a,c) && pointEquals(b,d)) || (pointEquals(a,d) && pointEquals(b,c))) { return true; }
final float t = (a.x-c.x) * (c.y-d.y) - (a.y-c.y) * (c.x-d.x);
final float u = (b.x-a.x) * (a.y-c.y) - (b.y-a.y) * (a.x-c.x);
final float D = (a.x-b.x) * (c.y-d.y) - (a.y-b.y) * (c.x-d.x);
if (D == 0) { return false; }
final float td = t / D;
final float ud = u / D;
if (td >= 0 && td <= 1 && ud >= 0 && ud <= 1) { return true; }
return false;
}
}
boolean pointEquals(PVector A, PVector B) {
return (A.x == B.x && A.y == B.y);
}

232
breadthFirstSearch.pde Normal file
View File

@ -0,0 +1,232 @@
// Note #1: This version works using 'intersecting Lines' as a detection for Walls.
// Note #2: The ratio of constants 'cellsInWidth' and 'cellsInHeight' must remain the same as that of your screen.
// final int cells = 60;
final int cellsInWidth = 16;
final int cellsInHeight = 9;
final float verticalWall = .5;
final float horizontalWall = .5;
final int frameRate = 30; // Can't go above 60 or below 0 FPS!
final float timeout = 5;
int cIW = cellsInWidth, cIH = cellsInHeight;
float scl = 0, diameter = 0;
boolean solvedMaze = false, reachedOrigin = false;
ArrayList<Wall> walls = new ArrayList<Wall>();
ArrayList<Mover> movers = new ArrayList<Mover>();
ArrayList<Mover> visited = new ArrayList<Mover>();
ArrayList<Mover> finalPath = new ArrayList<Mover>();
Mover origin, pathFinder;
boolean outputToggle = false;
int previousUnsolvableMazes = 0;
int solvedFrameCountCapture = -1;
void setup() {
fullScreen();
generateMaze();
frameRate(frameRate);
}
void draw() {
background(0);
/*
translate(width / 2 - height / 2, 0);
fill(0);
stroke(0);
rect(0, 0, height, height);
*/
// Display Walls
noFill();
stroke(255);
for (Wall w : walls) {
w.show();
}
// Display spots that are to be moved to
fill(0,255,0);
stroke(0,255,0);
for (Mover m : movers) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
// Display origin spot
fill(255,0,0);
stroke(255,0,0);
ellipse(origin.position.x, origin.position.y, diameter, diameter);
if (!solvedMaze) {
/*
// Display previously visited spots
fill(255,255,0);
stroke(255,255,0);
for (Mover m : visited) {
if (!m.equals(origin)) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
}
*/
// As long as the maze isn't solved, keep stepping the algorithm
breadthFirstSearchStep();
} else {
// When the maze is solved, display the last position and the path to get from the origin to there.
fill(0,0,255);
stroke(0,0,255);
final Mover last = visited.get(visited.size()-1);
ellipse(last.position.x, last.position.y, diameter, diameter);
// Display path from origin to last visited.
fill(255,255,0);
stroke(255,255,0);
for (Mover m : finalPath) {
ellipse(m.position.x, m.position.y, diameter, diameter);
}
if (!outputToggle) {
println("Previously genereted '" + previousUnsolvableMazes + "' mazes which were unsolvable.");
outputToggle = true;
}
// Trace back the path from last visited to origin.
if (!reachedOrigin) {
for (Mover v : visited) {
if (pathFinder.isNextOf(v)) {
if (v.steps == 0) {
reachedOrigin = true;
break;
}
finalPath.add(v.copy());
pathFinder = v.copy();
break;
}
}
} else {
if (solvedFrameCountCapture == -1) {
solvedFrameCountCapture = frameCount;
} else if (frameCount-solvedFrameCountCapture == frameRate*timeout) {
// Possible Error: 'frameCount-solvedFrameCountCapture' could be a negative number or similar.
// Note: frameCount, as the name implies, counts how many frames has passed. At one point, it has to reset to 0 (?).
// -> when resetting, no matter the result, the difference will never equal the wanted window or take too long to get there.
outputToggle = false;
solvedFrameCountCapture = -1;
resetMaze(false);
previousUnsolvableMazes = 0;
generateMaze();
}
}
}
}
void breadthFirstSearchStep() {
// Idea: Move to every accessable (no walls inbetween the two) neighbor, when reaching the bottom, you have a path.
// Note: I don't actually know if this is the same working principle as Breadth-First Search.
ArrayList<Mover> nextGen = new ArrayList<Mover>();
for (Mover m : movers) {
visited.add(m.copy());
if (m.position.y == height-scl/2) {
solvedMaze = true;
nextGen = new ArrayList<Mover>();
pathFinder = m.copy();
break;
}
final ArrayList<Mover> neighbors = m.getNeighbors();
for (Mover n : neighbors) {
boolean alreadyVisited = false;
for (Mover v : visited) {
if (n.equals(v)) {
alreadyVisited = true;
break;
}
}
for (Mover s : nextGen) {
if (n.equals(s)) {
alreadyVisited = true;
break;
}
}
if (!alreadyVisited) {
nextGen.add(n);
}
}
}
movers = new ArrayList<Mover>(nextGen);
}
void generateMaze() {
while (true) {
// While loop to reset when previous maze is unsolvable (from origin position).
int randomScalor = floor(random(3,8));
cIW *= randomScalor;
cIH *= randomScalor;
scl = (float) height / cIH;
diameter = scl / 2;
for (float i = 0; i < /*height*/width; i += scl) {
for (float j = 0; j < height; j += scl) {
if (random(1) <= verticalWall && i != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i, j+scl)
));
}
if (random(1) <= horizontalWall && j != 0) {
walls.add(new Wall(
new PVector(i, j),
new PVector(i+scl, j)
));
}
}
}
origin = new Mover((floor(random(/*cells*/cellsInWidth))+.5) * scl, scl/2, 0);
movers.add(origin);
// Check if maze is solvable by stepping through until solved.
// Note: If there are no movers while the maze is unsolved, it means there are no spots to be visited and it's unsolvable.
boolean isSolvable = false;
while (!solvedMaze) {
breadthFirstSearchStep();
if (solvedMaze) {
isSolvable = true;
break;
} else if (movers.size() == 0) {
break;
}
}
resetMaze(isSolvable);
if (isSolvable) {
break;
}
}
}
void resetMaze(boolean iS) {
// Resetting variables depending on solvability of the maze.
cIW = cellsInWidth;
cIH = cellsInHeight;
solvedMaze = false;
reachedOrigin = false;
movers = new ArrayList<Mover>();
visited = new ArrayList<Mover>();
finalPath = new ArrayList<Mover>();
if (iS) {
movers.add(origin);
} else {
previousUnsolvableMazes++;
walls = new ArrayList<Wall>();
}
}

111
extra.pde Normal file
View File

@ -0,0 +1,111 @@
class Mover {
PVector position;
int steps;
Mover(float x, float y, int s) {
position = new PVector(x, y);
steps = s;
}
boolean isNextOf(Mover other) {
return ((other.steps == steps-1) && maxDistFrom(other, scl) && other.canMoveTo(position));
}
boolean maxDistFrom(Mover other, float maxDist) {
return (PVector.dist(position, other.position) <= maxDist);
}
Mover copy() {
return new Mover(position.x, position.y, steps);
}
boolean equals(Mover other) {
return pointEquals(position, other.position);
}
boolean canMoveTo(PVector newPos) {
if ((newPos.x < 0 || newPos.x > /*height*/width) || (newPos.y < 0 || newPos.y > height)) { return false; }
final Wall path = new Wall(position, newPos);
boolean noIntersects = true;
for (Wall w : walls) {
if (w.intersect(path)) {
noIntersects = false;
break;
}
}
return noIntersects;
}
ArrayList<Mover> getNeighbors() {
ArrayList<Mover> neighbors = new ArrayList<Mover>();
for (int i = 0; i < 4; i++) {
final PVector converted = convertDirection(i);
if (converted == null) { continue; }
final PVector newPosition = PVector.add(position, converted);
if (canMoveTo(newPosition)) {
neighbors.add(new Mover(newPosition.x, newPosition.y, steps+1));
}
}
return neighbors;
}
}
PVector convertDirection(int direction) {
if (direction < 0 || direction > 3) { return null; }
switch (direction) {
case 0:
return new PVector(-scl, 0);
case 1:
return new PVector(scl, 0);
case 2:
return new PVector(0, -scl);
case 3:
return new PVector(0, scl);
}
return null;
}
class Wall {
PVector start, end;
Wall(PVector a, PVector b) {
start = new PVector(a.x, a.y);
end = new PVector(b.x, b.y);
}
void show() {
line(start.x, start.y, end.x, end.y);
}
boolean intersect(Wall other) {
final PVector a = start.copy();
final PVector b = end.copy();
final PVector c = other.start.copy();
final PVector d = other.end.copy();
if ((pointEquals(a,c) && pointEquals(b,d)) || (pointEquals(a,d) && pointEquals(b,c))) { return true; }
final float t = (a.x-c.x) * (c.y-d.y) - (a.y-c.y) * (c.x-d.x);
final float u = (b.x-a.x) * (a.y-c.y) - (b.y-a.y) * (a.x-c.x);
final float D = (a.x-b.x) * (c.y-d.y) - (a.y-b.y) * (c.x-d.x);
if (D == 0) { return false; }
final float td = t / D;
final float ud = u / D;
if (td >= 0 && td <= 1 && ud >= 0 && ud <= 1) { return true; }
return false;
}
}
boolean pointEquals(PVector A, PVector B) {
return (A.x == B.x && A.y == B.y);
}