package Roguelike.DungeonGeneration.RoomGenerators; import java.util.Random; import Roguelike.DungeonGeneration.DungeonFileParser; import Roguelike.DungeonGeneration.Symbol; import com.badlogic.gdx.utils.XmlReader.Element; public class CellularAutomata extends AbstractRoomGenerator { private static final int GRID_WALL = 0; private static final int GRID_FLOOR = 1; public int[][] joinRegions( int[][] igrid, int[][] igrid2 ) { for ( int x = 0; x < igrid.length; x++ ) { for ( int y = 0; y < igrid[0].length; y++ ) { igrid[x][y] = igrid[x][y] == 1 || igrid2[x][y] == 1 ? 1 : 0; } } return igrid; } /* * This builds a cave-like region using cellular automata identical to that * outlined in the algorithm at * http://roguebasin.roguelikedevelopment.org/index * .php?title=Cellular_Automata_Method_for_Generating_Random_Cave * -Like_Levels * * The floor and wall grid define which features are generated. Wall_prob * defines the chance of being initialised as a wall grid. * * R1 defines the minimum number of walls that must be within 1 grid to make * the new grid a wall R2 defines the maximum number of walls that must be * within 2 grids to make the new grid a wall else the new grid is a floor * gen gives the number of generations. gen2 gives the number of generations * from which the r2 parameter is ignored * * Examples given in the article are: wall_prob = 45, r1 = 5, r2 = N/A, gen * = 5, gen2 = 0 wall_prob = 45, r1 = 5, r2 = 0, gen = 5, gen2 = 5 wall_prob * = 40, r1 = 5, r2 = 2, gen = 7, gen2 = 4 * * We can define a combination of wall, floor and edge to allow e.g. a * series of islands rising out of lava or some other mix of terrain. */ @Override public void process( Symbol[][] grid, Symbol floor, Symbol wall, Random ran, DungeonFileParser dfp ) { int wall_prob = ran.nextInt( 5 ) + 40; int r1 = 5; int r2 = ran.nextInt( 2 ); int gen = ran.nextInt( 2 ) + 5; int gen2 = ran.nextInt( 5 ); int xi, yi; int size_y = grid[0].length; int size_x = grid.length; int ii, jj; int[][] igrid = new int[size_y][size_x]; int[][] igrid2 = new int[size_y][size_x]; /* Initialise the starting grids randomly */ for ( yi = 1; yi < size_y - 1; yi++ ) { for ( xi = 1; xi < size_x - 1; xi++ ) { igrid[yi][xi] = ran.nextInt( 100 ) < wall_prob ? GRID_WALL : GRID_FLOOR; } } /* Initialise the destination grids - for paranoia */ for ( yi = 0; yi < size_y; yi++ ) { for ( xi = 0; xi < size_x; xi++ ) { igrid2[yi][xi] = GRID_WALL; } } /* Surround the starting grids in walls */ for ( yi = 0; yi < size_y; yi++ ) { igrid[yi][0] = igrid[yi][size_x - 1] = GRID_WALL; } for ( xi = 0; xi < size_x; xi++ ) { igrid[0][xi] = igrid[size_y - 1][xi] = GRID_WALL; } /* Run through generations */ for ( ; gen > 0; gen--, gen2-- ) { for ( yi = 1; yi < size_y - 1; yi++ ) { for ( xi = 1; xi < size_x - 1; xi++ ) { int adjcount_r1 = 0, adjcount_r2 = 0; // Count adjacent for ( ii = -1; ii <= 1; ii++ ) { for ( jj = -1; jj <= 1; jj++ ) { if ( igrid[yi + ii][xi + jj] != GRID_FLOOR ) { adjcount_r1++; } } } for ( ii = yi - 2; ii <= yi + 2; ii++ ) { for ( jj = xi - 2; jj <= xi + 2; jj++ ) { if ( Math.abs( ii - yi ) == 2 && Math.abs( jj - xi ) == 2 ) { continue; } if ( ii < 0 || jj < 0 || ii >= size_y || jj >= size_x ) { continue; } if ( igrid[ii][jj] != GRID_FLOOR ) { adjcount_r2++; } } } if ( adjcount_r1 >= r1 || ( ( gen2 > 0 ) && ( adjcount_r2 <= r2 ) ) ) { igrid2[yi][xi] = GRID_WALL; } else { igrid2[yi][xi] = GRID_FLOOR; } } } for ( yi = 1; yi < size_y - 1; yi++ ) { for ( xi = 1; xi < size_x - 1; xi++ ) { igrid[yi][xi] = igrid2[yi][xi]; } } } igrid = joinRegions( igrid, igrid2 ); /* Write final grids out to map */ for ( yi = 0; yi < size_y; yi++ ) { for ( xi = 0; xi < size_x; xi++ ) { if ( igrid[yi][xi] == GRID_FLOOR ) { grid[xi][yi] = floor; } else { grid[xi][yi] = wall; } } } } @Override public void parse( Element xml ) { } }