ED_LRR/rust/src/common.rs

232 lines
6.1 KiB
Rust

use crate::route::Router;
use dict_derive::IntoPyObject;
use pyo3::conversion::ToPyObject;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyTuple};
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::path::PathBuf;
pub fn get_fsd_booster_info(class: usize) -> Result<f32, String> {
// Data from https://elite-dangerous.fandom.com/wiki/Guardian_Frame_Shift_Drive_Booster
let ret = match class {
0 => 0.0,
1 => 4.0,
2 => 6.0,
3 => 7.75,
4 => 9.25,
5 => 10.5,
_ => return Err(format!("Invalid Guardian booster class: {}", class)),
};
return Ok(ret);
}
pub fn get_fsd_info(rating: usize, class: usize) -> Result<HashMap<String, f32>, String> {
let mut ret = HashMap::new();
// Data from https://elite-dangerous.fandom.com/wiki/Frame_Shift_Drive#Specifications
let (opt_mass, max_fuel) = match (class, rating) {
(2, 1) => (48.0, 0.6),
(2, 2) => (54.0, 0.6),
(2, 3) => (60.0, 0.6),
(2, 4) => (75.0, 0.8),
(2, 5) => (90.0, 0.9),
(3, 1) => (80.0, 1.2),
(3, 2) => (90.0, 1.2),
(3, 3) => (100.0, 1.2),
(3, 4) => (125.0, 1.5),
(3, 5) => (150.0, 1.8),
(4, 1) => (280.0, 2.0),
(4, 2) => (315.0, 2.0),
(4, 3) => (350.0, 2.0),
(4, 4) => (438.0, 2.5),
(4, 5) => (525.0, 3.0),
(5, 1) => (560.0, 3.3),
(5, 2) => (630.0, 3.3),
(5, 3) => (700.0, 3.3),
(5, 4) => (875.0, 4.1),
(5, 5) => (1050.0, 5.0),
(6, 1) => (960.0, 5.3),
(6, 2) => (1080.0, 5.3),
(6, 3) => (1200.0, 5.3),
(6, 4) => (1500.0, 6.6),
(6, 5) => (1800.0, 8.0),
(7, 1) => (1440.0, 8.5),
(7, 2) => (1620.0, 8.5),
(7, 3) => (1800.0, 8.5),
(7, 4) => (2250.0, 10.6),
(7, 5) => (2700.0, 12.8),
(r, c) => return Err(format!("Invalid FSD Type: Rating: {}, Class: {}", r, c)),
};
ret.insert("FSDOptimalMass".to_owned(), opt_mass);
ret.insert("MaxFuel".to_owned(), max_fuel);
return Ok(ret);
}
pub fn get_mult(star_type: &str) -> f32 {
if star_type.contains("White Dwarf") {
return 1.5;
}
if star_type.contains("Neutron") {
return 4.0;
}
1.0
}
pub enum SysEntry {
ID(u32),
Name(String),
}
impl SysEntry {
pub fn parse(s: &str) -> Self {
if let Ok(n) = s.parse() {
SysEntry::ID(n)
} else {
SysEntry::Name(s.to_owned())
}
}
}
pub fn find_matches(
path: &PathBuf,
names: Vec<String>,
exact: bool,
) -> Result<HashMap<String, (f64, Option<System>)>, String> {
let mut best: HashMap<String, (f64, Option<System>)> = HashMap::new();
if names.is_empty() {
return Ok(best);
}
for name in &names {
best.insert(name.to_string(), (0.0, None));
}
let mut reader = match csv::ReaderBuilder::new().from_path(path) {
Ok(rdr) => rdr,
Err(e) => {
return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e));
}
};
let systems = reader.deserialize::<SystemSerde>();
for sys in systems {
let sys = sys.unwrap();
for name in &names {
best.entry(name.clone()).and_modify(|ent| {
if (exact) && (&sys.system == name) {
*ent = (1.0, Some(sys.clone().build()))
} else {
let d1 = strsim::normalized_levenshtein(&sys.system, &name);
let d2 = strsim::normalized_levenshtein(&sys.body, &name);
if d1 > ent.0 {
*ent = (d1, Some(sys.clone().build()))
} else if d2 > ent.0 {
*ent = (d2, Some(sys.clone().build()))
}
}
});
}
}
Ok(best)
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct TreeNode {
pub id: u32,
pub pos: [f32; 3],
pub mult: f32,
}
impl TreeNode {
pub fn get(&self, router: &Router) -> Option<System> {
let mut cache = router.cache.as_ref().unwrap().lock().unwrap();
cache.get(self.id)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, IntoPyObject)]
pub struct SystemSerde {
pub id: u32,
pub star_type: String,
pub system: String,
pub body: String,
pub mult: f32,
pub distance: f32,
pub x: f32,
pub y: f32,
pub z: f32,
}
impl SystemSerde {
pub fn build(self) -> System {
System {
id: self.id,
star_type: self.star_type,
system: self.system,
body: self.body,
mult: self.mult,
distance: self.distance,
pos: [self.x, self.y, self.z],
}
}
pub fn to_node(&self) -> TreeNode {
TreeNode {
id: self.id,
pos: [self.x, self.y, self.z],
mult: self.mult,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct System {
pub id: u32,
pub star_type: String,
pub system: String,
pub body: String,
pub mult: f32,
pub distance: f32,
pub pos: [f32; 3],
}
impl ToPyObject for System {
fn to_object(&self, py: Python) -> PyObject {
let pos = PyTuple::new(py, self.pos.iter());
let elem = PyDict::new(py);
elem.set_item("star_type", self.star_type.clone()).unwrap();
elem.set_item("system", self.system.clone()).unwrap();
elem.set_item("body", self.body.clone()).unwrap();
elem.set_item("distance", self.distance).unwrap();
elem.set_item("mult", self.mult).unwrap();
elem.set_item("id", self.id).unwrap();
elem.set_item("pos", pos).unwrap();
elem.to_object(py)
}
}
impl System {
pub fn to_node(&self) -> TreeNode {
TreeNode {
id: self.id,
pos: self.pos,
mult: self.mult,
}
}
}
impl Ord for System {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for System {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}