impl sinkholes

This commit is contained in:
Tangent 2024-01-13 14:54:25 -05:00
parent d44076b32c
commit dc8fc5ef87
3 changed files with 85 additions and 7 deletions

View file

@ -168,6 +168,50 @@ export const NO_ISLAND: LobeGeneratorConstructor =
return true; return true;
}; };
const SINKHOLE_BURNOUT = 1500;
/** carve out elevation */
export const SINKHOLE: LobeGeneratorConstructor = (
islands: IslandGrid,
basePos: number
) => {
// emergency cutoff in case sinkhole ends up fighting a generator that terminates at a given elevation
let ticks = 0;
return () => {
if (ticks++ < SINKHOLE_BURNOUT) {
const sunk = islands.floodSearch(basePos, (tile) => tile < 0);
islands.sinkhole(islands.choose(sunk));
}
return true;
};
};
/** carve out elevation more aggressively */
export const WIDE_SINKHOLE: LobeGeneratorConstructor = (
islands: IslandGrid,
basePos: number
) => {
// emergency cutoff in case sinkhole ends up fighting a generator that terminates at a given elevation
let ticks = 0;
return () => {
if (ticks++ < SINKHOLE_BURNOUT) {
const sunk = islands.floodSearch(basePos, (tile) => tile < 0);
const sunkEdge = sunk.filter((pos) => islands.data[pos] >= WATER);
if (sunkEdge.length > 0) {
islands.sinkhole(islands.choose(sunkEdge));
} else {
islands.sinkhole(islands.choose(sunk));
}
}
return true;
};
};
export const BIG_ISLANDS = [BIG_MOUNTAIN, BIG_BEACH, HILLY_FOREST]; export const BIG_ISLANDS = [BIG_MOUNTAIN, BIG_BEACH, HILLY_FOREST];
export const ROCKY_ISLANDS = [SMALL_MOUNTAIN, BIG_MOUNTAIN, HILLY_FOREST]; export const ROCKY_ISLANDS = [SMALL_MOUNTAIN, BIG_MOUNTAIN, HILLY_FOREST];
export const GREEN_ISLANDS = [ export const GREEN_ISLANDS = [
@ -186,3 +230,4 @@ export const ALL_ISLANDS = [
HILLY_FOREST, HILLY_FOREST,
ERODED_BEACH, ERODED_BEACH,
]; ];
export const VOIDS = [NO_ISLAND, SINKHOLE, WIDE_SINKHOLE];

View file

@ -7,7 +7,9 @@ import {
LobeGenerator, LobeGenerator,
NO_ISLAND, NO_ISLAND,
ROCKY_ISLANDS, ROCKY_ISLANDS,
SINKHOLE,
SMALL_ISLANDS, SMALL_ISLANDS,
VOIDS,
} from "./generators"; } from "./generators";
export class IslandGrid { export class IslandGrid {
@ -30,10 +32,10 @@ export class IslandGrid {
this.choose(SMALL_ISLANDS), this.choose(SMALL_ISLANDS),
this.choose(ALL_ISLANDS), this.choose(ALL_ISLANDS),
this.choose(ALL_ISLANDS), this.choose(ALL_ISLANDS),
NO_ISLAND, this.choose(VOIDS),
NO_ISLAND, this.choose(VOIDS),
NO_ISLAND, this.choose(VOIDS),
NO_ISLAND, this.choose(VOIDS),
NO_ISLAND, NO_ISLAND,
NO_ISLAND, NO_ISLAND,
]); ]);
@ -126,10 +128,36 @@ export class IslandGrid {
} }
// flat, increase elevation // flat, increase elevation
const newValue = ++this.data[pos]; ++this.data[pos];
if (newValue == ICECAP) { }
this.done = true;
public sinkhole(pos: number): void {
const higherNeighbors: number[] = [];
const check = (adjPos: number) => {
if (this.data[adjPos] > this.data[pos]) {
higherNeighbors.push(adjPos);
}
};
// try to pull from neighbors
check((pos - this.width - 1) % this.data.length);
check((pos - this.width) % this.data.length);
check((pos - this.width + 1) % this.data.length);
check((pos - 1) % this.data.length);
check((pos + 1) % this.data.length);
check((pos + this.width - 1) % this.data.length);
check((pos + this.width) % this.data.length);
check((pos + this.width + 1) % this.data.length);
if (higherNeighbors.length > 0) {
const uphill = higherNeighbors[this.rng() % higherNeighbors.length];
return this.sinkhole(uphill);
} }
// flat, decrease elevation
this.data[pos] = Math.max(this.data[pos] - 1, -3);
} }
public choose<T>(list: T[]) { public choose<T>(list: T[]) {

View file

@ -9,6 +9,11 @@ export function renderIslands(
for (let x = 0; x < islands.width; x++) { for (let x = 0; x < islands.width; x++) {
const tile = islands.data[islands.xy(x, y)]; const tile = islands.data[islands.xy(x, y)];
switch (tile) { switch (tile) {
case -3:
case -2:
case -1:
cx.fillStyle = "#000088";
break;
case WATER: case WATER:
cx.fillStyle = "blue"; cx.fillStyle = "blue";
break; break;