vendredi 22 mai 2015

Labyrinth mittel FloodFill

Hallo zusammen,

ich möchte ein Labyrinth mittels des FloodFill - Algorithmus implementieren (siehe Anhang). Dazu habe ich diese Klasse gegeben:

Java Code:

  1. import java.util.List;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.Collections;
  5. import java.util.Random;
  6. import java.awt.Point;
  7.  
  8. public class Labyrinth {
  9. // Größe der Karte. Die Karte ist quadratisch
  10. private int size;
  11. // Karte. true = Feld begehbar, false = Feld blockiert
  12. private boolean[][] map;
  13. // initiale Position der Prinzessin
  14. private Point startingPoint;
  15. // Position des Prinzen
  16. private Point destinationPoint;
  17. // aktuelle Position der Prinzessin
  18. private Point currentPosition;
  19.  
  20. // Richtungen, als int kodiert
  21. private static final int kDirUp = 0;
  22. private static final int kDirDown = 1;
  23. private static final int kDirRight = 2;
  24. private static final int kDirLeft = 3;
  25. // erste und letzte Richtung (um Richtungen in Schleifen zu durchlaufen
  26. // etc.)
  27. private static final int kDirFirst = 0;
  28. private static final int kDirLast = 3;
  29.  
  30. // Interface um die GUI über Updates zu informieren
  31. public interface Listener {
  32. // aktuelle des Position der Prinzessin (= die Position, die von
  33. // getCurrentPosition() zurückgegeben wird) hat sich geändert
  34. void princessUpdated();
  35. };
  36.  
  37. private List<Listener> listeners = new ArrayList<Listener>();
  38.  
  39. Labyrinth(int size) {
  40. this.size = size;
  41.  
  42. Random random = new Random();
  43.  
  44. map = new boolean[size][size];
  45. floodFill(new Point(size / 2, size / 2), random);
  46.  
  47. // finde freie Start- und Zielkoordinaten
  48. List<Point> free = new ArrayList<Point>();
  49. for (int x = 0; x < size; x++)
  50. for (int y = 0; y < size; y++)
  51. if (map[x][y])
  52. free.add(new Point(x, y));
  53.  
  54. if (free.size() == 0)
  55. throw new RuntimeException(
  56. "There are not free fields in the labyrinth");
  57.  
  58. startingPoint = free.get(random.nextInt(free.size()));
  59. destinationPoint = free.get(random.nextInt(free.size()));
  60. currentPosition = startingPoint;
  61. }
  62.  
  63. // wird vom GUI Code benutzt, um einen Listener zu installieren
  64. public void addListener(Listener listener) {
  65. listeners.add(listener);
  66. }
  67.  
  68. public int getMapSize() {
  69. return size;
  70. }
  71.  
  72. public Point getStartingPoint() {
  73. return startingPoint;
  74. }
  75.  
  76. public Point getDestinationPoint() {
  77. return destinationPoint;
  78. }
  79.  
  80. public Point getCurrentPosition() {
  81. return currentPosition;
  82. }
  83.  
  84. public boolean tileIsBlocked(int x, int y) {
  85. return !map[x][y];
  86. }
  87.  
  88. // ruft alle Listener auf. Sollte nach jedem Update von
  89. // currentPosition aufgerufen werden.
  90. private void princessUpdated() {
  91. for (Listener listener : listeners)
  92. listener.princessUpdated();
  93. }
  94.  
  95. // berechnet zu einem gegebenen Punkt den nächsten Punkt in
  96. // einer bestimmten Richtung. Überprüft NICHT, ob der
  97. // Ergebnispunkt auch wirklich auf der Karte liegt!
  98. private Point addDir(Point p, int direction) {
  99. switch (direction) {
  100. case kDirUp:
  101. return new Point(p.x, p.y - 1);
  102. case kDirDown:
  103. return new Point(p.x, p.y + 1);
  104. case kDirRight:
  105. return new Point(p.x + 1, p.y);
  106. case kDirLeft:
  107. return new Point(p.x - 1, p.y);
  108. default:
  109. throw new IllegalArgumentException("Illegal direction");
  110. }
  111. }
  112.  
  113. // testet, ob der gegebene Punkt auf der Karte liegt
  114. // (testet NICHT dessen Begehbarkeit!)
  115. private boolean onMap(Point p) {
  116. return p.x >= 0 && p.x < size && p.y >= 0 && p.y < size;
  117. }
  118.  
  119. private void floodFill(Point point, Random random) {
  120.  
  121. }
  122.  
  123. public void searchForKnight() {
  124.  
  125. }
  126. }


Die searchForKnight-Methode kann erstmal weggelassen werden.
Bis jetzt habe ich leider nur Methode à la
Java Code:

  1. private void floodFill(Point point, Random random) {
  2. for(int i = 0; i < 50; i++){
  3. map[random.nextInt(14)][random.nextInt(14)] = true;
  4. }
  5. }

oder ähnliches geschafft. "map[x][y] = true" bedeutet hier immer, dass hier ein freies Feld ist, false bedeutet, dass hier nicht gegangen werde kann. Auch schon aufwendigere Methoden, die ein Labyrinth mit verbunden Gängen erzeugt hat, sind mit gelungen. Aber nichts davon hatte was mit FloodFill oder einem vernünftigen Labyrinth zu tun.

