From 7990f5d06d9da5c421010e96632e4420e483e35a Mon Sep 17 00:00:00 2001 From: NET-D3v3l0p3r <3r0rxx@gmail.com> Date: Fri, 23 Apr 2021 18:11:44 +0200 Subject: [PATCH] =?UTF-8?q?2=20Ans=C3=A4tze=20->=20simples=20flood=20fill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/debug.png | Bin 0 -> 884 bytes src/Program.java | 6 +- src/{ => approach1}/algorithm/Explorer.java | 10 +- .../algorithm/ParallelPathfinder.java | 5 +- .../algorithm/WorkingExplorers.java | 8 +- .../parallel/EagerWorkingThread.java | 2 +- src/{ => approach1}/parallel/MapLoader.java | 2 +- .../parallel/SharedRessources.java | 16 ++- src/approach2/ExplorerThread.java | 17 +++ src/approach2/MapLoader.java | 45 ++++++ src/approach2/SharedRessources.java | 121 ++++++++++++++++ src/approach2/algorithm/Explorer.java | 119 ++++++++++++++++ .../algorithm/ParallelPathfinder.java | 130 ++++++++++++++++++ ...inWindow.java => MainWindowApproach1.java} | 11 +- src/window/MainWindowApproach2.java | 71 ++++++++++ 15 files changed, 531 insertions(+), 32 deletions(-) create mode 100644 examples/debug.png rename src/{ => approach1}/algorithm/Explorer.java (95%) rename src/{ => approach1}/algorithm/ParallelPathfinder.java (97%) rename src/{ => approach1}/algorithm/WorkingExplorers.java (89%) rename src/{ => approach1}/parallel/EagerWorkingThread.java (97%) rename src/{ => approach1}/parallel/MapLoader.java (98%) rename src/{ => approach1}/parallel/SharedRessources.java (90%) create mode 100644 src/approach2/ExplorerThread.java create mode 100644 src/approach2/MapLoader.java create mode 100644 src/approach2/SharedRessources.java create mode 100644 src/approach2/algorithm/Explorer.java create mode 100644 src/approach2/algorithm/ParallelPathfinder.java rename src/window/{MainWindow.java => MainWindowApproach1.java} (86%) create mode 100644 src/window/MainWindowApproach2.java diff --git a/examples/debug.png b/examples/debug.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb918962ed113c30f201511e1c0da6f8bebec8c GIT binary patch literal 884 zcmeAS@N?(olHy`uVBq!ia0y~yVA#&Uz_6TyiGhLP&aJ3m1_lPk;vjb?hIQv;UNSH+ zu%tWsIx;Y9?C1WI$jZRLz**oCS<Jw|cNl~jkLRyQVPIh9^mK6ysfc@f$&l-S14GM! z-~X2jb4-hFXP$fO(qt9SqQ&Yz4UV`7*|yE_Sae)K*z=1-l2WIfvyaNf<c?02Djvg$ uF8zvXlU^8(DjE%fA({#%sr<ZbslRU@&zbjjB|Qub3=E#GelF{r5}E*XNJD%8 literal 0 HcmV?d00001 diff --git a/src/Program.java b/src/Program.java index a25e53b..ee73c02 100644 --- a/src/Program.java +++ b/src/Program.java @@ -1,13 +1,13 @@ // - 1 - -import parallel.EagerWorkingThread; -import window.MainWindow; +import window.MainWindowApproach1; +import window.MainWindowApproach2; public class Program { public static void main(String[] args) throws Exception { - MainWindow window = new MainWindow("Pathfinder v1", 1080, 1080); + MainWindowApproach2 window = new MainWindowApproach2("Pathfinder v1", 1080, 1080); window.run(); } diff --git a/src/algorithm/Explorer.java b/src/approach1/algorithm/Explorer.java similarity index 95% rename from src/algorithm/Explorer.java rename to src/approach1/algorithm/Explorer.java index 7e9fe2c..092cfc7 100644 --- a/src/algorithm/Explorer.java +++ b/src/approach1/algorithm/Explorer.java @@ -1,7 +1,6 @@ -package algorithm; +package approach1.algorithm; -import parallel.EagerWorkingThread; -import parallel.SharedRessources; +import approach1.parallel.SharedRessources; import structs.Vec3; public class Explorer { @@ -20,11 +19,6 @@ public class Explorer { private Direction direction; - - public int getSteps() { - return steps; - } - public Explorer(int x, int y, int steps, Direction direction) { this.x = x; this.y = y; diff --git a/src/algorithm/ParallelPathfinder.java b/src/approach1/algorithm/ParallelPathfinder.java similarity index 97% rename from src/algorithm/ParallelPathfinder.java rename to src/approach1/algorithm/ParallelPathfinder.java index 217e09a..fbb5bc4 100644 --- a/src/algorithm/ParallelPathfinder.java +++ b/src/approach1/algorithm/ParallelPathfinder.java @@ -1,7 +1,6 @@ -package algorithm; +package approach1.algorithm; -import parallel.EagerWorkingThread; -import parallel.SharedRessources; +import approach1.parallel.SharedRessources; import structs.Vec3; import java.awt.*; diff --git a/src/algorithm/WorkingExplorers.java b/src/approach1/algorithm/WorkingExplorers.java similarity index 89% rename from src/algorithm/WorkingExplorers.java rename to src/approach1/algorithm/WorkingExplorers.java index 8b6ad68..787350c 100644 --- a/src/algorithm/WorkingExplorers.java +++ b/src/approach1/algorithm/WorkingExplorers.java @@ -1,12 +1,10 @@ -package algorithm; +package approach1.algorithm; -import parallel.EagerWorkingThread; -import parallel.SharedRessources; +import approach1.parallel.EagerWorkingThread; +import approach1.parallel.SharedRessources; import java.util.*; -import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.LinkedBlockingQueue; public class WorkingExplorers extends EagerWorkingThread { diff --git a/src/parallel/EagerWorkingThread.java b/src/approach1/parallel/EagerWorkingThread.java similarity index 97% rename from src/parallel/EagerWorkingThread.java rename to src/approach1/parallel/EagerWorkingThread.java index cb1bba6..6145beb 100644 --- a/src/parallel/EagerWorkingThread.java +++ b/src/approach1/parallel/EagerWorkingThread.java @@ -1,4 +1,4 @@ -package parallel; +package approach1.parallel; public abstract class EagerWorkingThread extends Thread { diff --git a/src/parallel/MapLoader.java b/src/approach1/parallel/MapLoader.java similarity index 98% rename from src/parallel/MapLoader.java rename to src/approach1/parallel/MapLoader.java index d0721ba..50906d9 100644 --- a/src/parallel/MapLoader.java +++ b/src/approach1/parallel/MapLoader.java @@ -1,4 +1,4 @@ -package parallel; +package approach1.parallel; import structs.Vec3; diff --git a/src/parallel/SharedRessources.java b/src/approach1/parallel/SharedRessources.java similarity index 90% rename from src/parallel/SharedRessources.java rename to src/approach1/parallel/SharedRessources.java index 7f115e9..5119654 100644 --- a/src/parallel/SharedRessources.java +++ b/src/approach1/parallel/SharedRessources.java @@ -1,11 +1,9 @@ -package parallel; +package approach1.parallel; -import algorithm.Explorer; -import algorithm.WorkingExplorers; +import approach1.algorithm.Explorer; +import approach1.algorithm.WorkingExplorers; import structs.Vec3; -import java.util.Stack; - public class SharedRessources { private static int USING_CORES; @@ -81,6 +79,14 @@ public class SharedRessources { } public void add(Explorer explorer) { + + for(int i = 0; i < maxCores; i++){ + if(workingThreads[i].isReady()){ + workingThreads[i].add(explorer); + return; + } + } + this.workingThreads[(currentCore++) % maxCores].add(explorer); } diff --git a/src/approach2/ExplorerThread.java b/src/approach2/ExplorerThread.java new file mode 100644 index 0000000..6e2693c --- /dev/null +++ b/src/approach2/ExplorerThread.java @@ -0,0 +1,17 @@ +package approach2; + +import approach2.algorithm.Explorer; + +public class ExplorerThread extends Thread { + + private Explorer explorer; + + @Override + public void run() { + explorer.explore(); + } + + public void setExplorer(Explorer explorer) { + this.explorer = explorer; + } +} diff --git a/src/approach2/MapLoader.java b/src/approach2/MapLoader.java new file mode 100644 index 0000000..d9dd596 --- /dev/null +++ b/src/approach2/MapLoader.java @@ -0,0 +1,45 @@ +package approach2; + +import structs.Vec3; + +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().setWidth(width); + SharedRessources.getInstance().setHeight(height); + + SharedRessources.getInstance().initializeArrays(); + + // 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/approach2/SharedRessources.java b/src/approach2/SharedRessources.java new file mode 100644 index 0000000..2166944 --- /dev/null +++ b/src/approach2/SharedRessources.java @@ -0,0 +1,121 @@ +package approach2; + +import approach1.algorithm.WorkingExplorers; +import approach2.algorithm.Explorer; +import structs.Vec3; + +public class SharedRessources { + + private static SharedRessources sharedRessources; + + public static SharedRessources getInstance() { + if (sharedRessources == null) + sharedRessources = new SharedRessources(USING_CORES); + return sharedRessources; + } + + private static int USING_CORES; + + /*** + * Use Integer.MAX_VALUE for all cores + * @param cores + */ + public static void setMaximumCores(int cores) { + if (cores >= Runtime.getRuntime().availableProcessors()) + cores = Runtime.getRuntime().availableProcessors(); + USING_CORES = cores; + } + + private int width; + private int height; + + private boolean[] wallMatrix; + private boolean[] visitMatrix; + + private Vec3[] directionMatrix; + + private int maxCores; + private int currentCore; + + private ExplorerThread[] workingThreads; + + + private SharedRessources(int cores) { + maxCores = cores; + currentCore = 0; + + System.out.println("[*] Using " + maxCores + " cores."); + + workingThreads = new ExplorerThread[maxCores]; + for (int i = 0; i < maxCores; i++) + workingThreads[i] = new ExplorerThread(); + } + + public void initializeArrays() { + wallMatrix = new boolean[width * height]; + visitMatrix = new boolean[width * height]; + directionMatrix = new Vec3[width * height]; + + for (int i = 0; i < directionMatrix.length; i++) + directionMatrix[i] = new Vec3(0, 0, Integer.MAX_VALUE); + } + + public void setExplorer(Explorer explorer) { + int index + = (currentCore++) % maxCores; + + workingThreads[index] + .setExplorer(explorer); + } + + public void start() { + for (int i = 0; i < maxCores; i++) + workingThreads[i].start(); + } + + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + protected void setWidth(int width) { + this.width = width; + } + + protected void setHeight(int height) { + this.height = height; + } + + protected void setWall(int x, int y) { + wallMatrix[x + y * width] = true; + } + + public boolean isWall(int x, int y) { + return wallMatrix[x + y * width]; + } + + public int getStep(int x, int y) { + return (int) directionMatrix[x + y * width].getZ(); + } + + public void visit(int x, int y) { + visitMatrix[x + y * width] = true; + } + + public boolean isVisited(int x, int y) { + return visitMatrix[x + y * width]; + } + + public Vec3 getData(int x, int y) { + return directionMatrix[x + y * width]; + } + + public void set(int x, int y, Vec3 data) { + directionMatrix[x + y * width] + = new Vec3(data.getX(), data.getY(), data.getZ()); + } +} diff --git a/src/approach2/algorithm/Explorer.java b/src/approach2/algorithm/Explorer.java new file mode 100644 index 0000000..727edd3 --- /dev/null +++ b/src/approach2/algorithm/Explorer.java @@ -0,0 +1,119 @@ +package approach2.algorithm; + +import approach2.SharedRessources; +import structs.Vec3; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.util.HashMap; +import java.util.Stack; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class Explorer { + + private int px; + private int py; + + private int steps; + + public Explorer(int x, int y, int steps) { + this.px = x; + this.py = y; + this.steps = steps; + } + + private ConcurrentLinkedQueue<Point> openPoints + = new ConcurrentLinkedQueue<>(); + + 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 + 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); + + 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) { + if (steps < stepLeft) { + SharedRessources.getInstance() + .set(x - 1, y, new Vec3(1, 0, steps + 1)); + + openPoints + .offer(new Point(x - 1, y)); + + } + } + + if (!right) { + if (steps < stepRight) { + SharedRessources.getInstance() + .set(x + 1, y, new Vec3(-1, 0, steps + 1)); + + + openPoints + .offer(new Point(x + 1, y)); + } + } + + if (!up) { + if (steps < stepUp) { + SharedRessources.getInstance() + .set(x, y - 1, new Vec3(0, 1, steps + 1)); + + + openPoints + .offer(new Point(x, y - 1)); + } + } + + if (!down) { + if (steps < stepDown) { + SharedRessources.getInstance() + .set(x, y + 1, new Vec3(0, -1, steps + 1)); + + + openPoints + .offer(new Point(x, y + 1)); + } + } + + + + steps++; + + + + + } + + + } + + +} diff --git a/src/approach2/algorithm/ParallelPathfinder.java b/src/approach2/algorithm/ParallelPathfinder.java new file mode 100644 index 0000000..724f4ca --- /dev/null +++ b/src/approach2/algorithm/ParallelPathfinder.java @@ -0,0 +1,130 @@ +package approach2.algorithm; + +import approach2.SharedRessources; +import structs.Vec3; + +import java.awt.*; +import java.util.ArrayList; + +public class ParallelPathfinder { + + int lastDestX; + int lastDestY; + + public void flood(int destX, int destY) { + System.out.println("[*] Flooding..."); + + lastDestX = destX; + lastDestY = destY; + + SharedRessources + .getInstance() + .setExplorer(new Explorer(destX - 1, destY, 1)); + + SharedRessources + .getInstance() + .setExplorer(new Explorer(destX + 1, destY, 1)); + + SharedRessources + .getInstance() + .setExplorer(new Explorer(destX, destY - 1, 1)); + SharedRessources + .getInstance() + .setExplorer(new Explorer(destX, destY + 1, 1)); + + + + + SharedRessources.getInstance() + .set(destX - 1, destY, new Vec3(1, 0, 1)); + + SharedRessources.getInstance() + .set(destX + 1, destY, new Vec3(-1, 0, 1)); + + SharedRessources.getInstance() + .set(destX, destY - 1, new Vec3(0, +1, 1)); + + SharedRessources.getInstance() + .set(destX, destY + 1, new Vec3(0, -1, 1)); + + + SharedRessources + .getInstance().start(); + + } + + public ArrayList<Point> calculatePath(int startX, int startY, int destX, int destY) { + ArrayList<Point> path + = new ArrayList<>(); + + int x = startX; + int y = startY; + + while (x != destX || y != destY) { + + path.add(new Point(x, y)); + + Vec3 currentDir + = + SharedRessources.getInstance().getData(x, y); + + int dx = (int) currentDir.getX(); + int dy = (int) currentDir.getY(); + + if (dx == 0 && dy == 0) + return null; + + x += dx; + y += dy; + } + + System.out.println("Done."); + + return path; + } + + public void draw(Graphics g) { + + for (int j = 0; j < SharedRessources.getInstance().getHeight(); j++) { + for (int i = 0; i < SharedRessources.getInstance().getWidth(); i++) { + + + if (SharedRessources.getInstance().isWall(i, j)) { + g.setColor(Color.blue); + g.fillRect(i * 10, j * 10, 10, 10); + } + else { + + + int dx = (int) SharedRessources.getInstance().getData(i, j).getX() * 5; + int dy = (int) SharedRessources.getInstance().getData(i, j).getY() * 5; + + if (dx != 0 || dy != 0) { + int green = SharedRessources.getInstance().getStep(i, j); + if (green >= 255) + green = 255; + Color color + = new Color(0, green, 0); + + g.setColor(color); + + g.fillRect(i * 10, j * 10, 10, 10); + + g.setColor(Color.red); + g.drawLine(i * 10, j * 10, i * 10 + dx, j * 10 + dy); + + + + } else { + g.setColor(Color.black); + g.fillRect(i * 10, j * 10, 10, 10); + } + } + + + + + } + } + } +} diff --git a/src/window/MainWindow.java b/src/window/MainWindowApproach1.java similarity index 86% rename from src/window/MainWindow.java rename to src/window/MainWindowApproach1.java index 3600393..8fb9460 100644 --- a/src/window/MainWindow.java +++ b/src/window/MainWindowApproach1.java @@ -1,19 +1,18 @@ package window; -import algorithm.ParallelPathfinder; -import parallel.MapLoader; -import parallel.SharedRessources; +import approach1.algorithm.ParallelPathfinder; +import approach1.parallel.MapLoader; +import approach1.parallel.SharedRessources; import javax.imageio.ImageIO; import java.awt.*; -import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; -public class MainWindow extends Game { - public MainWindow(String title, int w, int h) { +public class MainWindowApproach1 extends Game { + public MainWindowApproach1(String title, int w, int h) { super(title, w, h); } diff --git a/src/window/MainWindowApproach2.java b/src/window/MainWindowApproach2.java new file mode 100644 index 0000000..e1769c6 --- /dev/null +++ b/src/window/MainWindowApproach2.java @@ -0,0 +1,71 @@ +package window; + +import approach2.MapLoader; +import approach2.SharedRessources; +import approach2.algorithm.ParallelPathfinder; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +public class MainWindowApproach2 extends Game { + public MainWindowApproach2(String title, int w, int h) { + super(title, w, h); + } + + + ParallelPathfinder parallelPathfinder + = new ParallelPathfinder(); + + @Override + public void loadGame() { + SharedRessources.setMaximumCores(4); + + try { + MapLoader.getDefault().load(ImageIO.read(new File("examples/maze.png"))); + } catch (IOException e) { + e.printStackTrace(); + } + + parallelPathfinder.flood(80 ,80); + + + } + + + private boolean pressed; + ArrayList<Point> pts = new ArrayList<>(); + @Override + public void updateGame() { + + if (isMouseKeyDown(MouseEvent.BUTTON1) && !pressed) { + pts = + parallelPathfinder.calculatePath(this.getMouseX() / 10, this.getMouseY() / 10, 80, 80); + pressed = true; + } + + if (isMouseKeyUp(MouseEvent.BUTTON1)) + pressed = false; + + } + + @Override + public void renderGame(Graphics g) { + parallelPathfinder.draw(g); + + + + if (pts == null) + return; + + g.setColor(Color.red); + for (var pt : pts) { + g.fillRect(pt.x * 10, pt.y * 10, 10, 10); + } + } + + +} -- GitLab