<andres-carmona />

Algoritmo Mulberry32
First published on
on programming, tech, gamedev

Ya hace un tiempo que he querido incursionar en el desarrollo de videojuegos, y hoy en día es mucho más fácil utilizando la IA, sin embargo mi meta nunca ha sido crear un juego como tal (aunque esto pareciera ser el objetivo último), si no aprender todos los conceptos y técnicas al rededor del desarrollo de videojuegos, por lo que hace unas semanas empecé a desarrollar una prueba de concepto, un video juego basado en el mítico FreeCiv al que he llamado MicroCiv.

FreeCiv es un juego de estrategia por turnos que te permite desarrollar y gestionar una civilización desde sus inicios hasta convertirse en una potencia mundial, enfrentándote a otros jugadores o a la inteligencia artificial en un mapa generado proceduralmente.

Uno de los aspectos importantes en este tipo de juegos es la aleatoriedad, que nos permitirá generar diferentes aspectos del juego de manera aleatoria (me refiero a mapas, biomas, estructuras, etc). Sin embargo, necesitamos cierto determinismo dentro de esta aleatoriedad, es decir; necesitamos poder replicar exactamente la misma secuencia de números aleatorios basándonos en una misma semilla, y para eso Mulberry32 se pinta solo.

Mulberry32 es un generador de números pseudoaleatorios (PRNG) determinista de 32 bits. Determinista significa que toda la secuencia de números que produce está completamente determinada por su estado inicial, comúnmente llamado semilla.

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;
  }
}

Implementación básica de Mulberry32

En mi actual implementación lo estoy usando para la generación procedimental de un mapa básico en 2D.

En el mapa anterior los diferentes colores corresponden a tipos de terrenos de acuerdo a la siguiente relación:

const TERRAIN_COLORS: Record<TerrainId, string> = {
  OCEAN: "#2f79a8", // Azul
  GRASSLAND: "#7fad4b", // Verde
  FOREST: "#28674a", // Verde oscuro
  MOUNTAINS: "#85817a", // Gris
};

Si quieres saber más como funciona internamente este algoritmo te dejo estos excelentes enlaces donde se explica a detalle y paso a paso como funciona.