fix(simulation): determinism fixes — BTreeSet ordering, entity sort, mover sort

Replace HashSet with BTreeSet for visible_ids, sort visible_tiles by
coordinates, sort visible entities in snapshot by entity_id, and sort
movers by Entity bits in validate_movement. Required by D-010 principle 4
(deterministic simulation). Fixes #456, #457, #458.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 17:40:57 +01:00
co-authored by Claude Opus 4.6
parent 600cfe506c
commit af8e20ab9a
3 changed files with 83 additions and 14 deletions
+4 -3
View File
@@ -5,7 +5,7 @@
//! provide mode-specific FOV and visibility sector computation.
//! v0.1 implements only NaturalVision.
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeSet, HashMap};
use bevy_ecs::prelude::*;
@@ -21,7 +21,7 @@ use crate::simulation::movement::{TilePosition, WalkabilityMap};
#[derive(Resource, Default)]
pub struct VisibilityGeometry {
pub visible_tiles: Vec<VisibleTile>,
pub visible_positions: HashSet<(i32, i32)>,
pub visible_positions: BTreeSet<(i32, i32)>,
pub sector_lookup: HashMap<(i32, i32), VisibilitySector>,
pub observer_z: i32,
}
@@ -64,7 +64,7 @@ impl PerceptionQuery for NaturalVision {
let cone_tiles = apply_vision_cone(&fov, observer_pos.x, observer_pos.y, facing, &config);
let visible_tiles = cone_tiles
let mut visible_tiles: Vec<VisibleTile> = cone_tiles
.iter()
.map(|&(x, y, sector)| {
let tile_kind = if walkability.can_move_to(&TilePosition::new(x, y, z)) {
@@ -81,6 +81,7 @@ impl PerceptionQuery for NaturalVision {
}
})
.collect();
visible_tiles.sort_by_key(|t| (t.x, t.y));
let visible_positions = cone_tiles.iter().map(|&(x, y, _)| (x, y)).collect();