Untitled
unknown
plain_text
2 years ago
5.8 kB
2
Indexable
package byow.Core; import byow.TileEngine.TERenderer; import byow.TileEngine.TETile; import byow.TileEngine.Tileset; import byow.architect.Area; import byow.architect.Hallway; import byow.architect.Room; import edu.princeton.cs.introcs.Stopwatch; import java.util.Random; /** * Primary class for random world generation. The algorithm is as follows. * First, builds a starter room. Second, builds a hallway coming out of * starter-room, then another room at the end of the first hallway. Third * randomly selects an existing room, builds a hallway out of it, and a room at * the end of the hallway. Repeats step 3 until the total number of occupied tiles * reaches LOAD_FACTOR. */ public class WorldGenerator { private static final double LOAD_FACTOR = 0.22; private static final int TIMEOUT = 2; private final int WIDTH; private final int HEIGHT; private final Random RANDOM; protected final TETile[][] WORLD; private int totalNumOfTiles; private boolean isWorldGenerated; /** * Initializes a TETile[][] board. Fills every tile with NOTHING, and then replaces tiles * with FLOOR and WALL according to the world generation algorithm. */ public WorldGenerator(int width, int height, Random random) { WIDTH = width; HEIGHT = height; RANDOM = random; WORLD = new TETile[width][height]; totalNumOfTiles = 0; isWorldGenerated = false; fillBackground(); } /** * The primary method for world generation. First, builds a starter room. Second, repeats * the following steps until the number of occupied tiles reaches LOAD_FACTOR or this * operation reaches time limit: * A. randomly choose an existing room * B. try building a hallway out of it * i. if succeeds, there's a 50% chance of choosing to try building a hallway turn * ii. if succeeds, try building a room at the end of the hallway */ protected void generateWorld() { Stopwatch sw = new Stopwatch(); buildRoom(null); while (load() < LOAD_FACTOR && sw.elapsedTime() < TIMEOUT) { int randomIndex = RANDOM.nextInt(Area.ROOMS.size()); Room room = Area.ROOMS.get(randomIndex); Hallway hallway = buildHallway(room); if (hallway != null) { hallway = buildTurn(hallway); buildRoom(hallway); } } isWorldGenerated = load() >= LOAD_FACTOR; } /** * Tries building a new room. In the case of starter room, tries for infinite times until * succeed. In the case of regular rooms, tries for 6 attempts - 6 but not less because * construction success rate can be low. */ private Room buildRoom(Hallway hallway) { if (hallway == null) { return (Room) multipleAttempts(null, hallway, Integer.MAX_VALUE); } else { return (Room) multipleAttempts(null, hallway, 6); } } /** * Tries building a new hallway within 3 attempts. */ private Hallway buildHallway(Room room) { return (Hallway) multipleAttempts(room, null, 3); } /** * Tries building an area instance within the given number of attempts. If an instance is * successfully created, increases the total number of occupied tiles. */ private Area multipleAttempts(Room room, Hallway hallway, int numAttempts) { while (numAttempts > 0) { Area area = room == null ? new Room(WORLD, hallway, RANDOM) : new Hallway(WORLD, room, RANDOM); if (area.isInstanceCreated()) { totalNumOfTiles += area.numOfTiles(); return area; } numAttempts--; } return null; } /** * There's a 50% chance of choosing to build a hallway turn (in one attempt, since * construction success rate is very high). If a valid hallway turn is built, returns it. * Otherwise, returns the original hallway. */ private Hallway buildTurn(Hallway hallway) { boolean buildTurn = RandomUtils.bernoulli(RANDOM, 0.5); if (buildTurn) { hallway = buildMultipleTurns(hallway); } return hallway; } /** * Randomly determines how many turns are to be constructed: at most 2, at least 1. If hallway * turn(s) is created, returns it, otherwise returns the original hallway. */ private Hallway buildMultipleTurns(Hallway hallway) { int numOfTurns = RANDOM.nextInt(2) + 1; for (int i = 0; i < numOfTurns; i++) { Hallway turn = Hallway.hallwayTurn(WORLD, hallway); if (turn.isInstanceCreated()) { totalNumOfTiles += turn.numOfTiles() - 1; hallway = turn; } } return hallway; } /** * Fills every tile of the world with NOTHING. */ private void fillBackground() { for (int i = 0; i < WORLD.length; i++) { for (int j = 0; j < WORLD[0].length; j++) { WORLD[i][j] = Tileset.NOTHING; } } } /** * Returns the percentage of occupied tiles against the total number of tiles. */ private double load() { return (float) totalNumOfTiles / (WIDTH * HEIGHT); } protected boolean isWorldGenerated() { return isWorldGenerated; } /** * For testing. */ public static void main(String[] args) { TERenderer teRenderer = new TERenderer(); teRenderer.initialize(80, 30); long seed = 84; Random r = new Random(seed); WorldGenerator wg = new WorldGenerator(80, 30, r); teRenderer.renderFrame(wg.WORLD); } }
Editor is loading...