#![doc = include_str!("../README.md")]
#[derive(Debug)]
pub struct Characters {
pub names: Vec<&'static str>,
pub costs: Vec<usize>,
}
macro_rules! load_csv {
($path:tt) => {{
let mut characters: Vec<&str> = Vec::new();
let costs: Vec<usize> = include_str!($path)
.lines()
.enumerate()
.filter_map(|(line_index, line_value)| {
if line_index != 0 {
Some(
line_value
.split(',')
.map(|comma_value| comma_value.parse::<usize>().unwrap())
.collect::<Vec<usize>>(),
)
} else {
characters = line_value.split(',').collect();
None
}
})
.into_iter()
.flatten()
.collect();
Characters {
names: characters,
costs,
}
}};
}
#[derive(Debug)]
pub struct Database {
pub characters: Characters,
pub max_distance_size: usize,
}
impl Default for Database {
fn default() -> Self {
Self {
characters: load_csv!("./../docs/assets/csv/characters.csv"),
max_distance_size: 255,
}
}
}
impl Database {
pub fn get_distance(&self, from: &str, to: &str) -> u8 {
let index_x = match self.characters.names.iter().position(|&r| r == from) {
Some(i) => i,
None => return self.max_distance_size as u8,
};
let index_y = match self.characters.names.iter().position(|&r| r == to) {
Some(i) => i,
None => return self.max_distance_size as u8,
};
match self.characters.costs[index_y + (index_x * self.characters.names.len())] {
i if self.max_distance_size < i => self.max_distance_size as u8,
i => i as u8,
}
}
pub fn get_word_distance(&self, str1: &str, str2: &str) -> usize {
let table_x_size = str1.chars().count() + 1;
let table_y_size = str2.chars().count() + 1;
let mut table = vec![0; table_x_size * table_y_size];
for (i, item) in table.iter_mut().enumerate().take(table_x_size) {
*item = i * self.max_distance_size;
}
for i in 0..table_y_size {
table[i * (table_x_size)] = i * self.max_distance_size;
}
for i in 1..table_y_size {
for j in 1..table_x_size {
let up = table[j + ((i - 1) * table_x_size)] + self.max_distance_size;
let left = table[j + (i * table_x_size) - 1] + self.max_distance_size;
let upper_left = {
let char1 = str1.chars().nth(j - 1).unwrap();
let char2 = str2.chars().nth(i - 1).unwrap();
let c = if char1 == char2 {
0
} else {
self.get_distance(&char1.to_string(), &char2.to_string()) as usize
};
table[j + ((i - 1) * table_x_size) - 1] + c
};
table[j + (i * table_x_size)] = std::cmp::min(std::cmp::min(up, left), upper_left);
}
}
table[(table_x_size * table_y_size) - 1]
}
}
pub fn new() -> Database {
Database::default()
}
pub mod search;