Schreibe den erforderlichen Java-Code, um die folgenden Aufgaben auszuführen: Der Algorithmus zur Generierung einer Karte eines unterirdischen Dungeons basiert darauf, zufällig eine Wand und einen Raum auszuwählen, um sie dem Dungeon hinzuzufügen. Eine Tür wird dann an einer zufälligen Position an der ausgewählten Wand platziert und eine Tür wird an dem Raum platziert, die der Position der Tür an der Wand entspricht. Die beiden Räume werden dann entlang der Tür ausgerichtet, und wenn der neue Raum mit einem vorhandenen Raum überlappt, versucht der Algorithmus, den neuen Raum zu verschieben, bis er nicht mehr überlappt. Dieser Vorgang wird wiederholt, bis alle verfügbaren Räume platziert wurden oder bis der Algorithmus nach einer bestimmten Anzahl von Versuchen keinen Raum platzieren kann. Das Ergebnis ist eine zufällig generierte Karte eines unterirdischen Dungeons mit verbundenen Räumen und Türen.
Hier ist eine Beispielimplementierung des Algorithmus in Java:

```java
import java.util.*;

public class DungeonMapGenerator {

    private int dungeonWidth;
    private int dungeonHeight;
    private int maxAttempts;
    private List<Room> rooms;
    private List<Wall> walls;
    private Random rand;

    public DungeonMapGenerator(int width, int height, int attempts) {
        dungeonWidth = width;
        dungeonHeight = height;
        maxAttempts = attempts;
        rooms = new ArrayList<>();
        walls = new ArrayList<>();
        rand = new Random();
    }

    public void generate() {
        // erstelle ersten Raum
        Raum ersterRaum = new Raum(0, 0, rand.nextInt(dungeonWidth/2) + 3, rand.nextInt(dungeonHeight/2) + 3);
        rooms.add(ersterRaum);
        
        // füge Wände zur Wändeliste hinzu
        walls.addAll(ersterRaum.getWalls());

        // füge zusätzliche Räume hinzu
        int versuche = 0;
        while (versuche < maxAttempts && !walls.isEmpty()) {
            // wähle zufällige Wand und Raum zum Hinzufügen aus
            int wandIndex = rand.nextInt(walls.size());
            Wand ausgewählteWand = walls.get(wandIndex);
            Raum ausgewählterRaum = new Raum(ausgewählteWand);

            // versuche den Raum zu verschieben, wenn er mit vorhandenen Räumen überlappt
            boolean überlappung = false;
            for (Raum r : rooms) {
                if (ausgewählterRaum.überlappt(r)) {
                    überlappung = true;
                    for (int i = 0; i < 4; i++) {
                        ausgewählterRaum.verschieben(i);
                        if (!ausgewählterRaum.überlappt(r)) {
                            break;
                        }
                    }
                    if (überlappung) {
                        break;
                    }
                }
            }

            // füge Raum hinzu, wenn keine Überlappung besteht
            if (!überlappung) {
                rooms.add(ausgewählterRaum);
                walls.remove(ausgewählteWand);
                walls.addAll(ausgewählterRaum.getWalls());
                verbindeRäume(ausgewählteWand, ausgewählterRaum);
                versuche = 0;
            } else {
                versuche++;
            }
        }
    }

    private void verbindeRäume(Wand wand, Raum raum) {
        // füge Tür zu Wand und Raum hinzu
        wand.fügeTürHinzu();
        raum.fügeTürHinzu(wand.getTürPosition());

        // richte Räume entlang der Tür aus
        switch (wand.getAusrichtung()) {
            case Wand.HORIZONTAL:
                raum.setY(wand.getY() - raum.getHöhe() + 1);
                break;
            case Wand.VERTICAL:
                raum.setX(wand.getX() - raum.getBreite() + 1);
                break;
        }
    }

    private class Raum {
        private int x, y;
        private int breite, höhe;
        private List<Wand> wände;

        public Raum(int x, int y, int breite, int höhe) {
            this.x = x;
            this.y = y;
            this.breite = breite;
            this.höhe = höhe;
            wände = new ArrayList<>();
            erstelleWände();
        }

        public Raum(Wand wand) {
            switch (wand.getAusrichtung()) {
                case Wand.HORIZONTAL:
                    breite = rand.nextInt(dungeonWidth/4) + 3;
                    höhe = rand.nextInt(dungeonHeight/2) + 3;
                    x = rand.nextInt(wand.getLänge() - breite) + wand.getX();
                    y = wand.getY() - höhe + 1;
                    break;
                case Wand.VERTICAL:
                    breite = rand.nextInt(dungeonWidth/2) + 3;
                    höhe = rand.nextInt(dungeonHeight/4) + 3;
                    x = wand.getX() - breite + 1;
                    y = rand.nextInt(wand.getLänge() - höhe) + wand.getY();
                    break;
            }
            wände = new ArrayList<>();
            erstelleWände
```