1use rydit_core::{RyditModule, ModuleResult, ModuleError};
8use serde_json::{Value, json};
9use std::collections::HashMap;
10
11pub struct PhysicsModule;
13
14impl RyditModule for PhysicsModule {
15 fn name(&self) -> &'static str {
16 "physics"
17 }
18
19 fn version(&self) -> &'static str {
20 "0.7.3"
21 }
22
23 fn register(&self) -> HashMap<&'static str, &'static str> {
24 let mut cmds = HashMap::new();
25 cmds.insert("projectile", "Simulación de proyectil");
26 cmds.insert("nbody_2", "Simulación N-cuerpos (2 cuerpos)");
27 cmds
28 }
29
30 fn execute(&self, command: &str, params: Value) -> ModuleResult {
31 match command {
32 "projectile" => self.projectile(params),
33 "nbody_2" => self.nbody_2(params),
34 _ => Err(ModuleError {
35 code: "UNKNOWN_COMMAND".to_string(),
36 message: format!("Comando desconocido: {}", command),
37 }),
38 }
39 }
40}
41
42impl PhysicsModule {
43 fn projectile(&self, params: Value) -> ModuleResult {
53 let arr = params.as_array().ok_or_else(|| ModuleError {
54 code: "INVALID_PARAMS".to_string(),
55 message: "Params must be an array".to_string(),
56 })?;
57
58 if arr.len() != 4 {
59 return Err(ModuleError {
60 code: "INVALID_PARAMS".to_string(),
61 message: "physics::projectile requires 4 params: x0, y0, v0, angle".to_string(),
62 });
63 }
64
65 let x0 = arr[0].as_f64().unwrap_or(0.0);
66 let y0 = arr[1].as_f64().unwrap_or(0.0);
67 let v0 = arr[2].as_f64().unwrap_or(0.0);
68 let angle = arr[3].as_f64().unwrap_or(0.0);
69
70 let rad = angle.to_radians();
71 let vx = v0 * rad.cos();
72 let vy = v0 * rad.sin();
73 let g = 9.81;
74
75 let flight_time = 2.0 * vy / g;
76 let max_height = (vy * vy) / (2.0 * g);
77 let range = vx * flight_time;
78
79 Ok(json!([
80 x0 + vx * flight_time, y0, flight_time, max_height, range ]))
86 }
87
88 fn nbody_2(&self, params: Value) -> ModuleResult {
99 let arr = params.as_array().ok_or_else(|| ModuleError {
100 code: "INVALID_PARAMS".to_string(),
101 message: "Params must be an array".to_string(),
102 })?;
103
104 if arr.len() != 7 {
105 return Err(ModuleError {
106 code: "INVALID_PARAMS".to_string(),
107 message: "physics::nbody_2 requires 7 params: m1, m2, x1, y1, x2, y2, G".to_string(),
108 });
109 }
110
111 let m1 = arr[0].as_f64().unwrap_or(0.0);
112 let m2 = arr[1].as_f64().unwrap_or(0.0);
113 let x1 = arr[2].as_f64().unwrap_or(0.0);
114 let y1 = arr[3].as_f64().unwrap_or(0.0);
115 let x2 = arr[4].as_f64().unwrap_or(0.0);
116 let y2 = arr[5].as_f64().unwrap_or(0.0);
117 let g = arr[6].as_f64().unwrap_or(6.674e-11);
118
119 let dx = x2 - x1;
120 let dy = y2 - y1;
121 let dist = (dx * dx + dy * dy).sqrt();
122
123 if dist > 0.001 {
124 let force = g * m1 * m2 / (dist * dist);
125 let fx = force * dx / dist;
126 let fy = force * dy / dist;
127
128 Ok(json!([fx, fy, -fx, -fy, dist]))
129 } else {
130 Ok(json!([0.0, 0.0, 0.0, 0.0, dist]))
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_physics_module_name() {
141 let module = PhysicsModule;
142 assert_eq!(module.name(), "physics");
143 assert_eq!(module.version(), "0.7.3");
144 }
145
146 #[test]
147 fn test_physics_register() {
148 let module = PhysicsModule;
149 let cmds = module.register();
150
151 assert!(cmds.contains_key("projectile"));
152 assert!(cmds.contains_key("nbody_2"));
153 }
154
155 #[test]
156 fn test_projectile() {
157 let module = PhysicsModule;
158 let params = json!([0.0, 0.0, 10.0, 45.0]);
160 let result = module.execute("projectile", params).unwrap();
161
162 let arr = result.as_array().unwrap();
163 assert_eq!(arr.len(), 5);
164 let flight_time = arr[2].as_f64().unwrap();
166 assert!(flight_time > 1.4 && flight_time < 1.5);
167 }
168
169 #[test]
170 fn test_nbody_2() {
171 let module = PhysicsModule;
172 let params = json!([100.0, 200.0, 0.0, 0.0, 10.0, 0.0, 1.0]);
174 let result = module.execute("nbody_2", params).unwrap();
175
176 let arr = result.as_array().unwrap();
177 assert_eq!(arr.len(), 5);
178 let fx = arr[0].as_f64().unwrap();
180 assert!((fx - 200.0).abs() < 0.01);
181 }
182
183 #[test]
184 fn test_nbody_2_close() {
185 let module = PhysicsModule;
186 let params = json!([100.0, 200.0, 0.0, 0.0, 0.0001, 0.0, 1.0]);
188 let result = module.execute("nbody_2", params).unwrap();
189
190 let arr = result.as_array().unwrap();
191 assert_eq!(arr[0].as_f64().unwrap(), 0.0);
192 assert_eq!(arr[1].as_f64().unwrap(), 0.0);
193 }
194
195 #[test]
196 fn test_unknown_command() {
197 let module = PhysicsModule;
198 let result = module.execute("unknown", json!([]));
199
200 assert!(result.is_err());
201 let err = result.unwrap_err();
202 assert_eq!(err.code, "UNKNOWN_COMMAND");
203 }
204}