core_rust/core/utils/
plotting.rs1use crate::core::game::state::State;
2use plotters::prelude::*;
3use std::fs;
4use std::path::Path;
5
6#[allow(dead_code)]
8pub fn draw_world(
9 world: &[Vec<char>],
10 out_path: &str,
11 cell_size: u32,
12) -> Result<(), Box<dyn std::error::Error>> {
13 if let Some(dir) = Path::new(out_path).parent() {
15 fs::create_dir_all(dir)?;
16 }
17
18 let rows = world.len() as i32;
20 let cols = if rows > 0 { world[0].len() as i32 } else { 0 };
21 let cs = cell_size as i32;
22 let width = cols * cs;
23 let height = rows * cs;
24
25 let root = BitMapBackend::new(out_path, ((width) as u32, (height) as u32)).into_drawing_area();
27 root.fill(&WHITE)?;
28
29 for row in 0..=rows {
31 let y = row * cs;
32 root.draw(&PathElement::new(vec![(0, y), (width, y)], BLACK))?;
33 }
34 for col in 0..=cols {
35 let x = col * cs;
36 root.draw(&PathElement::new(vec![(x, 0), (x, height)], BLACK))?;
37 }
38
39 for (r, row) in world.iter().enumerate() {
41 for (c, &ch) in row.iter().enumerate() {
42 let x0 = (c as i32) * cs;
43 let y0 = (r as i32) * cs;
44
45 match ch {
46 'X' => {
47 root.draw(&Rectangle::new(
49 [(x0, y0), (x0 + cs, y0 + cs)],
50 BLACK.filled(),
51 ))?;
52 }
53 'G' => {
54 root.draw(&Text::new(
56 "G",
57 (x0 + cs / 3, y0 + cs / 4),
58 ("sans-serif", (cs / 2) as u32).into_font().color(&GREEN),
59 ))?;
60 }
61 _ => { }
62 }
63 }
64 }
65
66 root.present()?;
67 Ok(())
68}
69
70#[allow(dead_code)]
72pub fn draw_abstraction(
73 world: &[Vec<char>],
74 states: &[State],
75 clusters: &[Vec<isize>],
76 out_path: &str,
77 cell_size: u32,
78) -> Result<(), Box<dyn std::error::Error>> {
79 if let Some(dir) = Path::new(out_path).parent() {
81 fs::create_dir_all(dir)?;
82 }
83 let rows = world.len() as i32;
84 let cols = if rows > 0 { world[0].len() as i32 } else { 0 };
85 let cs = cell_size as i32;
86 let width = (cols * cs) as u32;
87 let height = (rows * cs) as u32;
88
89 let root = BitMapBackend::new(out_path, (width, height)).into_drawing_area();
90 root.fill(&WHITE)?;
91
92 for r in 0..=rows {
94 let y = r * cs;
95 root.draw(&PathElement::new(vec![(0, y), (cols * cs, y)], BLACK))?;
96 }
97 for c in 0..=cols {
98 let x = c * cs;
99 root.draw(&PathElement::new(vec![(x, 0), (x, rows * cs)], BLACK))?;
100 }
101 for (r, row) in world.iter().enumerate() {
102 for (c, &ch) in row.iter().enumerate() {
103 let x0 = (c as i32) * cs;
104 let y0 = (r as i32) * cs;
105 if ch == 'X' {
106 root.draw(&Rectangle::new(
107 [(x0, y0), (x0 + cs, y0 + cs)],
108 BLACK.filled(),
109 ))?;
110 }
111 }
112 }
113
114 for (abs_id, cluster) in clusters.iter().enumerate() {
116 let label = abs_id.to_string();
117 for &state_idx in cluster {
118 let State {
119 unit_position: (x, y),
120 ..
121 } = &states[state_idx as usize];
122 let x0 = (*x as i32) * cs;
123 let y0 = (*y as i32) * cs;
124 let cx = x0 + cs / 2;
125 let cy = y0 + cs / 2;
126 let radius = (cs as f64) * 0.4;
128
129 root.draw(&Circle::new((cx, cy), radius, BLUE))?;
131
132 root.draw(&Text::new(
134 label.clone(),
135 (
136 cx - (cs as f64 * 0.15) as i32,
137 cy - (cs as f64 * 0.15) as i32,
138 ),
139 ("sans-serif", (cs as f64 * 0.5) as u32)
140 .into_font()
141 .color(&BLACK),
142 ))?;
143 }
144 }
145
146 root.present()?;
147 Ok(())
148}