Package squidpony.squidgrid
Class MultiSpill
java.lang.Object
squidpony.squidgrid.MultiSpill
public class MultiSpill extends Object
A randomized flood-fill implementation that can be used for level generation (e.g. filling ponds and lakes), for
gas propagation, or for all sorts of fluid-dynamics-on-the-cheap.
Created by Tommy Ettinger on 4/7/2015.
-
Field Summary
Fields Modifier and Type Field Description protected GreasedRegion
anyFreshMap
The cells that are filled by the any spiller will be true, others will be false.protected GreasedRegion
anySpillMap
The cells that are filled by the any spiller will be true, others will be false.int
filled
The amount of cells filled by this Spill, which may be less than the volume passed to start() if the boundaries are reached on all sides and the Spill has no more room to fill.int
height
Height of the map.Measurement
measurement
This affects how distance is measured on diagonal directions vs.boolean[][]
physicalMap
Stores which parts of the map are accessible (with a value of true) and which are not (with a value of false, including both walls and unreachable sections of the map).IRNG
rng
The IRNG used to decide how to randomly fill a space; can have its state set and read.short[][]
spillMap
The cells that are filled by the a spiller with index n when it reaches its volume or limits will be equal to n; others will be -1.ArrayList<ArrayList<Coord>>
spreadPattern
Each key here is an initial point for a spiller passed to start(), and each value corresponds to a list of points that the spiller will randomly fill, starting with the key, in order of when they are reached.int
width
Width of the map. -
Constructor Summary
Constructors Constructor Description MultiSpill()
Construct a Spill without a level to actually scan.MultiSpill(char[][] level)
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile.MultiSpill(char[][] level, char alternateWall)
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where one char means a wall and anything else is a walkable tile.MultiSpill(char[][] level, Measurement measurement)
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile.MultiSpill(char[][] level, Measurement measurement, IRNG random)
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile.MultiSpill(long state)
Construct a Spill without a level to actually scan.MultiSpill(short[][] level)
Used to construct a Spill from the output of another.MultiSpill(short[][] level, Measurement measurement)
Used to construct a Spill from the output of another, specifying a distance calculation.MultiSpill(short[][] level, Measurement measurement, IRNG random)
Used to construct a Spill from the output of another, specifying a distance calculation and RNG.MultiSpill(IRNG random)
Construct a Spill without a level to actually scan.MultiSpill(IStatefulRNG random)
Construct a Spill without a level to actually scan. -
Method Summary
Modifier and Type Method Description MultiSpill
initialize(char[][] level)
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently (not if a creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ).MultiSpill
initialize(char[][] level, char alternateWall)
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently (not if a creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ).MultiSpill
initialize(short[][] level)
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently.void
reset()
Resets this Spill to a state with an empty spillMap and an empty spreadPattern.void
resetCell(int x, int y)
Reverts a cell to an unfilled state (false in spillMap).void
resetCell(Coord pt)
Reverts a cell to an unfilled state (false in spillMap).void
resetMap()
Resets the spillMap to being empty.protected void
setFresh(int idx, int x, int y)
protected void
setFresh(int idx, Coord pt)
ArrayList<ArrayList<Coord>>
start(List<Coord> entries, int volume, Collection<Coord> impassable)
Recalculate the spillMap and return the spreadPattern.ArrayList<ArrayList<Coord>>
start(OrderedMap<Coord,Double> entries, int volume, Collection<Coord> impassable)
Recalculate the spillMap and return the spreadPattern.
-
Field Details
-
measurement
This affects how distance is measured on diagonal directions vs. orthogonal directions. MANHATTAN should form a diamond shape on a featureless map, while CHEBYSHEV and EUCLIDEAN will form a square. If you only call Spill.start() once, you should strongly prefer MANHATTAN, even if the rest of the game uses another measurement, because CHEBYSHEV and EUCLIDEAN can produce odd, gap-filled flood-fills. Any case where you have too many gaps can be corrected to varying extent by calling start() more than once with slowly increasing values. Because start() will extend from the existing area of the Spill, holes are likely to be filled after a few calls, but if the last call to start() tries to fill too many more cells than the previous one, it can cause holes on the periphery of the Spill area. -
physicalMap
Stores which parts of the map are accessible (with a value of true) and which are not (with a value of false, including both walls and unreachable sections of the map). Should not be changed unless the actual physical terrain has changed. You should call initialize() with a new map instead of changing this directly. -
spillMap
The cells that are filled by the a spiller with index n when it reaches its volume or limits will be equal to n; others will be -1. -
anySpillMap
The cells that are filled by the any spiller will be true, others will be false. -
anyFreshMap
The cells that are filled by the any spiller will be true, others will be false. -
spreadPattern
Each key here is an initial point for a spiller passed to start(), and each value corresponds to a list of points that the spiller will randomly fill, starting with the key, in order of when they are reached. -
height
Height of the map. Exciting stuff. Don't change this, instead call initialize(). -
width
Width of the map. Exciting stuff. Don't change this, instead call initialize(). -
filled
The amount of cells filled by this Spill, which may be less than the volume passed to start() if the boundaries are reached on all sides and the Spill has no more room to fill. -
rng
The IRNG used to decide how to randomly fill a space; can have its state set and read.
-
-
Constructor Details
-
MultiSpill
public MultiSpill()Construct a Spill without a level to actually scan. If you use this constructor, you must call an initialize() method before using this class. -
MultiSpill
Construct a Spill without a level to actually scan. This constructor allows you to specify an RNG, but the actual RandomnessSource the RNG that this object uses will not be identical to the one passed as random (64 bits will be requested from the passed RNG, and that will be used to seed this class' RNG). If you use this constructor, you must call an initialize() method before using this class.- Parameters:
random
- an RNG that will be converted to a StatefulRNG if it is not one already
-
MultiSpill
Construct a Spill without a level to actually scan. This constructor allows you to specify the state to be used for the RNG without actually passing an RNG, since this will use its own anyway. If you use this constructor, you must call an initialize() method before using this class.- Parameters:
state
- the state to use for this class' random number generator
-
MultiSpill
Construct a Spill without a level to actually scan. This constructor allows you to specify an IStatefulRNG that will be used exactly, without copying the generator. This permits usingGWTRNG
instead of the defaultStatefulRNG
if optimal performance on GWT is desirable at the expense of some performance on desktop. If you use this constructor, you must call an initialize() method before using this class.- Parameters:
random
- an IStatefulRNG that will be used exactly, without copying
-
MultiSpill
Used to construct a Spill from the output of another.- Parameters:
level
- a short[][] that should have been the spillMap of another MultiSpill
-
MultiSpill
Used to construct a Spill from the output of another, specifying a distance calculation.- Parameters:
level
- a short[][] that should have been the spillMap of another MultiSpillmeasurement
- a Spill.Measurement that should usually be MANHATTAN
-
MultiSpill
Used to construct a Spill from the output of another, specifying a distance calculation and RNG.
This constructor allows you to specify an RNG, but the actual RandomnessSource the RNG that this object uses will not be identical to the one passed as random (64 bits will be requested from the passed RNG, and that will be used to seed this class' RNG).- Parameters:
level
- a short[][] that should have been the spillMap of another MultiSpillmeasurement
- a Spill.Measurement that should usually be MANHATTAN
-
MultiSpill
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile. If you only have a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a map that can be used here.- Parameters:
level
- a char[][] that should use '#' for walls and '.' for floors
-
MultiSpill
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where one char means a wall and anything else is a walkable tile. If you only have a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a map that can be used here. You can specify the character used for walls.- Parameters:
level
- a char[][] that should use alternateWall for walls and '.' for floorsalternateWall
- the char to use for walls
-
MultiSpill
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile. If you only have a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a map that can be used here. This constructor specifies a distance measurement.- Parameters:
level
- a char[][] that should use '#' for walls and '.' for floorsmeasurement
- a Spill.Measurement that should usually be MANHATTAN
-
MultiSpill
Constructor meant to take a char[][] returned by DungeonBoneGen.generate(), or any other char[][] where '#' means a wall and anything else is a walkable tile. If you only have a map that uses box-drawing characters, use DungeonUtility.linesToHashes() to get a map that can be used here. This constructor specifies a distance measurement.
This constructor allows you to specify an RNG, but the actual RandomnessSource the RNG that this object uses will not be identical to the one passed as random (64 bits will be requested from the passed RNG, and that will be used to seed this class' RNG).- Parameters:
level
- a char[][] that should use '#' for walls and '.' for floorsmeasurement
- a Spill.Measurement that should usually be MANHATTANrandom
- an RNG that will be converted to a StatefulRNG if it is not one already
-
-
Method Details
-
initialize
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently.- Parameters:
level
- a short[][] that should have been the spillMap of another MultiSpill- Returns:
- this for chaining
-
initialize
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently (not if a creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ).- Parameters:
level
- a char[][] that should use '#' for walls and '.' for floors- Returns:
- this for chaining
-
initialize
Used to initialize or re-initialize a Spill that needs a new PhysicalMap because it either wasn't given one when it was constructed, or because the contents of the terrain have changed permanently (not if a creature moved; for that you pass the positions of creatures that block paths to scan() or findPath() ). This initialize() method allows you to specify an alternate wall char other than the default character, '#' .- Parameters:
level
- a char[][] that should use alternateWall for walls and '.' for floorsalternateWall
- the char to use for walls- Returns:
- this for chaining
-
resetMap
Resets the spillMap to being empty. -
reset
Resets this Spill to a state with an empty spillMap and an empty spreadPattern. -
resetCell
Reverts a cell to an unfilled state (false in spillMap).- Parameters:
x
- the x-component of the Coord to revert to an unfilled statey
- the y-component of the Coord to revert to an unfilled state
-
resetCell
Reverts a cell to an unfilled state (false in spillMap).- Parameters:
pt
- the Coord to revert to an unfilled state
-
setFresh
-
setFresh
-
start
public ArrayList<ArrayList<Coord>> start(List<Coord> entries, int volume, Collection<Coord> impassable)Recalculate the spillMap and return the spreadPattern. The cell corresponding to a Coord in entries will be true, the cells near each of those will be true if chosen at random from all passable cells adjacent to a filled (true) cell, and all other cells will be false. This takes a total number of cells to attempt to fill (the volume parameter), which can be negative to simply fill the whole map, and will fill less if it has completely exhausted all passable cells from all sources in entries. If the measurement this Spill uses is anything other than MANHATTAN, you can expect many gaps in the first filled area. Subsequent calls to start() with the same entry and a higher volume will expand the area of the Spill, and are likely to fill any gaps after a few subsequent calls. Increasing the volume slowly is the best way to ensure that gaps only exist on the very edge if you use a non-MANHATTAN measurement.- Parameters:
entries
- the first cell for each spiller to spread from, which should really be passable.volume
- the total number of cells to attempt to fill; if negative will fill the whole map.impassable
- a Collection, ideally a Set or GreasedRegion, holding Coord items representing the locations of moving obstacles to a fill that cannot be moved through; null means no obstacles exist.- Returns:
- an ArrayList of Points that this will enter, in order starting with entry at index 0, until it reaches its volume or fills its boundaries completely.
-
start
public ArrayList<ArrayList<Coord>> start(OrderedMap<Coord,Double> entries, int volume, Collection<Coord> impassable)Recalculate the spillMap and return the spreadPattern. The cell corresponding to a key in entries will be true, the cells near each of those will be true if chosen at random from all passable cells adjacent to a filled (true) cell, and all other cells will be false. This takes a total number of cells to attempt to fill (the volume parameter), which can be negative to simply fill the whole map, and will fill less if it has completely exhausted all passable cells from all sources in entries. It uses the values in entries to determine whether it should advance from a particular key in that step or not; this choice is pseudo-random. If you have some values that are at or near 1.0 and some values that are closer to 0.0, you should expect the keys for the higher values to spread further out than the keys associated with lower values.
If the measurement this Spill uses is anything other than MANHATTAN, you can expect many gaps in the first filled area. Subsequent calls to start() with the same entry and a higher volume will expand the area of the Spill, and are likely to fill any gaps after a few subsequent calls. Increasing the volume slowly is the best way to ensure that gaps only exist on the very edge if you use a non-MANHATTAN measurement.
The intended purpose for this method is filling contiguous areas of dungeon with certain terrain features, but it has plenty of other uses as well.- Parameters:
entries
- key: the first cell for each spiller to spread from. value: the bias toward advancing this key; 1.0 will always advance, 0.0 will never advance beyond the key, in between will randomly choosevolume
- the total number of cells to attempt to fill; if negative will fill the whole map.impassable
- a Collection, ideally a Set or GreasedRegion, holding Coord items representing the locations of moving obstacles to a fill that cannot be moved through; null means no obstacles exist.- Returns:
- an ArrayList of Points that this will enter, in order starting with entry at index 0, until it reaches its volume or fills its boundaries completely.
-