use sectors
This commit is contained in:
parent
344aa4af18
commit
e2acf6899e
|
@ -20,6 +20,7 @@ import javax.swing.JScrollPane;
|
|||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
final public class Solver extends JPanel {
|
||||
|
||||
|
@ -37,6 +38,10 @@ final public class Solver extends JPanel {
|
|||
// For each cell in the labyrinth: Has solve() visited it yet?
|
||||
private boolean[][] visited; // initialized in solve()
|
||||
private AtomicBoolean[][] visitedAtomic;
|
||||
private AtomicInteger numTasks = new AtomicInteger(0);
|
||||
|
||||
private Semaphore[] sectors;
|
||||
private static final int SECTOR_SIZE = (int) Math.sqrt(DEFAULT_WIDTH_IN_CELLS * DEFAULT_HEIGHT_IN_CELLS) / 50;
|
||||
|
||||
// determined by trial and error
|
||||
private static final int DISTANCE_PER_TASK = DEFAULT_WIDTH_IN_CELLS * DEFAULT_HEIGHT_IN_CELLS / 128;
|
||||
|
@ -123,15 +128,32 @@ final public class Solver extends JPanel {
|
|||
return pathSoFar.toArray(new Point[0]);
|
||||
}
|
||||
|
||||
private int getSectorsX() {
|
||||
return (int)Math.ceil((double)labyrinth.getWidth() / SECTOR_SIZE);
|
||||
}
|
||||
private int getSectorsY() {
|
||||
return (int)Math.ceil((double)labyrinth.getHeight() / SECTOR_SIZE);
|
||||
}
|
||||
private int getSectorId(Point p) {
|
||||
return (p.getX() / SECTOR_SIZE) + (p.getY() / SECTOR_SIZE) * getSectorsX();
|
||||
}
|
||||
|
||||
public Point[] solveConcurrently() {
|
||||
// dummy origin direction for start
|
||||
PointAndDirection start = new PointAndDirection(labyrinth.getStart(), null);
|
||||
|
||||
visitedAtomic = new AtomicBoolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
||||
for (int i = 0; i < visitedAtomic.length; i++) {
|
||||
for (int j = 0; j < visitedAtomic[i].length; j++) {
|
||||
visitedAtomic[i][j] = new AtomicBoolean(false);
|
||||
}
|
||||
// visitedAtomic = new AtomicBoolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
||||
// for (int i = 0; i < visitedAtomic.length; i++) {
|
||||
// for (int j = 0; j < visitedAtomic[i].length; j++) {
|
||||
// visitedAtomic[i][j] = new AtomicBoolean(false);
|
||||
// }
|
||||
// }
|
||||
|
||||
visited = new boolean[labyrinth.getWidth()][labyrinth.getHeight()];
|
||||
|
||||
sectors = new Semaphore[getSectorsX() * getSectorsY()];
|
||||
for (int i = 0; i < sectors.length; i++) {
|
||||
sectors[i] = new Semaphore(1);
|
||||
}
|
||||
|
||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||
|
@ -140,6 +162,9 @@ final public class Solver extends JPanel {
|
|||
ConcurrentSolverTask t = new ConcurrentSolverTask(start, pathSoFar, pool);
|
||||
Point[] result = pool.invoke(t);
|
||||
|
||||
System.out.println("Used tasks: " + numTasks.get());
|
||||
System.out.println("Task to Solution Length Ratio: " + (double)result.length / numTasks.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -149,6 +174,7 @@ final public class Solver extends JPanel {
|
|||
private ArrayDeque<Point> pathSoFar;
|
||||
private ForkJoinPool pool;
|
||||
private ArrayList<ConcurrentSolverTask> subtasks;
|
||||
private int currentSector;
|
||||
public ConcurrentSolverTask(PointAndDirection start, ArrayDeque<Point> pathSoFar, ForkJoinPool pool) {
|
||||
this.start = start;
|
||||
this.pathSoFar = pathSoFar;
|
||||
|
@ -156,9 +182,33 @@ final public class Solver extends JPanel {
|
|||
|
||||
this.backtrackStack = new ArrayDeque<>();
|
||||
this.subtasks = new ArrayList<>();
|
||||
this.currentSector = -1;
|
||||
}
|
||||
|
||||
private void acquireSector(Point p) {
|
||||
if (getSectorId(p) == this.currentSector) return;
|
||||
if (this.currentSector >= 0) {
|
||||
// release previous sector
|
||||
sectors[this.currentSector].release();
|
||||
}
|
||||
this.currentSector = getSectorId(p);
|
||||
try {
|
||||
// acquire new sector
|
||||
sectors[this.currentSector].acquire();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseSector() {
|
||||
if (this.currentSector >= 0) {
|
||||
sectors[this.currentSector].release();
|
||||
}
|
||||
}
|
||||
|
||||
public Point[] compute() {
|
||||
numTasks.incrementAndGet();
|
||||
int currentLength = 0;
|
||||
Point current = this.start.getPoint();
|
||||
|
||||
|
@ -197,11 +247,19 @@ final public class Solver extends JPanel {
|
|||
|
||||
// check if that cell has been visited
|
||||
// set visitedAtomic to true if it has not been visited
|
||||
if (!visitedAtomic[neighbour.x][neighbour.y].compareAndSet(false, true)) {
|
||||
continue;
|
||||
}
|
||||
// if (!visitedAtomic[neighbour.x][neighbour.y].compareAndSet(false, true)) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
acquireSector(neighbour);
|
||||
if (visited[neighbour.x][neighbour.y]) continue;
|
||||
visited[neighbour.x][neighbour.y] = true;
|
||||
releaseSector();
|
||||
|
||||
|
||||
// System.out.println("Found unvisited neighbour: " + neighbour);
|
||||
if (currentLength >= DISTANCE_PER_TASK) {
|
||||
releaseSector();
|
||||
// if we have reached the distance limit, create a subtask
|
||||
ArrayDeque<Point> subPath = this.pathSoFar.clone();
|
||||
subPath.addLast(current);
|
||||
|
@ -210,8 +268,9 @@ final public class Solver extends JPanel {
|
|||
subPath,
|
||||
this.pool
|
||||
);
|
||||
subtask.fork();
|
||||
subtasks.add(subtask);
|
||||
|
||||
subtask.fork();
|
||||
} else {
|
||||
if (next == null) {
|
||||
// visit first unvisited neighbour next
|
||||
|
@ -224,7 +283,6 @@ final public class Solver extends JPanel {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at least one unvisited neighbour found
|
||||
if (next != null) {
|
||||
pathSoFar.addLast(current);
|
||||
|
@ -232,6 +290,7 @@ final public class Solver extends JPanel {
|
|||
currentLength++;
|
||||
}
|
||||
if (next == null) {
|
||||
releaseSector();
|
||||
// no unvisited neighbour found
|
||||
// backtrack if possible
|
||||
if (this.backtrackStack.isEmpty()) {
|
||||
|
|
Loading…
Reference in New Issue