Factor out generators
This commit is contained in:
parent
a7e0145736
commit
4fc076d80c
2 changed files with 101 additions and 49 deletions
74
island/generators.ts
Normal file
74
island/generators.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import { BEACH, ICECAP, LIGHT_FOREST, MOUNTAIN, WATER } from "./data";
|
||||
import { IslandGrid } from "./grid";
|
||||
|
||||
export type IsDone = boolean;
|
||||
export type LobeGenerator = () => IsDone;
|
||||
export type LobeGeneratorConstructor = (
|
||||
islands: IslandGrid,
|
||||
basePos: number
|
||||
) => LobeGenerator;
|
||||
|
||||
/** form mountain with icecap */
|
||||
export const BIG_MOUNTAIN: LobeGeneratorConstructor =
|
||||
(islands: IslandGrid, basePos: number) => () => {
|
||||
const mountainTiles = islands.floodSearch(
|
||||
basePos,
|
||||
(tile) => tile > MOUNTAIN
|
||||
);
|
||||
islands.dropWithin(mountainTiles);
|
||||
|
||||
return mountainTiles.some((pos) => islands.data[pos] == ICECAP);
|
||||
};
|
||||
|
||||
/** form low-lying beach */
|
||||
export const BEACH_LOBE: LobeGeneratorConstructor =
|
||||
(islands: IslandGrid, basePos: number) => () => {
|
||||
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
||||
|
||||
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
||||
islands.dropWithin(shoreTiles);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/** form forested zone */
|
||||
export const FOREST_LOBE: LobeGeneratorConstructor =
|
||||
(islands: IslandGrid, basePos: number) => () => {
|
||||
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
||||
|
||||
// grow shore
|
||||
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
||||
islands.dropWithin(shoreTiles);
|
||||
|
||||
// seed beach
|
||||
const beachTiles = islandTiles.filter((pos) => islands.data[pos] == BEACH);
|
||||
islands.dropWithin(beachTiles);
|
||||
|
||||
// expand forest
|
||||
const forestLobe = islands.floodSearch(basePos, (tile) => tile > BEACH);
|
||||
const forestTiles = forestLobe.filter(
|
||||
(pos) => islands.data[pos] == LIGHT_FOREST
|
||||
);
|
||||
islands.dropWithin(forestTiles);
|
||||
islands.dropWithin(forestTiles);
|
||||
islands.dropWithin(forestTiles);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/** form low-lying beach with eroded sections */
|
||||
export const ERODED_LOBE: LobeGeneratorConstructor =
|
||||
(islands: IslandGrid, basePos: number) => () => {
|
||||
const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);
|
||||
|
||||
const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
|
||||
islands.dropWithin(shoreTiles);
|
||||
|
||||
// erode
|
||||
if (islandTiles.length > 1) {
|
||||
const erodePos = islandTiles[islands.rng() % islandTiles.length];
|
||||
islands.data[erodePos] = Math.max(islands.data[erodePos] - 1, WATER);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
|
@ -1,13 +1,17 @@
|
|||
import { Prng, mulberry32 } from "../lib/prng";
|
||||
import { BEACH, ICECAP, LIGHT_FOREST, MOUNTAIN, WATER } from "./data";
|
||||
import {
|
||||
BEACH_LOBE,
|
||||
BIG_MOUNTAIN,
|
||||
FOREST_LOBE,
|
||||
LobeGenerator,
|
||||
} from "./generators";
|
||||
|
||||
export class IslandGrid {
|
||||
data: number[];
|
||||
rng: Prng;
|
||||
|
||||
basePos: number;
|
||||
lobePos1: number;
|
||||
lobePos2: number;
|
||||
generators: LobeGenerator[] = [];
|
||||
|
||||
done = false;
|
||||
|
||||
|
@ -15,14 +19,24 @@ export class IslandGrid {
|
|||
this.data = Array(width * height).fill(0);
|
||||
this.rng = mulberry32(seed);
|
||||
|
||||
this.basePos = this.data.length >> 1;
|
||||
this.lobePos1 = this.xy(
|
||||
(width >> 1) + (this.rng() % 48) - 24,
|
||||
(height >> 1) + (this.rng() % 48) - 24
|
||||
this.generators.push(BIG_MOUNTAIN(this, this.data.length >> 1));
|
||||
this.generators.push(
|
||||
FOREST_LOBE(
|
||||
this,
|
||||
this.xy(
|
||||
(width >> 1) + (this.rng() % 48) - 24,
|
||||
(height >> 1) + (this.rng() % 48) - 24
|
||||
)
|
||||
)
|
||||
);
|
||||
this.lobePos2 = this.xy(
|
||||
(width >> 1) + (this.rng() % 48) - 24,
|
||||
(height >> 1) + (this.rng() % 48) - 24
|
||||
this.generators.push(
|
||||
BEACH_LOBE(
|
||||
this,
|
||||
this.xy(
|
||||
(width >> 1) + (this.rng() % 48) - 24,
|
||||
(height >> 1) + (this.rng() % 48) - 24
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -112,44 +126,8 @@ export class IslandGrid {
|
|||
}
|
||||
|
||||
public step() {
|
||||
const lowlandTiles1 = this.floodSearch(
|
||||
this.lobePos1,
|
||||
(tile) => tile > WATER
|
||||
);
|
||||
const lowlandTiles2 = this.floodSearch(
|
||||
this.lobePos2,
|
||||
(tile) => tile > WATER
|
||||
);
|
||||
|
||||
// grow shore
|
||||
const shoreTiles1 = lowlandTiles1.filter((pos) => this.data[pos] == WATER);
|
||||
this.dropWithin(shoreTiles1);
|
||||
const shoreTiles2 = lowlandTiles2.filter((pos) => this.data[pos] == WATER);
|
||||
this.dropWithin(shoreTiles2);
|
||||
|
||||
// seed beach
|
||||
const beachTiles = lowlandTiles1.filter((pos) => this.data[pos] == BEACH);
|
||||
this.dropWithin(beachTiles);
|
||||
|
||||
// expand forest
|
||||
const forestLobe = this.floodSearch(this.lobePos1, (tile) => tile > BEACH);
|
||||
const forestTiles = forestLobe.filter(
|
||||
(pos) => this.data[pos] == LIGHT_FOREST
|
||||
);
|
||||
this.dropWithin(forestTiles);
|
||||
this.dropWithin(forestTiles);
|
||||
this.dropWithin(forestTiles);
|
||||
|
||||
// form mountain
|
||||
const mountainTiles = this.floodSearch(
|
||||
this.basePos,
|
||||
(tile) => tile > MOUNTAIN
|
||||
);
|
||||
this.dropWithin(mountainTiles); // GENERATOR
|
||||
|
||||
if (lowlandTiles2.length > 1) {
|
||||
const erodePos = lowlandTiles2[this.rng() % lowlandTiles2.length];
|
||||
this.data[erodePos] = Math.max(this.data[erodePos] - 1, 0);
|
||||
}
|
||||
this.done = this.generators
|
||||
.map((generator) => generator())
|
||||
.every((done) => done);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue