core_rust/core/utils/
representation.rs

1use std::collections::HashMap;
2
3use crate::core::{
4    abstraction::homomorphism::get_all_states, game::game_logic::Game, game::utils::world::Terrain,
5};
6use serde_json::{json, Value};
7
8/// JSON object with start/goal IDs and a grid of state IDs.
9#[allow(dead_code)]
10fn generate_json_representation(game: &Game) -> Value {
11    let size = game.get_size();
12
13    let all_states = get_all_states(game).expect("failed to retrieve all staes in representation");
14
15    let mut position_to_id = HashMap::new();
16
17    for (index, state) in all_states.iter().enumerate() {
18        position_to_id.insert(state.unit_position, index);
19    }
20
21    let mut grid = Vec::with_capacity(size);
22
23    for y in 0..size {
24        let mut row = Vec::with_capacity(size);
25        for x in 0..size {
26            if let Some(&idx) = position_to_id.get(&(x, y)) {
27                row.push(json!(idx));
28            } else {
29                row.push(json!("X"));
30            }
31        }
32        grid.push(row);
33    }
34
35    // start & goal
36    let start_pos = (0, 0);
37    let start = *position_to_id.get(&start_pos).expect("start not found");
38    let goal_pos = game.goal();
39    let goal = *position_to_id.get(&goal_pos).expect("goal not found");
40
41    json!({
42        "start": start,
43        "goal":  goal,
44        "grid":  grid,
45    })
46}
47
48/// Human-readable text grid with state indices (X for impassable, ? for none).
49#[allow(dead_code)]
50fn generate_text_representation(game: &mut Game) -> String {
51    let size = game.get_size();
52    let all_states = get_all_states(game).expect("failed to enumerate states");
53    let mut pos2idx = HashMap::new();
54    for (i, st) in all_states.iter().enumerate() {
55        pos2idx.insert(st.unit_position, i);
56    }
57
58    let mut lines = Vec::with_capacity(size);
59    for y in 0..size {
60        let mut cells = Vec::with_capacity(size);
61        for x in 0..size {
62            match game.tile(x, y).terrain() {
63                Terrain::Mountain => {
64                    cells.push("X".to_string());
65                }
66                _ if pos2idx.contains_key(&(x, y)) => {
67                    cells.push(pos2idx[&(x, y)].to_string());
68                }
69                _ => {
70                    cells.push("?".to_string());
71                }
72            }
73        }
74        lines.push(cells.join(" "));
75    }
76    lines.join("\n")
77}
78
79/// JSON adjacency list keyed by state index with neighbor indices.
80#[allow(dead_code)]
81fn generate_adjacency_representation(game: &mut Game) -> Value {
82    let size = game.get_size();
83    let all_states = get_all_states(game).expect("failed to enumerate states");
84    let mut pos2idx = HashMap::new();
85    for (i, st) in all_states.iter().enumerate() {
86        pos2idx.insert(st.unit_position, i);
87    }
88
89    // start & goal
90    let start_pos = (0, 0);
91    let start = *pos2idx.get(&start_pos).expect("start not found");
92    let goal_pos = game.goal();
93    let goal = *pos2idx.get(&goal_pos).expect("goal not found");
94
95    // directions: up/down/left/right
96    let deltas = [(0_i32, -1_i32), (0, 1), (-1, 0), (1, 0)];
97
98    // build adjacency map
99    let mut state_adj = serde_json::Map::new();
100    for ((x, y), &idx) in &pos2idx {
101        let mut neigh = Vec::new();
102        for &(dx, dy) in &deltas {
103            let nx = *x as i32 + dx;
104            let ny = *y as i32 + dy;
105            if nx >= 0 && ny >= 0 && nx < size as i32 && ny < size as i32 {
106                let (nx, ny) = (nx as usize, ny as usize);
107                if game.tile(nx, ny).is_walkable() {
108                    if let Some(&j) = pos2idx.get(&(nx, ny)) {
109                        neigh.push(json!(j));
110                    }
111                }
112            }
113        }
114        state_adj.insert(idx.to_string(), Value::Array(neigh));
115    }
116
117    json!({
118        "start": start,
119        "goal":  goal,
120        "state adjacency": Value::Object(state_adj),
121    })
122}
123
124/// Build (json, text, adjacency) representations of the world.
125#[allow(dead_code)]
126pub fn generate_representations(game: &mut Game) -> (Value, String, Value) {
127    let js = generate_json_representation(game);
128    let txt = generate_text_representation(game);
129    let adj = generate_adjacency_representation(game);
130    (js, txt, adj)
131}