diff --git a/src/Program.java b/src/Program.java index 2dda2440f00cdd849c956078b52c9e8ee362a830..a182e27ba7474e246c7b66769c7109d39548e725 100644 --- a/src/Program.java +++ b/src/Program.java @@ -1,10 +1,6 @@ // - 1 - -import window.MainWindowApproach1; -import window.MainWindowApproach2; - -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; +import approach2.window.MainWindowApproach2; public class Program { diff --git a/src/window/MainWindowApproach1.java b/src/approach1/window/MainWindowApproach1.java similarity index 97% rename from src/window/MainWindowApproach1.java rename to src/approach1/window/MainWindowApproach1.java index 8fb9460b2d65297f4be2e4b0dca7dda80eb9ff9c..b340212e054774bd47677144b8dab5b09a42a324 100644 --- a/src/window/MainWindowApproach1.java +++ b/src/approach1/window/MainWindowApproach1.java @@ -1,8 +1,9 @@ -package window; +package approach1.window; import approach1.algorithm.ParallelPathfinder; import approach1.parallel.MapLoader; import approach1.parallel.SharedRessources; +import framework.Game; import javax.imageio.ImageIO; import java.awt.*; diff --git a/src/approach2/ExplorerThread.java b/src/approach2/ExplorerThread.java index 6e2693c51fd4a92356ed287f5c1800221cb4b228..0993db46331318a658f653357b7ee2c16a87dea7 100644 --- a/src/approach2/ExplorerThread.java +++ b/src/approach2/ExplorerThread.java @@ -8,6 +8,8 @@ public class ExplorerThread extends Thread { @Override public void run() { + if (explorer == null) + return; explorer.explore(); } diff --git a/src/approach2/algorithm/Explorer.java b/src/approach2/algorithm/Explorer.java index dcff27d00c9ac3a4c51cfc9d1466bc8b6fba1afa..58f5c8ed59f888fbe2378eb212aff2081bf100dd 100644 --- a/src/approach2/algorithm/Explorer.java +++ b/src/approach2/algorithm/Explorer.java @@ -5,7 +5,9 @@ import structs.Vec3; import java.awt.*; import java.awt.geom.Point2D; +import java.util.ArrayDeque; import java.util.HashMap; +import java.util.Queue; import java.util.Stack; import java.util.concurrent.ConcurrentLinkedQueue; @@ -22,23 +24,20 @@ public class Explorer { this.steps = steps; } - private ConcurrentLinkedQueue<Point> openPoints - = new ConcurrentLinkedQueue<>(); + private Queue<Point> openPoints + = new ArrayDeque<>(); public void explore() { openPoints.offer(new Point(px, py)); while (!openPoints.isEmpty()) { - - Point cur = openPoints.poll(); int x = cur.x; int y = cur.y; - SharedRessources.getInstance().visit(x, y); boolean diff --git a/src/window/MainWindowApproach2.java b/src/approach2/window/MainWindowApproach2.java similarity index 93% rename from src/window/MainWindowApproach2.java rename to src/approach2/window/MainWindowApproach2.java index e1769c6c489c5dc32b006bddc1969d3e70ce4995..993bed05a6d9747526ae0a20e8b21e4bf704fe8d 100644 --- a/src/window/MainWindowApproach2.java +++ b/src/approach2/window/MainWindowApproach2.java @@ -1,8 +1,9 @@ -package window; +package approach2.window; import approach2.MapLoader; import approach2.SharedRessources; import approach2.algorithm.ParallelPathfinder; +import framework.Game; import javax.imageio.ImageIO; import java.awt.*; @@ -22,7 +23,7 @@ public class MainWindowApproach2 extends Game { @Override public void loadGame() { - SharedRessources.setMaximumCores(4); + SharedRessources.setMaximumCores(Integer.MAX_VALUE); try { MapLoader.getDefault().load(ImageIO.read(new File("examples/maze.png"))); diff --git a/src/approach3/misc/MapLoader.java b/src/approach3/misc/MapLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..d9abcdbddf1112506724a3a76047e34aef597752 --- /dev/null +++ b/src/approach3/misc/MapLoader.java @@ -0,0 +1,42 @@ +package approach3.misc; + +import approach3.parallel.SharedRessources; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; + +public class MapLoader { + + private int width; + private int height; + + private MapLoader() { + } + + private static MapLoader mapLoader; + + public static MapLoader getDefault() { + if (mapLoader == null) + mapLoader = new MapLoader(); + return mapLoader; + } + + public void load(BufferedImage src) { + this.width = src.getWidth(); + this.height = src.getHeight(); + + SharedRessources.getInstance().initialize(width, height); + + // https://stackoverflow.com/a/9470843/14727115 + byte[] pixels = ((DataBufferByte) src.getRaster().getDataBuffer()).getData(); + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + if (((BufferedImage) src).getRGB(i, j) == Color.black.getRGB()) + SharedRessources.getInstance().setWall(i, j); + } + } + } + +} diff --git a/src/approach3/parallel/SharedRessources.java b/src/approach3/parallel/SharedRessources.java new file mode 100644 index 0000000000000000000000000000000000000000..198eef2111f38a85278a69eb637e14b04e90ae4a --- /dev/null +++ b/src/approach3/parallel/SharedRessources.java @@ -0,0 +1,107 @@ +package approach3.parallel; + +import structs.Int3; + +import java.awt.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class SharedRessources { + private static final int AVAIBLE_CORES + = Runtime.getRuntime().availableProcessors(); + + private static int MAX_CORES = 1; + + public static void setMaxCores(int cores) { + MAX_CORES = cores >= AVAIBLE_CORES ? AVAIBLE_CORES : cores; + } + + private static SharedRessources sharedRessources; + + public static SharedRessources getInstance() { + if (sharedRessources == null) + sharedRessources + = new SharedRessources(); + + return sharedRessources; + } + + private ExecutorService threadPool; + + private Int3[] data; + private boolean[] walls; + + private int width; + private int height; + + private Point start; + private Point end; + + private volatile boolean found; + + private SharedRessources() { + threadPool = Executors.newFixedThreadPool(MAX_CORES); + } + + public void initialize(int w, int h) { + this.width = w; + this.height = h; + + + data = new Int3[width * height]; + for (int i = 0; i < data.length; i++) + data[i] = new Int3(0, 0, Integer.MAX_VALUE); + + walls = new boolean[width * height]; + } + + + public void setFound(boolean found) { + this.found = found; + } + + public boolean isFound() { + return found; + } + + public void setStart(int x, int y) { + start = new Point(x, y); + } + + public void setEnd(int x, int y) { + end = new Point(x, y); + } + + public Point getStart() { + return start; + } + + public Point getEnd() { + return end; + } + + public ExecutorService getExecutor() { + return threadPool; + } + + public int getStep(int x, int y) { + synchronized (this) { + return data[x + y * width].getZ(); + } + } + + public void setData(int x, int y, int dirX, int dirY, int step) { + synchronized (this) { + data[x + y * width] = new Int3(dirX, dirY, step); + } + } + + public boolean isWall(int x, int y) { + return walls[x + y * width]; + } + + public void setWall(int x, int y) { + walls[x + y * width] = true; + } + +} diff --git a/src/approach3/parallel/WallBasedPathfinder.java b/src/approach3/parallel/WallBasedPathfinder.java new file mode 100644 index 0000000000000000000000000000000000000000..a0270c4597736085268e3c881d7eafcae11a9890 --- /dev/null +++ b/src/approach3/parallel/WallBasedPathfinder.java @@ -0,0 +1,7 @@ +package approach3.parallel; + +public class WallBasedPathfinder { + + + +} diff --git a/src/approach3/parallel/operations/Flood.java b/src/approach3/parallel/operations/Flood.java new file mode 100644 index 0000000000000000000000000000000000000000..952adfe9c6e8c3bae9e0f5a7b917560dbe7122be --- /dev/null +++ b/src/approach3/parallel/operations/Flood.java @@ -0,0 +1,150 @@ +package approach3.parallel.operations; + +import approach3.parallel.SharedRessources; + +import java.awt.*; +import java.util.ArrayDeque; +import java.util.Queue; + +/** + * Diese Klasse überflutet alle Bereiche an der Wand und probiert an jedem Punkt eine + * neue Trace zum Ziel zu generieren + */ +public class Flood implements Runnable { + + private int px; + private int py; + + private int steps; + + private Queue<Point> openPoints + = new ArrayDeque<>(); + + public Flood(int x, int y, int steps) { + this.px = x; + this.py = y; + this.steps = steps; + } + + + @Override + public void run() { + if (SharedRessources.getInstance().isWall(px, py)) + return; + + openPoints.offer(new Point(px, py)); + + while (!openPoints.isEmpty()) { + + if (SharedRessources.getInstance().isFound()) + return; + + Point cur + = openPoints.poll(); + + + + int x = cur.x; + int y = cur.y; + + + if(steps >= SharedRessources.getInstance().getStep(x, y)) + break; + + boolean + left = SharedRessources.getInstance().isWall(x - 1, y); + boolean + right = SharedRessources.getInstance().isWall(x + 1, y); + boolean up + = SharedRessources.getInstance().isWall(x, y - 1); + boolean down + = SharedRessources.getInstance().isWall(x, y + 1); + + boolean leftUp = + SharedRessources.getInstance().isWall(x - 1, y - 1); + boolean rightUp = + SharedRessources.getInstance().isWall(x + 1, y - 1); + + boolean leftDown = + SharedRessources.getInstance().isWall(x - 1, y + 1); + boolean rightDown = + SharedRessources.getInstance().isWall(x + 1, y + 1); + + + int stepLeft + = SharedRessources.getInstance().getStep(x - 1, y); + int stepRight + = SharedRessources.getInstance().getStep(x + 1, y); + int stepUp + = SharedRessources.getInstance().getStep(x, y - 1); + int stepDown + = SharedRessources.getInstance().getStep(x, y + 1); + + if (!left && !right && !up && !down && !rightDown && !rightUp && !leftDown && !leftUp) + continue; + + if (!left) { + if (steps < stepLeft) { + SharedRessources.getInstance() + .setData(x - 1, y, 1, 0, steps + 1); + + openPoints + .offer(new Point(x - 1, y)); + + } + } + + if (!right) { + if (steps < stepRight) { + SharedRessources.getInstance() + .setData(x + 1, y, -1, 0, steps + 1); + + + openPoints + .offer(new Point(x + 1, y)); + } + } + + if (!up) { + if (steps < stepUp) { + SharedRessources.getInstance() + .setData(x, y - 1, 0, 1, steps + 1); + + + openPoints + .offer(new Point(x, y - 1)); + } + } + + if (!down) { + if (steps < stepDown) { + SharedRessources.getInstance() + .setData(x, y + 1, 0, -1, steps + 1); + + + openPoints + .offer(new Point(x, y + 1)); + } + } + + + SharedRessources + .getInstance() + .getExecutor() + .execute(new Trace( + x, + y, + SharedRessources.getInstance().getStart().x, + SharedRessources.getInstance().getStart().y, + steps)); + + steps++; + + } + + + System.out.println("Done flooding."); + + + } +} diff --git a/src/approach3/parallel/operations/Trace.java b/src/approach3/parallel/operations/Trace.java new file mode 100644 index 0000000000000000000000000000000000000000..c1b93fc47eab9f6a9e6635af748f99337d76b10d --- /dev/null +++ b/src/approach3/parallel/operations/Trace.java @@ -0,0 +1,106 @@ +package approach3.parallel.operations; + +import approach3.parallel.SharedRessources; + +// Source: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases +public class Trace implements Runnable { + + private int x0, y0; + private int x1, y1; + + private int step; + + public Trace(int x0, int y0, int x1, int y1, int step) { + this.x0 = x0; + this.y0 = y0; + + this.x1 = x1; + this.y1 = y1; + + this.step = step; + } + + @Override + public void run() { + + int oldX = 0; + int oldY = 0; + + + int dx = Math.abs(x1 - x0); + int sx = x0 < x1 ? 1 : -1; + + int dy = -Math.abs(y1 - y0); + int sy = y0 < y1 ? 1 : -1; + + int err = dx + dy; + + while (true) { + + if (SharedRessources.getInstance().isFound()) + return; + + oldX = x0; + oldY = y0; + + if (x0 == x1 && y0 == y1) { + SharedRessources.getInstance().setFound(true); + System.out.println("FOUND!!!!!!!!"); + break; + } + + int err2 = 2 * err; + + if (err2 >= dy) { + err += dy; + x0 += sx; + } + if (err2 <= dx) { + err += dx; + y0 += sy; + } + + step++; + + int currentStep + = SharedRessources.getInstance().getStep(x0, y0); + + if (SharedRessources.getInstance().isWall(x0, y0)) { + + if (step < SharedRessources.getInstance().getStep(oldX - 1, oldY)) + SharedRessources + .getInstance() + .getExecutor() + .execute(new Flood(oldX - 1, oldY, step)); + + if (step < SharedRessources.getInstance().getStep(oldX + 1, oldY)) + SharedRessources + .getInstance() + .getExecutor() + .execute(new Flood(oldX + 1, oldY, step)); + + if (step < SharedRessources.getInstance().getStep(oldX, oldY - 1)) + SharedRessources + .getInstance() + .getExecutor() + .execute(new Flood(oldX, oldY - 1, step)); + + if (step < SharedRessources.getInstance().getStep(oldX, oldY + 1)) + SharedRessources + .getInstance() + .getExecutor() + .execute(new Flood(oldX, oldY + 1, step)); + + break; + } else if (step < currentStep) { + int dirX = x0 - oldX; + int dirY = y0 - oldY; + + SharedRessources.getInstance() + .setData(x0, y0, dirX, dirY, step); + + } + } + + } +} diff --git a/src/approach3/window/MainWindowApproach3.java b/src/approach3/window/MainWindowApproach3.java new file mode 100644 index 0000000000000000000000000000000000000000..e70b60888ba286cbff1f23fdbcb91bbfc4f63339 --- /dev/null +++ b/src/approach3/window/MainWindowApproach3.java @@ -0,0 +1,26 @@ +package approach3.window; + +import framework.Game; + +import java.awt.*; + +public class MainWindowApproach3 extends Game { + public MainWindowApproach3(String title, int w, int h) { + super(title, w, h); + } + + @Override + public void loadGame() { + + } + + @Override + public void updateGame() { + + } + + @Override + public void renderGame(Graphics g) { + + } +} diff --git a/src/window/Game.java b/src/framework/Game.java similarity index 99% rename from src/window/Game.java rename to src/framework/Game.java index 8adbaa3190b4b7e7c49ca22c1da07c5a2732e5f2..061c4d9595ee01bc36397b63483719f6c4a49f10 100644 --- a/src/window/Game.java +++ b/src/framework/Game.java @@ -1,4 +1,4 @@ -package window; +package framework; import javax.swing.*; import java.awt.*; diff --git a/src/structs/Int3.java b/src/structs/Int3.java new file mode 100644 index 0000000000000000000000000000000000000000..89ae1a9dab740ba2ff88e374f899484af75ecf5d --- /dev/null +++ b/src/structs/Int3.java @@ -0,0 +1,37 @@ +package structs; + +public class Int3 { + private int x; + private int y; + private int z; + + public Int3(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void setX(int x) { + this.x = x; + } + + public void setY(int y) { + this.y = y; + } + + public void setZ(int z) { + this.z = z; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } +}