I’ve wanted to explore game development for a while, and these days it’s much easier with AI. However, my goal has never been to create a game as such (even if that might seem like the ultimate objective), but to learn all the concepts and techniques involved in game development. So a few weeks ago, I started building a proof of concept: a video game based on the legendary FreeCiv, which I’ve named MicroCiv.
FreeCiv is a turn-based strategy game that lets you develop and manage a civilization from its beginnings until it becomes a world power, competing against other players or artificial intelligence on a procedurally generated map.
One important aspect of games like this is randomness, which lets us generate different parts of the game at random (maps, biomes, structures, and so on). However, we need some determinism within that randomness: we need to be able to reproduce the exact same sequence of random numbers from the same seed. That’s where Mulberry32 really shines.
Mulberry32 is a deterministic 32-bit pseudo-random number generator (PRNG). Deterministic means that the entire sequence of numbers it produces is fully determined by its initial state, commonly called the seed.
class Mulberry32 {
constructor(seed) {
this.seed = seed >>> 0;
}
next() {
let t = (this.seed += 0x6d2b79f5);
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
}
}
Basic implementation of Mulberry32
In my current implementation, I’m using it for the procedural generation of a basic 2D map.
In the previous map, the different colors correspond to terrain types according to the following relationship:
const TERRAIN_COLORS: Record<TerrainId, string> = {
OCEAN: "#2f79a8", // Blue
GRASSLAND: "#7fad4b", // Green
FOREST: "#28674a", // Dark Green
MOUNTAINS: "#85817a", // Gray
};
If you’d like to learn more about how this algorithm works internally, here are some excellent links that explain it in detail, step by step.