package squidpony.squidgrid.mapping; import squidpony.ArrayTools; import squidpony.squidmath.RNG; /** * Meant to produce the sort of narrow, looping, not-quite-maze-like passages found in a certain famous early arcade game. * Created by Tommy Ettinger on 3/30/2016. */ public class PacMazeGenerator { public RNG rng; public int width, height; private boolean[][] map; private int[][] env; private char[][] maze; public PacMazeGenerator() { this(250, 250); } public PacMazeGenerator(int width, int height) { this.height = height; this.width = width; rng = new RNG(); } public PacMazeGenerator(int width, int height, RNG rng) { this.height = height; this.width = width; this.rng = rng; } private static final byte[] //unbiased_connections = new byte[]{3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}, connections = new byte[]{ 3, 5, 6, 9, 10, 12,/* 3, 5, 6, 9, 10, 12, 3, 5, 6, 9, 10, 12, 3, 5, 6, 9, 10, 12, 7, 11, 13, 14, 7, 11, 13, 14, 15*/ }; private static final int connections_length = connections.length; private boolean write(boolean[][] m, int x, int y, int xOffset, int yOffset, boolean value) { int nx = x * 3 + xOffset + 1, ny = y * 3 + yOffset + 1; if(nx >= 0 && nx < m.length && ny >= 0 && ny < m[nx].length) { m[nx][ny] = value; return true; } return false; } public boolean[][] create() { map = new boolean[width][height]; byte[][] conns = new byte[(width+2) / 3][(height+2) / 3]; int xOff = (width % 3 == 1) ? -1 : 0, yOff = (height % 3 == 1) ? -1 : 0; for (int x = 0; x < (width+2) / 3; x++) { for (int y = 0; y < (height+2) / 3; y++) { conns[x][y] = connections[rng.nextInt(connections_length)]; } } for (int x = 0; x < (width+2) / 3; x++) { for (int y = 0; y < (height+2) / 3; y++) { write(map, x, y, xOff, yOff, true); if(x > 0 && ((conns[x - 1][y] & 1) != 0 || (conns[x][y] & 2) != 0)) { conns[x - 1][y] |= 1; conns[x][y] |= 2; } if(x < conns.length - 1 && ((conns[x + 1][y] & 2) != 0 || (conns[x][y] & 1) != 0)) { conns[x + 1][y] |= 2; conns[x][y] |= 1; } if(y > 0 && ((conns[x][y - 1] & 4) != 0 || (conns[x][y] & 8) != 0)) { conns[x][y - 1] |= 4; conns[x][y] |= 8; } if(y < conns[0].length - 1 && ((conns[x][y + 1] & 8) != 0 || (conns[x][y] & 4) != 0)) { conns[x][y + 1] |= 8; conns[x][y] |= 4; } } } for (int x = 1; x < (width-1) / 3; x++) { for (int y = 1; y < (height-1) / 3; y++) { if (Integer.bitCount(conns[x][y]) >= 4) { //byte temp = connections[rng.nextInt(connections_length)]; int temp = 1 << rng.nextInt(4); conns[x][y] ^= temp; if((temp & 2) != 0) conns[x - 1][y] ^= 1; else if((temp & 1) != 0) conns[x + 1][y] ^= 2; else if((temp & 8) != 0) conns[x][y - 1] ^= 4; else if((temp & 4) != 0) conns[x][y + 1] ^= 8; } } } for (int x = 0; x < (width+2) / 3; x++) { for (int y = 0; y < (height+2) / 3; y++) { write(map, x, y, xOff, yOff, true); if(x > 0 && (conns[x][y] & 2) != 0) write(map, x, y, xOff - 1, yOff, true); if(x < conns.length - 1 && (conns[x][y] & 1) != 0) write(map, x, y, xOff + 1, yOff, true); if(y > 0 && (conns[x][y] & 8) != 0) write(map, x, y, xOff, yOff - 1, true); if(y < conns[0].length - 1 && (conns[x][y] & 4) != 0) write(map, x, y, xOff, yOff + 1, true); } } int upperY = height - 1; int upperX = width - 1; for (int i = 0; i < width; i++) { map[i][0] = false; map[i][upperY] = false; } for (int i = 0; i < height; i++) { map[0][i] = false; map[upperX][i] = false; } return map; } public char[][] generate() { create(); maze = new char[width][height]; env = new int[width][height]; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { maze[x][y] = map[x][y] ? '.' : '#'; env[x][y] = map[x][y] ? MixedGenerator.CORRIDOR_FLOOR : MixedGenerator.CORRIDOR_WALL; } } return maze; } public int[][] getEnvironment() { if(env == null) return ArrayTools.fill(MixedGenerator.CORRIDOR_WALL, width, height); return env; } /** * Gets the maze as a 2D array of true for passable or false for blocked. * @return a 2D boolean array; true is passable and false is not. */ public boolean[][] getMap() { if(map == null) return new boolean[width][height]; return map; } /** * Gets the maze as a 2D array of ',' for passable or '#' for blocked. * @return a 2D boolean array; '.' is passable and '#' is not. */ public char[][] getMaze() { if(maze == null) return ArrayTools.fill('#', width, height); return maze; } }