/** * Like {@link #retract8way()}, this reduces the width of thick areas of this GreasedRegion, but thin8way() will not * remove areas that would be identical in a subsequent call to retract8way(), such as if the area would be * eliminated. This is useful primarily for adjusting areas so they do not exceed a width of 2 cells, though their * length (the longer of the two dimensions) will be unaffected by this. Especially wide, irregularly-shaped areas * may have unintended appearances if you call this repeatedly or use {@link #thinFully8way()}; consider using this * sparingly, or primarily when an area has just gotten thicker than desired. * <br> * This method was called {@link #thin()}, but now that name refers to a variant that uses 4-way adjacency. * @return this for chaining */ public GreasedRegion thin8way() { if(width <= 2 || ySections <= 0) return this; GreasedRegion c1 = new GreasedRegion(this).retract8way(), c2 = new GreasedRegion(c1).expand8way().xor(this).expand8way().and(this); remake(c1).or(c2); return this; }
@Override public boolean retainAll(Collection<?> c) { GreasedRegion g2 = new GreasedRegion(width, height); for(Object o : c) { if(contains(o) && o instanceof Coord) { g2.add((Coord)o); } } boolean changed = equals(g2); remake(g2); return changed; }
|| xPos + w * 2 >= changing.length || yPos + h >= changing[0].length) return changing; randomRegion.refill(randomness, 0.75, w, h); workingSolid.remake(potentialSolid); workingBody.remake(potentialBody).or(potentialSolid).andNot(alwaysSolid).and(randomRegion); workingSolid.andNot(workingBody).or(randomRegion.remake(workingBody).fringe()); workingShade.remake(workingBody).neighborDown().not().and(workingBody); workingShine.remake(workingBody).neighborUp().not().and(workingBody).andNot(workingShade); workingBody.andNot(workingShade).andNot(workingShine); for (int x = 0, o = w*2-1; x < w; x++, o--) { for (int y = 0; y < h; y++) {
public GreasedRegion fringe8way() { GreasedRegion cpy = new GreasedRegion(this); expand8way(); return andNot(cpy); } public GreasedRegion fringe8way(int amount)
public GreasedRegion[] expandSeries8way(int amount) { if(amount <= 0) return new GreasedRegion[0]; GreasedRegion[] regions = new GreasedRegion[amount]; GreasedRegion temp = new GreasedRegion(this); for (int i = 0; i < amount; i++) { regions[i] = new GreasedRegion(temp.expand8way()); } return regions; } public ArrayList<GreasedRegion> expandSeriesToLimit8way()
GreasedRegion bounds = new GreasedRegion(width, height).not().retract(5), smallerBounds = bounds.copy().retract(5), area = new GreasedRegion(width, height), tmpEdge = new GreasedRegion(width, height), tmpInner = new GreasedRegion(width, height), tmpOOB = new GreasedRegion(width, height); Coord[] pts = smallerBounds.randomPortion(rng, rng.between(24, 48)); waterStrength = Math.max(0.0, waterStrength); int aLen = pts.length; for (int i = 0; i < aLen; i++) { int volume = 10 + (height * width) / (aLen * 2); area.empty().insert(pts[i]).spill(bounds, volume, rng).expand(3); tmpInner.remake(area).retract(4).expand8way().and(area); tmpEdge.remake(area).surface8way(); Coord[] edges = tmpEdge.mixedRandomSeparated(0.35); int eLen = edges.length; Double[] powers = new Double[eLen]; eLen = entries.size(); for (int j = 0; j < 32; j++) { entries.put(tmpInner.singleRandom(rng), (rng.nextDouble() + 1.5) * 0.4); tmpOOB.remake(area).not(); GreasedRegion map = new GreasedRegion(sm, 0, 0x7fff); Coord[] centers = map.mixedRandomSeparated(0.1, factionCount, rng.nextLong()); int controlled = (int) (map.size() * Math.max(0.0, Math.min(1.0, controlledFraction))); GreasedRegion m2 = new GreasedRegion(map), g2; map.retract(1);
Coord[] boulders = new GreasedRegion(map, '.').retract8way(1).randomPortion(rng, boulderFill); Coord t; for (int i = 0; i < boulders.length; i++) { GreasedRegion floors = new GreasedRegion(map, '.'), working = new GreasedRegion(width, height); floorCount = floors.size(); float waterRate = waterFill / 100.0f, grassRate = grassFill / 100.0f; if(waterRate + grassRate > 1.0f) int remainingWater = targetWater, remainingGrass = targetGrass; if(targetWater > 0) { scatter = floors.quasiRandomSeparated(1.0 / 7.0); rng.shuffleInPlace(scatter); GreasedRegion allWater = new GreasedRegion(width, height); for (int i = 0; i < scatter.length; i++) { if (remainingWater > 5) if(!floors.contains(scatter[i])) continue; working.empty().insert(scatter[i]).spill(floors, rng.between(4, Math.min(remainingWater, sizeWaterPools)), rng); floors.andNot(working); remainingWater -= working.size(); allWater.addAll(working); } else break; scatter = floors.quasiRandomSeparated(1.03/6.7); rng.shuffleInPlace(scatter);
GreasedRegion limit = new GreasedRegion(width, height).insertRectangle(1, 1, width - 2, height - 2), potential = new GreasedRegion(fusedMap, '#').and(limit), flooded, chosen, tmp = new GreasedRegion(width, height); int ctr = potential.size(), potentialMazeSize = ctr * mazeFill / 100, potentialLakeSize = ctr * lakeFill / 100; ArrayList<GreasedRegion> viable; int minSize; boolean[][] deep; if(potentialMazeSize > 0) { viable = potential.split(); if (viable.isEmpty()) return maps; minSize = chosen.size(); for (GreasedRegion sa : viable) { int sz = sa.size(); if (sz > minSize) { chosen = sa; center = chosen.singleRandom(rng); flooded = new GreasedRegion(center, width, height).spill(chosen, potentialMazeSize, rng).and(limit); GreasedRegion pacEnv = new GreasedRegion(pacMap, '.').and(flooded).removeIsolated(); deep = pacEnv.decode(); finder.allCorridors.or(pacEnv); finder.allFloors.or(pacEnv); potential.andNot(flooded); viable = potential.split();
int stx = Math.min(Math.max((wmg.zoomStartX - (width >> 1)) / ((2 << wmg.zoom) - 2), 0), width ), sty = Math.min(Math.max((wmg.zoomStartY - (height >> 1)) / ((2 << wmg.zoom) - 2), 0), height); GreasedRegion nation = new GreasedRegion(wmg.landData); GreasedRegion fillable = new GreasedRegion(politicalMap, '~').not(); for (int i = 0; i < wmg.zoom; i++) { fillable.zoom(stx, sty); fillable.flood(nation, width + height); for (int i = 1; i < atlas.size(); i++) { nation.refill(politicalMap, c = atlas.keyAt(i)); if(nation.isEmpty()) continue; for (int z = 0; z < wmg.zoom; z++) { nation.zoom(stx, sty).expand8way().expand().fray(0.5); fillable.andNot(nation); nation.intoChars(zoomedMap, c); nation.refill(zoomedMap, c = atlas.keyAt(i)); if(nation.isEmpty()) continue; nation.flood(fillable, 4 << wmg.zoom).intoChars(zoomedMap, c); nation.refill(wmg.heightCodeData, 4, 999).and(new GreasedRegion(zoomedMap, ' ')).intoChars(zoomedMap, '%'); nation.refill(wmg.heightCodeData, -999, 4).intoChars(zoomedMap, '~'); return zoomedMap;
/** * Reduces the sharpness of corners by only considering a cell on if the previous version has 5 of the 9 cells in * the containing 3x3 area as "on." Typically, this method is run repeatedly. It does not return itself for * chaining, because it returns a direct reference to the {@link #current} GreasedRegion that this will use for * any future calls to this, and changes to current will be used here. * @return a direct reference to the changed GreasedRegion this considers its main state, {@link #current} */ public GreasedRegion runBasicSmoothing() { neighbors[0].remake(current).neighborUp(); neighbors[1].remake(current).neighborDown(); neighbors[2].remake(current).neighborLeft(); neighbors[3].remake(current).neighborRight(); neighbors[4].remake(current).neighborUpLeft(); neighbors[5].remake(current).neighborUpRight(); neighbors[6].remake(current).neighborDownLeft(); neighbors[7].remake(current).neighborDownRight(); neighbors[8].remake(current); ArrayTools.fill(sums, 0); GreasedRegion.sumInto(sums, neighbors); return current.refill(sums, 5, 10); }
caves = new OrderedMap<>(8); basic = DungeonUtility.simplifyDungeon(map); allFloors = new GreasedRegion(basic, '.'); allRooms = allFloors.copy().retract8way().flood(allFloors, 2); allCorridors = allFloors.copy().andNot(allRooms); environment = allCorridors.writeInts( allRooms.writeInts(environment, DungeonUtility.ROOM_FLOOR), DungeonUtility.CORRIDOR_FLOOR); allCaves = new GreasedRegion(width, height); GreasedRegion d = allCorridors.copy().fringe().and(allRooms); connections = doorways = d.asCoords(); mouths = new Coord[0]; List<GreasedRegion> rs = allRooms.split(), cs = allCorridors.split(); GreasedRegion someDoors = sep.copy().fringe().and(allRooms); Coord[] doors = someDoors.asCoords(); List<GreasedRegion> near = new ArrayList<>(4); for (int i = 0; i < doors.length; i++) { near.addAll(GreasedRegion.whichContain(doors[i].x, doors[i].y, rs)); GreasedRegion aroundDoors = sep.copy().fringe().and(allCorridors); Coord[] doors = aroundDoors.asCoords(); List<GreasedRegion> near = new ArrayList<>(10); for (int i = 0; i < doors.length; i++) { near.addAll(GreasedRegion.whichContain(doors[i].x, doors[i].y, cs));
coolingModifier = (coolMod <= 0) ? rng.nextDouble(0.45) * (rng.nextDouble()-0.5) + 1.1 : coolMod; earth.remake(earthOriginal); sty = Math.min(Math.max((zoomStartY - (height >> 1)) / ((2 << zoom) - 2), 0), height); for (int z = 0; z < zoom; z++) { earth.zoom(stx, sty).expand8way().fray(0.5).expand(); coast.remake(earth).not().fringe(2 << zoom).expand().fray(0.5); shallow.remake(earth).fringe(2 << zoom).expand().fray(0.5); coast.remake(earth).not().fringe(2); shallow.remake(earth).fringe(2); if(earth.contains(x, y)) if(coast.contains(x, y)) h += 0.05; else terrain.getNoiseWithSeed(xPos, yPos, seedB - seedA) * 0.5, yPos, seedA)) * -0.9; if(shallow.contains(x, y)) h = (h - 0.08) * 0.375; else landData.refill(heightCodeData, 4, 999);
remakeEnvironment = true; gen.generate(type, width, height); ArrayList<GreasedRegion> rooms = gen.region.copy().retract8way().flood8way(gen.region, 1).split(); ca.remake(gen.region); gen.region.and(ca.runBasicSmoothing()).deteriorate(rng, 0.9); gen.region.and(ca.runBasicSmoothing()).deteriorate(rng, 0.9); ca.current.remake(gen.region.deteriorate(rng, 0.9)); gen.region.or(ca.runBasicSmoothing()); for (int i = 0; i < rooms.size(); i++) { if(rng.nextDouble() < roomChance) gen.region.andNot(rooms.get(i).fringe8way().deteriorate(rng, 0.81)); gen.region.remake(gen.region.removeEdges()); gen.region.insertSeveral(DungeonUtility.ensurePath(gen.region.intoChars(gen.getDungeon(), '.', '#'), rng, '.', '#')); gen.region = gen.region.largestPart(); return gen.region.intoChars(gen.getDungeon(), '.', '#');
GreasedRegion sampled = new GreasedRegion(width, height).allOn().removeEdges(); sampled.remake(sampled.copy().randomScatter(rng, 6).or(sampled.randomScatter(rng,8))); for(Coord hole : new GreasedRegion(map, '.').fringe().removeEdges().mixedRandomSeparated(0.25, -1, rng.nextLong())) { if (((map[hole.x - 1][hole.y] == '.' && map[hole.x + 1][hole.y] == '.') || (map[hole.x][hole.y - 1] == '.' && map[hole.x][hole.y + 1] == '.'))) {
caves = new OrderedMap<>(32); basic = DungeonUtility.simplifyDungeon(map); allFloors = new GreasedRegion(basic, '.'); allRooms = new GreasedRegion(environment, DungeonUtility.ROOM_FLOOR); allCorridors = new GreasedRegion(environment, DungeonUtility.CORRIDOR_FLOOR); allCaves = new GreasedRegion(environment, DungeonUtility.CAVE_FLOOR); GreasedRegion d = allCorridors.copy().fringe().and(allRooms), m = allCaves.copy().fringe().and(allRooms.copy().or(allCorridors)); doorways = d.asCoords(); mouths = m.asCoords(); connections = new Coord[doorways.length + mouths.length]; System.arraycopy(doorways, 0, connections, 0, doorways.length); System.arraycopy(mouths, 0, connections, doorways.length, mouths.length); List<GreasedRegion> rs = allRooms.split(), cs = allCorridors.split(), vs = allCaves.split(); GreasedRegion someDoors = sep.copy().fringe().and(allRooms); Coord[] doors = someDoors.asCoords(); List<GreasedRegion> near = new ArrayList<>(16); for (int i = 0; i < doors.length; i++) { near.addAll(GreasedRegion.whichContain(doors[i].x, doors[i].y, rs)); someDoors.remake(sep).fringe().and(allCaves); doors = someDoors.asCoords(); for (int i = 0; i < doors.length; i++) { near.addAll(GreasedRegion.whichContain(doors[i].x, doors[i].y, vs)); GreasedRegion aroundDoors = sep.copy().fringe().and(allCorridors); Coord[] doors = aroundDoors.asCoords();
width = wmg.width; height = wmg.height; GreasedRegion land = new GreasedRegion(wmg.heightCodeData, 4, 999); politicalMap = land.toChars('%', '~'); int controlled = (int) (land.size() * Math.max(0.0, Math.min(1.0, controlledFraction))); int[] centers = land.copy().randomScatter(rng, (int) (Math.sqrt(width * height) * 0.1 + 0.999), factionCount).asTightEncoded(); int cen, cx, cy, cx2, cy2, biome, high, hot, moist, count = centers.length, re; String biomeName; GreasedRegion anySpillMap = new GreasedRegion(width, height), anyFreshMap = new GreasedRegion(width, height); anySpillMap.insert(cx, cy); if (cx == cx2 && cy == cy2) continue; if (land.contains(cx2, cy2) && !anySpillMap.contains(cx2, cy2)) { if(!anyFreshMap.contains(cx2, cy2)) { currentFresh.add(cx2 + cy2 * width); anyFreshMap.insert(cx2, cy2); anyFreshMap.remove(cx, cy);
public GreasedRegion removeIsolated() { int fst = firstTight(); GreasedRegion remaining = new GreasedRegion(this), filled = new GreasedRegion(this); while (fst >= 0) { filled.empty().insert(fst).flood(remaining, 8); if(filled.size() <= 4) andNot(filled); remaining.andNot(filled); fst = remaining.firstTight(); } return this; }
int current = size(); if(current >= volume) return this; GreasedRegion t = new GreasedRegion(this).notAnd(bounds); long[] b2 = new long[t.data.length]; System.arraycopy(t.data, 0, b2, 0, b2.length); t.remake(this).fringe().and(bounds).tally(); if(t.ct <= 0) return this; int x, y, p; for (int i = current; i < volume; i++) { c = t.singleRandom(rng); x = c.x; y = c.y; t.tally(); if(t.ct <= 0) break;
/** * Like {@link #retract()}, this reduces the width of thick areas of this GreasedRegion, but thin() will not remove * areas that would be identical in a subsequent call to retract(), such as if the area would be eliminated. This * is useful primarily for adjusting areas so they do not exceed a width of 2 cells, though their length (the longer * of the two dimensions) will be unaffected by this. Especially wide, irregularly-shaped areas may have unintended * appearances if you call this repeatedly or use {@link #thinFully()}; consider using this sparingly, or primarily * when an area has just gotten thicker than desired. * <br> * This currently uses 4-way adjacency, but had previously used 8-way; if you want the behavior this previously had, * you can use {@link #thin8way()}, but it may be a good idea to try this method as well (some of the old behavior * had problems where it yielded significantly larger minimum widths in some areas). * @return this for chaining */ public GreasedRegion thin() { if(width <= 2 || ySections <= 0) return this; GreasedRegion c1 = new GreasedRegion(this).retract(), c2 = new GreasedRegion(c1).expand().xor(this).expand().and(this); remake(c1).or(c2); /* System.out.println("\n\nc1:\n" + c1.toString() + "\n"); System.out.println("\n\nc2:\n" + c2.toString() + "\n"); System.out.println("\n\nthis:\n" + toString() + "\n"); */ return this; }