2019-08-04 22:05:44 +00:00
|
|
|
extern crate strsim;
|
2019-07-14 22:43:57 +00:00
|
|
|
mod common;
|
|
|
|
mod preprocess;
|
|
|
|
mod route;
|
2019-08-04 22:05:44 +00:00
|
|
|
use std::collections::HashMap;
|
2019-07-21 23:55:38 +00:00
|
|
|
use pyo3::exceptions::*;
|
2019-08-04 22:05:44 +00:00
|
|
|
use pyo3::prelude::*;
|
|
|
|
use pyo3::types::{PyDict, PyList};
|
2019-07-14 22:43:57 +00:00
|
|
|
use std::path::PathBuf;
|
2019-08-04 22:05:44 +00:00
|
|
|
use common::{System,SystemSerde};
|
|
|
|
|
|
|
|
fn find_matches(path:&PathBuf,names:Vec<String>) -> Result<HashMap<String,(f64,Option<System>)>,String> {
|
|
|
|
let mut best: HashMap<String,(f64,Option<System>)> = HashMap::new();
|
|
|
|
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).to_string());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let systems=reader
|
|
|
|
.deserialize::<SystemSerde>();
|
|
|
|
for sys in systems {
|
|
|
|
let sys=sys.unwrap();
|
|
|
|
for name in &names {
|
|
|
|
best.entry(name.clone()).and_modify(|ent| {
|
|
|
|
let d1=strsim::normalized_levenshtein(&sys.system,&name);
|
|
|
|
if d1>ent.0 {
|
|
|
|
*ent=(d1,Some(sys.build()))
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ok(best);
|
|
|
|
}
|
2019-07-14 22:43:57 +00:00
|
|
|
|
|
|
|
#[pymodule]
|
2019-07-21 23:55:38 +00:00
|
|
|
pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> {
|
2019-07-14 22:43:57 +00:00
|
|
|
/// preprocess(infile_systems, infile_bodies, outfile, callback)
|
2019-07-21 23:55:38 +00:00
|
|
|
/// --
|
2019-07-14 22:43:57 +00:00
|
|
|
///
|
|
|
|
/// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv
|
|
|
|
#[pyfn(m, "preprocess")]
|
2019-07-21 23:55:38 +00:00
|
|
|
fn ed_lrr_preprocess(
|
|
|
|
py: Python<'static>,
|
|
|
|
infile_systems: String,
|
|
|
|
infile_bodies: String,
|
|
|
|
outfile: String,
|
|
|
|
callback: PyObject,
|
|
|
|
) -> PyResult<PyObject> {
|
|
|
|
use preprocess::*;
|
2019-07-14 22:43:57 +00:00
|
|
|
let state = PyDict::new(py);
|
2019-07-21 23:55:38 +00:00
|
|
|
let state_dict = PyDict::new(py);
|
2019-08-04 22:05:44 +00:00
|
|
|
callback.call(py, (state_dict,), None).unwrap();
|
2019-07-21 23:55:38 +00:00
|
|
|
let callback_wrapped = move |state: &PreprocessState| {
|
|
|
|
// println!("SEND: {:?}",state);
|
2019-08-04 22:05:44 +00:00
|
|
|
state_dict.set_item("file", state.file.clone())?;
|
|
|
|
state_dict.set_item("total", state.total)?;
|
|
|
|
state_dict.set_item("count", state.count)?;
|
|
|
|
state_dict.set_item("done", state.done)?;
|
|
|
|
state_dict.set_item("message", state.message.clone())?;
|
|
|
|
callback.call(py, (state_dict,), None)
|
2019-07-21 23:55:38 +00:00
|
|
|
};
|
2019-08-04 22:05:44 +00:00
|
|
|
preprocess_files(
|
|
|
|
&PathBuf::from(infile_bodies),
|
|
|
|
&PathBuf::from(infile_systems),
|
|
|
|
&PathBuf::from(outfile),
|
|
|
|
Box::new(callback_wrapped),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
Ok(state.to_object(py))
|
|
|
|
}
|
|
|
|
|
|
|
|
///find_sys(sys_names,sys_list)
|
|
|
|
/// --
|
|
|
|
///
|
|
|
|
/// Find system by name
|
|
|
|
#[pyfn(m, "find_sys")]
|
|
|
|
fn find_sys(py:Python,sys_names:Vec<String>,sys_list:String) -> PyResult<PyObject> {
|
|
|
|
let path=PathBuf::from(sys_list);
|
|
|
|
match find_matches(&path,sys_names) {
|
|
|
|
Ok(vals) => {
|
|
|
|
let ret=PyDict::new(py);
|
|
|
|
for (key,(diff,sys)) in vals {
|
|
|
|
let ret_dict=PyDict::new(py);
|
|
|
|
if let Some(val)= sys {
|
|
|
|
let pos = PyList::new(py, val.pos.iter());
|
|
|
|
ret_dict.set_item("star_type", val.star_type.clone())?;
|
|
|
|
ret_dict.set_item("system", val.system.clone())?;
|
|
|
|
ret_dict.set_item("body", val.body.clone())?;
|
|
|
|
ret_dict.set_item("distance", val.distance)?;
|
|
|
|
ret_dict.set_item("pos", pos)?;
|
|
|
|
ret_dict.set_item("id", val.id)?;
|
|
|
|
ret.set_item(key,(diff,ret_dict).to_object(py))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ok(ret.to_object(py));
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
return Err(PyErr::new::<ValueError, _>(e));
|
|
|
|
}
|
|
|
|
}
|
2019-07-14 22:43:57 +00:00
|
|
|
}
|
|
|
|
|
2019-08-04 22:05:44 +00:00
|
|
|
/// route(infile, hops, range, radius_mult, mode,primary, greedyness, precomp, callback)
|
2019-07-14 22:43:57 +00:00
|
|
|
/// --
|
|
|
|
///
|
|
|
|
/// Compute a Route using the suplied parameters
|
|
|
|
#[pyfn(m, "route")]
|
2019-08-04 22:05:44 +00:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-07-21 23:55:38 +00:00
|
|
|
fn route(
|
|
|
|
py: Python<'static>,
|
|
|
|
hops: Vec<String>,
|
|
|
|
range: f32,
|
2019-08-04 22:05:44 +00:00
|
|
|
radius_mult: f32,
|
2019-07-21 23:55:38 +00:00
|
|
|
mode: String,
|
|
|
|
primary: bool,
|
|
|
|
permute: bool,
|
2019-08-04 22:05:44 +00:00
|
|
|
keep_first: bool,
|
|
|
|
keep_last: bool,
|
2019-07-21 23:55:38 +00:00
|
|
|
greedyness: Option<f32>,
|
|
|
|
precomp: Option<String>,
|
|
|
|
path: String,
|
|
|
|
callback: PyObject,
|
|
|
|
) -> PyResult<PyObject> {
|
|
|
|
use route::*;
|
|
|
|
let mode = match Mode::parse(&mode) {
|
|
|
|
Ok(val) => val,
|
|
|
|
Err(e) => {
|
2019-08-04 22:05:44 +00:00
|
|
|
return Err(PyErr::new::<ValueError, _>(e));
|
2019-07-21 23:55:38 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let state_dict = PyDict::new(py);
|
2019-08-04 22:05:44 +00:00
|
|
|
callback.call(py, (state_dict,), None).unwrap();
|
2019-07-21 23:55:38 +00:00
|
|
|
let callback_wrapped = move |state: &SearchState| {
|
2019-08-04 22:05:44 +00:00
|
|
|
state_dict.set_item("mode", state.mode.clone())?;
|
|
|
|
state_dict.set_item("system", state.system.clone())?;
|
|
|
|
state_dict.set_item("body", state.body.clone())?;
|
|
|
|
state_dict.set_item("depth", state.depth)?;
|
|
|
|
state_dict.set_item("queue_size", state.queue_size)?;
|
|
|
|
state_dict.set_item("d_rem", state.d_rem)?;
|
|
|
|
state_dict.set_item("d_total", state.d_total)?;
|
|
|
|
state_dict.set_item("prc_done", state.prc_done)?;
|
|
|
|
state_dict.set_item("n_seen", state.n_seen)?;
|
|
|
|
state_dict.set_item("prc_seen", state.prc_seen)?;
|
|
|
|
callback.call(py, (state_dict,), None)
|
2019-07-21 23:55:38 +00:00
|
|
|
};
|
2019-08-04 22:05:44 +00:00
|
|
|
let mut systems=Vec::new();
|
|
|
|
for sys in hops {
|
|
|
|
systems.push(route::SysEntry::parse(&sys))
|
|
|
|
}
|
|
|
|
println!("SYSTEMS: {:?}",systems);
|
|
|
|
let opts = RouteOpts {
|
|
|
|
systems,
|
|
|
|
range: Some(range),
|
2019-07-21 23:55:38 +00:00
|
|
|
file_path: PathBuf::from(path),
|
|
|
|
precomp_file: precomp.map(PathBuf::from),
|
|
|
|
callback: Box::new(callback_wrapped),
|
|
|
|
mode,
|
|
|
|
factor: greedyness,
|
|
|
|
precompute: false,
|
2019-08-04 22:05:44 +00:00
|
|
|
permute,
|
|
|
|
keep_first,
|
|
|
|
keep_last,
|
|
|
|
primary,
|
|
|
|
radius_mult
|
2019-07-21 23:55:38 +00:00
|
|
|
};
|
2019-08-04 22:05:44 +00:00
|
|
|
let none = ().to_object(py);
|
2019-07-21 23:55:38 +00:00
|
|
|
match route(opts) {
|
|
|
|
Ok(Some(route)) => {
|
2019-08-04 22:05:44 +00:00
|
|
|
let hops = route.iter().map(|hop| {
|
|
|
|
let pos = PyList::new(py, hop.pos.iter());
|
|
|
|
let elem = PyDict::new(py);
|
|
|
|
elem.set_item("star_type", hop.star_type.clone()).unwrap();
|
|
|
|
elem.set_item("system", hop.system.clone()).unwrap();
|
|
|
|
elem.set_item("body", hop.body.clone()).unwrap();
|
|
|
|
elem.set_item("distance", hop.distance).unwrap();
|
|
|
|
elem.set_item("pos", pos).unwrap();
|
|
|
|
elem
|
2019-07-21 23:55:38 +00:00
|
|
|
});
|
2019-08-04 22:05:44 +00:00
|
|
|
let lst = PyList::new(py, hops);
|
|
|
|
Ok(lst.to_object(py))
|
2019-07-21 23:55:38 +00:00
|
|
|
}
|
2019-08-04 22:05:44 +00:00
|
|
|
Ok(None) => Ok(none),
|
|
|
|
Err(e) => Err(PyErr::new::<ValueError, _>(e)),
|
|
|
|
}
|
2019-07-14 22:43:57 +00:00
|
|
|
}
|
|
|
|
Ok(())
|
2019-07-21 23:55:38 +00:00
|
|
|
}
|