write the required java code to perform the followings tasks: The algorithm for generating a map of an underground dungeon is based on randomly selecting a wall and a room to add to the dungeon. A door is then placed at a random location on the selected wall, and a door is placed on the room that matches the location of the door on the wall. The two rooms are then aligned along the door, and if the new room overlaps with an existing room, the algorithm attempts to move the new room until it no longer overlaps. This process is repeated until all available rooms have been placed, or until the algorithm fails to place a room after a certain number of attempts. The result is a randomly generated map of an underground dungeon with connected rooms and doors.
Here's an example implementation of the algorithm 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() {
        // create first room
        Room firstRoom = new Room(0, 0, rand.nextInt(dungeonWidth/2) + 3, rand.nextInt(dungeonHeight/2) + 3);
        rooms.add(firstRoom);
        
        // add walls to wall list
        walls.addAll(firstRoom.getWalls());

        // add additional rooms
        int attempts = 0;
        while (attempts < maxAttempts && !walls.isEmpty()) {
            // select random wall and room to add
            int wallIndex = rand.nextInt(walls.size());
            Wall selectedWall = walls.get(wallIndex);
            Room selectedRoom = new Room(selectedWall);

            // attempt to move room if overlapping with existing rooms
            boolean overlap = false;
            for (Room r : rooms) {
                if (selectedRoom.intersects(r)) {
                    overlap = true;
                    for (int i = 0; i < 4; i++) {
                        selectedRoom.move(i);
                        if (!selectedRoom.intersects(r)) {
                            break;
                        }
                    }
                    if (overlap) {
                        break;
                    }
                }
            }

            // add room if no overlap
            if (!overlap) {
                rooms.add(selectedRoom);
                walls.remove(selectedWall);
                walls.addAll(selectedRoom.getWalls());
                connectRooms(selectedWall, selectedRoom);
                attempts = 0;
            } else {
                attempts++;
            }
        }
    }

    private void connectRooms(Wall wall, Room room) {
        // add door to wall and room
        wall.addDoor();
        room.addDoor(wall.getDoorPosition());

        // align rooms along door
        switch (wall.getOrientation()) {
            case Wall.HORIZONTAL:
                room.setY(wall.getY() - room.getHeight() + 1);
                break;
            case Wall.VERTICAL:
                room.setX(wall.getX() - room.getWidth() + 1);
                break;
        }
    }

    private class Room {
        private int x, y;
        private int width, height;
        private List<Wall> walls;

        public Room(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            walls = new ArrayList<>();
            createWalls();
        }

        public Room(Wall wall) {
            switch (wall.getOrientation()) {
                case Wall.HORIZONTAL:
                    width = rand.nextInt(dungeonWidth/4) + 3;
                    height = rand.nextInt(dungeonHeight/2) + 3;
                    x = rand.nextInt(wall.getLength() - width) + wall.getX();
                    y = wall.getY() - height + 1;
                    break;
                case Wall.VERTICAL:
                    width = rand.nextInt(dungeonWidth/2) + 3;
                    height = rand.nextInt(dungeonHeight/4) + 3;
                    x = wall.getX() - width + 1;
                    y = rand.nextInt(wall.getLength() - height) + wall.getY();
                    break;
            }
            walls = new ArrayList<>();
            createWalls
```
Explain what does each of the classes do
Niggerr