Skip to main content

plato_mud/
types.rs

1//! PLATO MUD Engine — Core Types
2//!
3//! Rooms are computational domains. Tiles are structured knowledge objects.
4//! NPCs are expert agents. FLUX carries zeitgeist between rooms.
5
6extern crate alloc;
7
8use alloc::collections::BTreeMap;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::fmt;
12use serde::{Deserialize, Serialize};
13
14// ─── IDs ───────────────────────────────────────────────────────────────────
15
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
17pub struct RoomId(pub String);
18
19#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
20pub struct TileId(pub String);
21
22#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
23pub struct NpcId(pub String);
24
25#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
26pub struct AgentId(pub String);
27
28// ─── Domain & Depth ────────────────────────────────────────────────────────
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub enum Domain {
32    Fortran,
33    Rust,
34    C,
35    Python,
36    TypeScript,
37    Zig,
38    Cuda,
39    Concept,
40    Infrastructure,
41    Alignment,
42}
43
44impl Domain {
45    pub fn all() -> Vec<Domain> {
46        vec![
47            Domain::Fortran,
48            Domain::Rust,
49            Domain::C,
50            Domain::Python,
51            Domain::TypeScript,
52            Domain::Zig,
53            Domain::Cuda,
54            Domain::Concept,
55            Domain::Infrastructure,
56            Domain::Alignment,
57        ]
58    }
59
60    pub fn name(&self) -> &str {
61        match self {
62            Domain::Fortran => "fortran",
63            Domain::Rust => "rust",
64            Domain::C => "c",
65            Domain::Python => "python",
66            Domain::TypeScript => "typescript",
67            Domain::Zig => "zig",
68            Domain::Cuda => "cuda",
69            Domain::Concept => "concept",
70            Domain::Infrastructure => "infrastructure",
71            Domain::Alignment => "alignment",
72        }
73    }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
77pub enum Depth {
78    Introductory,
79    Advanced,
80    Expert,
81}
82
83impl Depth {
84    pub fn level(&self) -> u8 {
85        match self {
86            Depth::Introductory => 0,
87            Depth::Advanced => 1,
88            Depth::Expert => 2,
89        }
90    }
91}
92
93// ─── Room ───────────────────────────────────────────────────────────────────
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
96pub enum RoomState {
97    /// Room is dormant, no active agents
98    Dormant,
99    /// Agents are present and working
100    Active,
101    /// Knowledge is being validated/certified
102    Validating,
103    /// Room is merging zeitgeist from another room
104    Merging,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct Exit {
109    pub direction: String,
110    pub target: RoomId,
111    pub description: String,
112    pub locked: bool,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct Workbench {
117    pub name: String,
118    pub description: String,
119    pub recipes: Vec<Recipe>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct Recipe {
124    pub name: String,
125    pub inputs: Vec<TileId>,
126    pub output: TileContent,
127    pub description: String,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Room {
132    pub id: RoomId,
133    pub name: String,
134    pub description: String,
135    pub domain: Domain,
136    pub exits: Vec<Exit>,
137    pub tiles: Vec<TileId>,
138    pub npcs: Vec<NpcId>,
139    pub workbench: Option<Workbench>,
140    pub depth: Depth,
141    pub state: RoomState,
142}
143
144// ─── Tile ───────────────────────────────────────────────────────────────────
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct SpatialIndex {
148    /// Domain axis
149    pub x: f64,
150    /// Depth axis
151    pub y: f64,
152    /// Time axis
153    pub z: f64,
154}
155
156#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
157pub enum TileContent {
158    Theorem(String),
159    Proof(String),
160    Code(String),
161    Benchmark(String),
162    Caveat(String),
163    EmpiricalData(String),
164    Falsification(String),
165    Constraint(String),
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
169pub enum Lifecycle {
170    Created,
171    Validated,
172    Certified,
173    Superseded,
174    Deprecated,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct Tile {
179    pub id: TileId,
180    pub title: String,
181    pub location: SpatialIndex,
182    pub author: AgentId,
183    pub confidence: f64,
184    pub domain_tags: Vec<String>,
185    pub links: Vec<TileId>,
186    pub content: TileContent,
187    pub lifecycle: Lifecycle,
188    pub bloom_hash: [u8; 32],
189}
190
191// ─── NPC ────────────────────────────────────────────────────────────────────
192
193#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
194pub struct Query(pub String);
195
196#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
197pub struct Response(pub String);
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct Dialog {
201    pub npc: NpcId,
202    pub agent: AgentId,
203    pub turns: Vec<(String, String)>,
204    pub topic: String,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct Npc {
209    pub id: NpcId,
210    pub name: String,
211    pub room: RoomId,
212    pub expertise: Vec<String>,
213    pub personality: String,
214    pub knowledge_graph: BTreeMap<Query, Response>,
215    pub current_dialog: Option<Dialog>,
216}
217
218// ─── FLUX / Zeitgeist ──────────────────────────────────────────────────────
219
220/// Deadband funnel state — tracks precision convergence
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct FunnelState {
223    pub center: f64,
224    pub width: f64,
225    pub samples: u64,
226    pub converged: bool,
227}
228
229/// Bloom filter for certainty tracking
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct BloomFilter {
232    pub bits: Vec<u64>,
233    pub num_hashes: u32,
234    pub estimated_count: u64,
235}
236
237impl BloomFilter {
238    pub fn new(num_hashes: u32, size_bits: usize) -> Self {
239        let num_words = size_bits.div_ceil(64);
240        Self {
241            bits: alloc::vec![0u64; num_words],
242            num_hashes,
243            estimated_count: 0,
244        }
245    }
246
247    pub fn insert(&mut self, item: &[u8]) {
248        for i in 0..self.num_hashes {
249            let hash = simple_hash(item, i);
250            let bit = hash as usize % (self.bits.len() * 64);
251            self.bits[bit / 64] |= 1u64 << (bit % 64);
252        }
253        self.estimated_count += 1;
254    }
255
256    pub fn contains(&self, item: &[u8]) -> bool {
257        for i in 0..self.num_hashes {
258            let hash = simple_hash(item, i);
259            let bit = hash as usize % (self.bits.len() * 64);
260            if self.bits[bit / 64] & (1u64 << (bit % 64)) == 0 {
261                return false;
262            }
263        }
264        true
265    }
266
267    /// Merge two bloom filters (bitwise OR) — CRDT merge
268    pub fn merge(&mut self, other: &BloomFilter) {
269        for (i, word) in other.bits.iter().enumerate() {
270            if i < self.bits.len() {
271                self.bits[i] |= word;
272            }
273        }
274        self.estimated_count = core::cmp::max(self.estimated_count, other.estimated_count);
275    }
276}
277
278fn simple_hash(data: &[u8], seed: u32) -> u64 {
279    let mut hash: u64 = 0xcbf29ce484222325;
280    hash = hash.wrapping_add(seed as u64);
281    for &byte in data {
282        hash ^= byte as u64;
283        hash = hash.wrapping_mul(0x100000001b3);
284    }
285    hash
286}
287
288/// Hurst exponent estimate for trend detection
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct HurstEstimate {
291    pub value: f64,
292    pub confidence: f64,
293    pub sample_count: u64,
294}
295
296/// Holonomy state — cycle coherence tracking
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct HolonomyState {
299    pub cycle_count: u64,
300    pub coherence: f64,
301    pub last_check: f64,
302}
303
304/// Beat position — temporal rhythm
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct BeatPosition {
307    pub beat: u64,
308    pub tempo: f64,
309    pub phase: f64,
310}
311
312/// The zeitgeist carried by FLUX transference
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct Zeitgeist {
315    pub precision: FunnelState,
316    pub confidence: BloomFilter,
317    pub trajectory: HurstEstimate,
318    pub consensus: HolonomyState,
319    pub temporal: BeatPosition,
320}
321
322impl Default for Zeitgeist {
323    fn default() -> Self {
324        Self::new()
325    }
326}
327
328impl Zeitgeist {
329    pub fn new() -> Self {
330        Self {
331            precision: FunnelState {
332                center: 0.0,
333                width: 1.0,
334                samples: 0,
335                converged: false,
336            },
337            confidence: BloomFilter::new(3, 256),
338            trajectory: HurstEstimate {
339                value: 0.5,
340                confidence: 0.0,
341                sample_count: 0,
342            },
343            consensus: HolonomyState {
344                cycle_count: 0,
345                coherence: 0.0,
346                last_check: 0.0,
347            },
348            temporal: BeatPosition {
349                beat: 0,
350                tempo: 120.0,
351                phase: 0.0,
352            },
353        }
354    }
355
356    /// CRDT merge — commutative, associative, idempotent
357    pub fn merge(&mut self, other: &Zeitgeist) {
358        // Precision: narrowest funnel wins (most precise)
359        // Accumulate samples first, then adopt narrower funnel
360        self.precision.samples += other.precision.samples;
361        if other.precision.width < self.precision.width {
362            self.precision.width = other.precision.width;
363            self.precision.center = other.precision.center;
364            self.precision.converged = other.precision.converged;
365        }
366
367        // Confidence: bloom filter OR (CRDT)
368        self.confidence.merge(&other.confidence);
369
370        // Trajectory: highest confidence estimate
371        if other.trajectory.confidence > self.trajectory.confidence {
372            self.trajectory = other.trajectory.clone();
373        }
374
375        // Consensus: max coherence
376        self.consensus.cycle_count =
377            core::cmp::max(self.consensus.cycle_count, other.consensus.cycle_count);
378        self.consensus.coherence = self.consensus.coherence.max(other.consensus.coherence);
379
380        // Temporal: latest beat
381        self.temporal.beat = core::cmp::max(self.temporal.beat, other.temporal.beat);
382    }
383}
384
385// ─── FLUX Transference ──────────────────────────────────────────────────────
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub enum TransferencePayload {
389    Tile(Tile),
390    Knowledge(String),
391    StateUpdate(RoomState),
392    AlignmentCheck(AlignmentReport),
393    Heartbeat,
394}
395
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct AlignmentReport {
398    pub constraint_id: u8,
399    pub passed: bool,
400    pub message: String,
401    pub severity: AlignmentSeverity,
402}
403
404#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
405pub enum AlignmentSeverity {
406    Info,
407    Warning,
408    Block,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
412pub struct FluxTransference {
413    pub source: RoomId,
414    pub target: RoomId,
415    pub timestamp: f64,
416    pub payload: TransferencePayload,
417    pub zeitgeist: Zeitgeist,
418}
419
420// ─── Commands ───────────────────────────────────────────────────────────────
421
422#[derive(Debug, Clone, PartialEq, Eq)]
423pub enum Command {
424    Look,
425    Go(String),
426    Get(String),
427    Drop(String),
428    Talk(String),
429    Craft(Vec<String>),
430    Inventory,
431    Map,
432    Help,
433    Examine(String),
434    Status,
435}
436
437impl fmt::Display for Command {
438    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439        match self {
440            Command::Look => write!(f, "LOOK"),
441            Command::Go(dir) => write!(f, "GO {}", dir),
442            Command::Get(item) => write!(f, "GET {}", item),
443            Command::Drop(item) => write!(f, "DROP {}", item),
444            Command::Talk(npc) => write!(f, "TALK {}", npc),
445            Command::Craft(items) => write!(f, "CRAFT {}", items.join(" + ")),
446            Command::Inventory => write!(f, "INVENTORY"),
447            Command::Map => write!(f, "MAP"),
448            Command::Help => write!(f, "HELP"),
449            Command::Examine(t) => write!(f, "EXAMINE {}", t),
450            Command::Status => write!(f, "STATUS"),
451        }
452    }
453}
454
455// ─── Agent Session ──────────────────────────────────────────────────────────
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct AgentSession {
459    pub agent_id: AgentId,
460    pub current_room: RoomId,
461    pub inventory: Vec<TileId>,
462    pub connected_at: f64,
463}
464
465// ─── Transport ──────────────────────────────────────────────────────────────
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct TransportConfig {
469    pub transport_type: String,
470    pub address: String,
471    pub port: u16,
472    pub options: BTreeMap<String, String>,
473}