Gegen ist zudem noch eine GUI:
Java Code:

  1. package b5P;
  2.  
  3.  
  4. // Autoren: Ulrich, Zur, van der Grinten, Lückerath
  5.  
  6. import java.awt.BorderLayout;
  7. import java.awt.Color;
  8. import java.awt.FlowLayout;
  9. import java.awt.Graphics;
  10. import java.awt.Image;
  11. import java.awt.Point;
  12. import java.awt.event.ActionEvent;
  13. import java.awt.event.ActionListener;
  14. import java.awt.image.BufferedImage;
  15. import java.io.File;
  16. import java.io.IOException;
  17.  
  18. import javax.imageio.ImageIO;
  19. import javax.swing.JButton;
  20. import javax.swing.JFrame;
  21. import javax.swing.JPanel;
  22.  
  23. public class GUI {
  24. private Labyrinth labyrinth;
  25.  
  26. private JFrame frame = new JFrame();
  27. private JPanel panelMain = new JPanel();
  28. private JPanel panelNorth = new JPanel();
  29. private JButton btnStart = new JButton();
  30. private Display display = new Display();
  31.  
  32. private Image imgPrince;
  33. private Image imgPrincess;
  34. private Image imgCensored;
  35. private BufferedImage imgGrass;
  36. private BufferedImage imgRock;
  37.  
  38. public GUI() {
  39. labyrinth = new Labyrinth(15);
  40. labyrinth.addListener(new Labyrinth.Listener() {
  41. @Override public void princessUpdated() {
  42. frame.repaint();
  43.  
  44. // damit man die Bewegung sehen kann
  45. try{
  46. Thread.sleep(500);
  47. } catch(InterruptedException e) { }
  48. }
  49. });
  50.  
  51. // initialisiere alle Swing-Komponenten
  52. btnStart.setText("Lösen!");
  53. btnStart.addActionListener(new ActionListener() {
  54. @Override public void actionPerformed(ActionEvent e) {
  55. // müssen das Labyrinth in einem anderen Thread lösen,
  56. // damit die GUI Anwendung reaktionsfähig bleibt.
  57. Runnable runnable = new Runnable() {
  58. @Override public void run() {
  59. labyrinth.searchForKnight();
  60. btnStart.setEnabled(true);
  61. }
  62. };
  63.  
  64. btnStart.setEnabled(false);
  65. new Thread(runnable).start();
  66. }
  67. });
  68.  
  69. panelNorth.setLayout(new FlowLayout(FlowLayout.CENTER));
  70. panelNorth.add(btnStart);
  71.  
  72. panelMain.setLayout(new BorderLayout());
  73. panelMain.add(panelNorth, BorderLayout.NORTH);
  74. panelMain.add(display, BorderLayout.CENTER);
  75.  
  76. // lade Bilder und skaliere auf richtige Größe
  77. try{
  78. imgGrass = ImageIO.read(new File("./res/grass.jpg"));
  79. imgRock = ImageIO.read(new File("./res/rock.jpg"));
  80.  
  81. imgPrince = ImageIO.read(new File("./res/prince.png"))
  82. .getScaledInstance(60, 60, Image.SCALE_FAST);
  83. imgPrincess = ImageIO.read(new File("./res/princess.png"))
  84. .getScaledInstance(60, 60, Image.SCALE_FAST);
  85.  
  86. imgCensored = ImageIO.read(new File("./res/censored.png"))
  87. .getScaledInstance(80, 60, Image.SCALE_FAST);
  88. }catch(IOException e){
  89. throw new RuntimeException("Could not load image", e);
  90. };
  91.  
  92. // zeige das Fenster an
  93. frame.setSize(600, 665);
  94. frame.setResizable(false);
  95. frame.setTitle("Save the prince!");
  96. frame.setContentPane(panelMain);
  97. frame.setVisible(true);
  98. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  99. }
  100.  
  101. public static void main(String args[]){
  102. new GUI();
  103. }
  104.  
  105. // unser Zeichenbereich
  106. class Display extends JPanel {
  107. @Override public void paintComponent(Graphics g) {
  108. super.paintComponent(g);
  109.  
  110. int height = this.getHeight();
  111. int width = this.getWidth();
  112.  
  113. // fülle Hintergrund
  114. g.setColor(Color.white);
  115. g.fillRect(0, 0, width, height);
  116.  
  117. for(int y = 0; y < labyrinth.getMapSize(); y++){
  118. for(int x = 0; x < labyrinth.getMapSize(); x++){
  119. // zeichne Feld
  120. if(labyrinth.tileIsBlocked(x, y)) {
  121. g.drawImage(imgRock, x * 40, y * 40, null);
  122. }else{
  123. g.drawImage(imgGrass, x * 40, y * 40, null);
  124. }
  125.  
  126. // zeichne Rahmen um die Grafik
  127. g.setColor(Color.BLACK);
  128. g.drawRect(x * 40, y * 40, 40, 40);
  129. }
  130.  
  131. // zeichne Prinz und Prinzessin
  132. g.drawImage(imgPrince, labyrinth.getDestinationPoint().x * 40 - 13,
  133. labyrinth.getDestinationPoint().y * 40 - 10, null);
  134. g.drawImage(imgPrincess, labyrinth.getCurrentPosition().x * 40 - 8,
  135. labyrinth.getCurrentPosition().y * 40 - 8, null);
  136. }
  137.  
  138. // wird eine Lösung gefunden ... naja
  139. if(labyrinth.getCurrentPosition().x == labyrinth.getDestinationPoint().x
  140. && labyrinth.getCurrentPosition().y == labyrinth.getDestinationPoint().y)
  141. g.drawImage(imgCensored, labyrinth.getCurrentPosition().x * 40 - 20,
  142. labyrinth.getCurrentPosition().y * 40 - 10, null);
  143. }
  144. }
  145. }


Wie kann ich den FloodFill Algorithmus zur Labyrintherzeugzung implementieren?
Angehängte Dateien


Labyrinth mittel FloodFill

0 commentaires:

Enregistrer un commentaire