Files
brahman/crates/modules/dominium/dominium-core/src/grid.rs
T
sergio d1727b1374 feat(dominium): dominium-core — núcleo del simulador de campo medio
- grid — el Sustrato Plano: grilla SoA de 5 capas f32 (materia, psique,
  poder, oro, degradación), indexada y*width+x.
- lemmings — Agentes Vectoriales en SoA: pos_x/y, edad, energia,
  vector_psi [Orden,Miedo,Curiosidad,Corruptibilidad], accion u8.
  spawn / swap_remove / nearest (determinista, empate por menor índice).
- world — World + las 6 acciones atómicas fijas: Mover (gravedad mental
  hacia el vecino más afín al psi), Extraer, Sincronizar, Intercambiar,
  Replicar, Degradar. step_lemming despacha por el byte accion.
- params — SimParams (las constantes que los sliders del panel ajustan).

Cero deps gráficas — sólo serde (regla inviolable de la spec).
11 tests verdes (acciones verificadas: Mover sigue la materia, Extraer
degrada, Replicar engendra, Intercambiar conserva energía, etc.).
cargo check --workspace verde.

Pendiente dominium: physics (difusión/entropía/cinemática), iso,
render-plan, canvas/panel GPUI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 16:01:42 +00:00

90 lines
2.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! El Sustrato Plano — grilla SoA de 5 capas de `f32`.
use serde::{Deserialize, Serialize};
/// Grilla de campos: 5 capas paralelas, cada una `width × height` `f32`,
/// indexadas `y * width + x`. Toda la física opera sobre estos arrays
/// contiguos (cache-friendly).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Grid {
pub width: usize,
pub height: usize,
/// Biomasa / energía / alimento disponible.
pub materia: Vec<f32>,
/// Densidad de información / frecuencia dogmática.
pub psique: Vec<f32>,
/// Tensión de control / deuda / atractores del Estado Profundo.
pub poder: Vec<f32>,
/// Materia prima densa intercambiable.
pub oro: Vec<f32>,
/// Contaminación / cicatrices industriales del suelo.
pub degradacion: Vec<f32>,
}
impl Grid {
/// Grilla de `width × height` con todas las capas en cero.
pub fn new(width: usize, height: usize) -> Self {
let n = width * height;
Self {
width,
height,
materia: vec![0.0; n],
psique: vec![0.0; n],
poder: vec![0.0; n],
oro: vec![0.0; n],
degradacion: vec![0.0; n],
}
}
/// Cantidad de celdas (`width * height`).
pub fn cells(&self) -> usize {
self.width * self.height
}
/// Índice plano de `(x, y)`. El caller garantiza bounds válidos.
pub fn idx(&self, x: usize, y: usize) -> usize {
y * self.width + x
}
/// `true` si `(x, y)` cae dentro de la grilla.
pub fn in_bounds(&self, x: i64, y: i64) -> bool {
x >= 0 && y >= 0 && (x as usize) < self.width && (y as usize) < self.height
}
/// Clampa una coordenada continua a una celda válida.
pub fn clamp_cell(&self, x: f32, y: f32) -> (usize, usize) {
let cx = (x.floor() as i64).clamp(0, self.width as i64 - 1) as usize;
let cy = (y.floor() as i64).clamp(0, self.height as i64 - 1) as usize;
(cx, cy)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_grid_is_zeroed() {
let g = Grid::new(8, 4);
assert_eq!(g.cells(), 32);
assert!(g.materia.iter().all(|&v| v == 0.0));
assert_eq!(g.materia.len(), 32);
}
#[test]
fn idx_and_bounds() {
let g = Grid::new(10, 5);
assert_eq!(g.idx(3, 2), 23);
assert!(g.in_bounds(9, 4));
assert!(!g.in_bounds(10, 4));
assert!(!g.in_bounds(-1, 0));
}
#[test]
fn clamp_cell_keeps_in_range() {
let g = Grid::new(10, 10);
assert_eq!(g.clamp_cell(-5.0, 3.7), (0, 3));
assert_eq!(g.clamp_cell(99.0, 99.0), (9, 9));
}
}