use crate::prelude::*;
use bevy::{
platform::collections::{HashMap, HashSet},
prelude::*,
};
const SECTOR_BOUNDARY_PORTAL_PORTAL_DISTANCE: i32 = 1;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Default, Reflect, Debug, Clone, Copy)]
struct Node {
sector_id: SectorID,
portal_cell: FieldCell,
weight: u8,
side: Ordinal,
}
impl Node {
fn new(sector_id: SectorID, portal_cell: FieldCell, weight: u8, side: Ordinal) -> Self {
Node {
sector_id,
portal_cell,
weight,
side,
}
}
fn get_sector(&self) -> &SectorID {
&self.sector_id
}
fn get_portal_cell(&self) -> &FieldCell {
&self.portal_cell
}
fn get_weight(&self) -> u8 {
self.weight
}
fn get_side(&self) -> &Ordinal {
&self.side
}
fn is_in_sector(&self, compare: &SectorID) -> bool {
self.sector_id == *compare
}
}
impl PartialEq for Node {
fn eq(&self, other: &Self) -> bool {
self.sector_id == other.sector_id
&& self.portal_cell == other.portal_cell
&& self.side == other.side
}
}
impl Eq for Node {}
impl std::hash::Hash for Node {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.sector_id.hash(state);
self.portal_cell.hash(state);
}
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Default, Reflect, Debug, Clone)]
struct Edge {
from: Node,
to: Node,
distance: i32,
}
impl Edge {
fn new(from: Node, to: Node, distance: i32) -> Self {
Edge { from, to, distance }
}
fn get_from(&self) -> &Node {
&self.from
}
fn get_to(&self) -> &Node {
&self.to
}
fn get_distance(&self) -> i32 {
self.distance
}
}
impl PartialEq for Edge {
fn eq(&self, other: &Self) -> bool {
self.from == other.from && self.to == other.to
}
}
impl Eq for Edge {}
impl std::hash::Hash for Edge {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.from.hash(state);
self.to.hash(state);
}
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Component, Default, Reflect, Debug, Clone)]
#[reflect(Component)]
pub struct PortalGraph {
nodes: HashSet<Node>,
edges_internal: HashSet<Edge>,
edges_external: HashSet<Edge>,
}
impl PortalGraph {
fn get_nodes(&self) -> &HashSet<Node> {
&self.nodes
}
fn add_node(&mut self, node: Node) {
self.nodes.insert(node);
}
fn remove_node(&mut self, node: &Node) {
let mut edges_to_remove_int = vec![];
for edge in &self.edges_internal {
if edge.from == *node || edge.to == *node {
edges_to_remove_int.push(edge.clone());
}
}
let mut edges_to_remove_ext = vec![];
for edge in &self.edges_external {
if edge.from == *node || edge.to == *node {
edges_to_remove_ext.push(edge.clone());
}
}
for edge in edges_to_remove_int.iter() {
self.remove_edge_internal(edge);
}
for edge in edges_to_remove_ext.iter() {
self.remove_edge_external(edge);
}
self.nodes.remove(node);
}
fn get_edges_internal(&self) -> &HashSet<Edge> {
&self.edges_internal
}
fn get_edges_external(&self) -> &HashSet<Edge> {
&self.edges_external
}
fn add_edge_internal(&mut self, edge: Edge) {
self.edges_internal.insert(edge);
}
fn add_edge_external(&mut self, edge: Edge) {
self.edges_external.insert(edge);
}
fn remove_edge_internal(&mut self, edge: &Edge) {
self.edges_internal.remove(edge);
}
fn remove_edge_external(&mut self, edge: &Edge) {
self.edges_external.remove(edge);
}
}
impl PortalGraph {
pub fn new(
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
map_dimensions: &MapDimensions,
) -> Self {
let mut graph = PortalGraph::default();
graph.create_all_nodes(sector_portals, sector_cost_fields);
graph.create_all_internal_edges(sector_portals, sector_cost_fields);
graph.create_all_external_edges(sector_portals, sector_cost_fields, map_dimensions);
graph
}
fn create_all_nodes(
&mut self,
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
) {
let portals_map = sector_portals.get();
for (sector_id, portals) in portals_map {
self.create_sector_nodes(sector_cost_fields, sector_id, portals);
}
}
fn create_sector_nodes(
&mut self,
sector_cost_fields: &SectorCostFields,
sector_id: &SectorID,
portals: &Portals,
) {
let ords = [Ordinal::North, Ordinal::East, Ordinal::South, Ordinal::West];
for ord in ords.iter() {
for cell in portals.get(ord).iter() {
let weight = sector_cost_fields
.get_scaled()
.get(sector_id)
.unwrap()
.get_field_cell_value(*cell);
let portal_node = Node::new(*sector_id, *cell, weight, *ord);
self.add_node(portal_node);
}
}
}
fn create_all_internal_edges(
&mut self,
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
) {
for (sector_id, portals) in sector_portals.get() {
let cost_field = sector_cost_fields.get_scaled().get(sector_id).unwrap();
self.create_sector_internal_edges(sector_id, cost_field, portals);
}
}
fn create_sector_internal_edges(
&mut self,
sector_id: &SectorID,
cost_field: &CostField,
portals: &Portals,
) {
let ords = [Ordinal::North, Ordinal::South, Ordinal::West, Ordinal::East];
let mut cells = vec![];
for ord in ords.iter() {
for cell in portals.get(ord).iter() {
cells.push((cell, ord));
}
}
for (i, (source, ord_source)) in cells.iter().enumerate() {
for (j, (target, ord_target)) in cells.iter().enumerate() {
if i != j {
if let Some(distance) = cost_field.get_distance_between_cells(source, target) {
let s_weight = cost_field.get_field_cell_value(**source);
let source_node = Node::new(*sector_id, **source, s_weight, **ord_source);
let t_weight = cost_field.get_field_cell_value(**target);
let target_node = Node::new(*sector_id, **target, t_weight, **ord_target);
let edge = Edge::new(source_node, target_node, distance);
self.add_edge_internal(edge);
}
}
}
}
}
fn create_all_external_edges(
&mut self,
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
map_dimensions: &MapDimensions,
) {
for (sector_id, portals) in sector_portals.get() {
let sector_neighbours =
map_dimensions.get_ordinal_and_ids_of_neighbouring_sectors(sector_id);
self.create_sector_external_edges(
sector_portals,
sector_cost_fields,
sector_id,
portals,
§or_neighbours,
);
}
}
fn create_sector_external_edges(
&mut self,
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
sector_id: &SectorID,
portals: &Portals,
sector_neighbours: &[(Ordinal, SectorID)],
) {
for (ordinal, neighbour_id) in sector_neighbours.iter() {
let cost_field_source = sector_cost_fields.get_scaled().get(sector_id).unwrap();
let cost_field_target = sector_cost_fields.get_scaled().get(neighbour_id).unwrap();
let boundary_portals = portals.get(ordinal);
let neighbour_portals = sector_portals.get().get(neighbour_id).unwrap();
let neighbour_boundary_portals = neighbour_portals.get(&ordinal.inverse());
for (i, cell) in boundary_portals.iter().enumerate() {
let source_weight = cost_field_source.get_field_cell_value(*cell);
let source_node = Node::new(*sector_id, *cell, source_weight, *ordinal);
let neighbour_portal = neighbour_boundary_portals[i];
let target_weight = cost_field_target.get_field_cell_value(neighbour_portal);
let target_node = Node::new(
*neighbour_id,
neighbour_portal,
target_weight,
ordinal.inverse(),
);
let edge = Edge::new(
source_node,
target_node,
SECTOR_BOUNDARY_PORTAL_PORTAL_DISTANCE,
);
self.add_edge_external(edge);
}
}
}
}
impl PortalGraph {
pub fn update_graph(
&mut self,
changed_sector: SectorID,
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
map_dimensions: &MapDimensions,
) -> &mut Self {
let sectors_to_rebuild =
map_dimensions.get_ordinal_and_ids_of_neighbouring_sectors(&changed_sector);
let mut nodes_to_remove = vec![];
let original_graph = self.clone();
for n in original_graph.get_nodes().iter() {
if n.is_in_sector(&changed_sector) {
nodes_to_remove.push(n);
}
}
for (ord, sector) in sectors_to_rebuild.iter() {
let neighbours_boundary_ord = ord.inverse();
for n in original_graph.get_nodes().iter() {
if n.is_in_sector(sector) && *n.get_side() == neighbours_boundary_ord {
nodes_to_remove.push(n);
}
}
}
for n in nodes_to_remove {
self.remove_node(n);
}
let portals = sector_portals.get().get(&changed_sector).unwrap();
self.create_sector_nodes(sector_cost_fields, &changed_sector, portals);
for (_ord, sector) in sectors_to_rebuild.iter() {
let portals = sector_portals.get().get(sector).unwrap();
self.create_sector_nodes(sector_cost_fields, sector, portals);
}
let cost_field = sector_cost_fields
.get_scaled()
.get(&changed_sector)
.unwrap();
self.create_sector_internal_edges(&changed_sector, cost_field, portals);
for (_ord, sector) in sectors_to_rebuild.iter() {
let cost_field = sector_cost_fields.get_scaled().get(sector).unwrap();
let portals = sector_portals.get().get(sector).unwrap();
self.create_sector_internal_edges(sector, cost_field, portals);
}
let portals = sector_portals.get().get(&changed_sector).unwrap();
self.create_sector_external_edges(
sector_portals,
sector_cost_fields,
&changed_sector,
portals,
§ors_to_rebuild,
);
for (ord, neighbour_sector) in sectors_to_rebuild.iter() {
let portals = sector_portals.get().get(neighbour_sector).unwrap();
let orignal_sector = vec![(ord.inverse(), changed_sector)];
self.create_sector_external_edges(
sector_portals,
sector_cost_fields,
neighbour_sector,
portals,
&orignal_sector,
);
}
self
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
enum Direction {
Internal,
External,
}
impl Direction {
fn flip(self) -> Direction {
if self == Direction::Internal {
Direction::External
} else {
Direction::Internal
}
}
}
#[derive(Debug)]
struct AStarQueueItem {
current_node: Node,
score: i32,
node_history: Vec<Node>,
cumulative_distance: i32,
edge_direction: Direction,
}
impl AStarQueueItem {
fn new(
node: Node,
score: i32,
node_history: Vec<Node>,
cumulative_distance: i32,
edge_direction: Direction,
) -> Self {
AStarQueueItem {
current_node: node,
score,
node_history,
cumulative_distance,
edge_direction,
}
}
}
impl PortalGraph {
pub fn find_best_path(
&self,
source: (SectorID, FieldCell),
target: (SectorID, FieldCell),
sector_portals: &SectorPortals,
sector_cost_fields: &SectorCostFields,
) -> Option<Vec<(SectorID, FieldCell)>> {
let cost_fields_scaled = sector_cost_fields.get_scaled();
let source_sector_id = source.0;
let source_field_cell = source.1;
let source_weight = sector_cost_fields
.get_scaled()
.get(&source_sector_id)
.unwrap()
.get_field_cell_value(source_field_cell);
let mut source_portals = Vec::new();
let portals = sector_portals.get().get(&source_sector_id).unwrap();
let ords = [Ordinal::North, Ordinal::South, Ordinal::West, Ordinal::East];
for ord in ords.iter() {
for cell in portals.get(ord) {
let cost_field = cost_fields_scaled.get(&source_sector_id).unwrap();
if let Some(source_distance) =
cost_field.get_distance_between_cells(&source_field_cell, cell)
{
source_portals.push((*cell, *ord, source_distance));
}
}
}
let target_sector_id = target.0;
let target_field_cell = target.1;
let target_weight = cost_fields_scaled
.get(&target_sector_id)
.unwrap()
.get_field_cell_value(target_field_cell);
let mut target_portals = Vec::new();
let portals = sector_portals.get().get(&target_sector_id).unwrap();
let ords = [Ordinal::North, Ordinal::South, Ordinal::West, Ordinal::East];
for ord in ords.iter() {
for cell in portals.get(ord) {
let cost_field = cost_fields_scaled.get(&target_sector_id).unwrap();
if cost_field.is_cell_pair_reachable(target_field_cell, *cell) {
target_portals.push((*cell, *ord));
}
}
}
let mut best_path: Option<(i32, Vec<(SectorID, FieldCell)>)> = None;
if source_sector_id == target_sector_id {
if let Some(cost) = cost_fields_scaled
.get(&source_sector_id)
.unwrap()
.get_distance_between_cells(&source_field_cell, &target_field_cell)
{
best_path = Some((cost, vec![(target_sector_id, target_field_cell)]));
}
}
for (source_portal, source_ordinal, source_distance) in source_portals.iter() {
for (target_portal, target_ordinal) in target_portals.iter() {
let source_portal_node = Node::new(
source_sector_id,
*source_portal,
source_weight,
*source_ordinal,
);
let target_portal_node = Node::new(
target_sector_id,
*target_portal,
target_weight,
*target_ordinal,
);
self.find_path_between_sector_portals(
&mut best_path,
source_portal_node,
target_portal_node,
*source_distance,
);
}
}
if let Some((_score, p)) = best_path {
Some(p)
} else {
None
}
}
fn find_path_between_sector_portals(
&self,
best_path: &mut Option<(i32, Vec<(SectorID, FieldCell)>)>,
source_node: Node,
target_node: Node,
source_distance: i32,
) {
let current_best_score = if let Some((score, _)) = best_path {
Some(*score)
} else {
None
};
if let Some(path) = self.astar(
current_best_score,
source_node,
target_node,
source_distance,
) {
let total_weight = path.0;
let mut p = Vec::new();
for node in path.1 {
p.push((*node.get_sector(), *node.get_portal_cell()));
}
if let Some((score, curr_path)) = best_path {
if *score > total_weight {
*score = total_weight;
*curr_path = p;
}
} else {
*best_path = Some((total_weight, p));
}
}
}
fn find_edges_internal(&self, source: Node) -> Vec<&Edge> {
let mut edges = vec![];
for edge in self.get_edges_internal().iter() {
if *edge.get_from().get_sector() == *source.get_sector()
&& *edge.get_to().get_sector() == *source.get_sector()
&& *edge.get_from().get_portal_cell() == *source.get_portal_cell()
{
edges.push(edge);
}
}
edges
}
fn find_edges_external(&self, source: Node) -> Vec<&Edge> {
let mut edges = vec![];
for edge in self.get_edges_external().iter() {
if *edge.get_from() == source && *edge.get_to().get_sector() != *source.get_sector() {
edges.push(edge);
}
}
edges
}
fn astar(
&self,
current_best_score: Option<i32>,
source_node: Node,
target_node: Node,
source_distance: i32,
) -> Option<(i32, Vec<Node>)> {
let nodes = self.get_nodes();
if !nodes.contains(&source_node) {
error!("Node data does not contain start node {:?}, this is probably a bug, please report it", source_node);
return None;
}
if !nodes.contains(&target_node) {
error!("Node data does not contain end node {:?}, this is probably a bug, please report it", target_node);
return None;
}
let start_weight: i32 = source_node.get_weight() as i32;
let mut node_astar_scores: HashMap<Node, i32> = HashMap::new();
node_astar_scores.insert(source_node, start_weight);
let initial_edge_direction = Direction::External;
let mut queue = vec![AStarQueueItem::new(
source_node,
start_weight,
Vec::<Node>::new(),
source_distance,
initial_edge_direction,
)];
while queue[0].current_node != target_node {
let current_path = queue.swap_remove(0);
if let Some(curr_score) = current_best_score {
if curr_score < current_path.score {
return None;
}
}
let edge_direction = current_path.edge_direction;
let neighbours = match edge_direction {
Direction::Internal => self.find_edges_internal(current_path.current_node),
Direction::External => self.find_edges_external(current_path.current_node),
};
for n in neighbours.iter() {
let distance_traveled_so_far: i32 = current_path.cumulative_distance;
let distance_to_this_neighbour: i32 = n.get_distance();
let distance_traveled = distance_traveled_so_far + distance_to_this_neighbour;
let node_weight: i32 = n.get_to().get_weight() as i32;
let astar_score = distance_traveled + node_weight;
let mut previous_nodes_traversed = current_path.node_history.clone();
previous_nodes_traversed.push(current_path.current_node);
if node_astar_scores.contains_key(n.get_to()) {
if node_astar_scores.get(n.get_to()) > Some(&astar_score) {
node_astar_scores.insert(*n.get_to(), astar_score);
let mut new_queue_item_required_for_node = true;
for q in queue.iter_mut() {
if q.current_node == *n.get_to() {
if q.score >= astar_score {
new_queue_item_required_for_node = false;
q.score = astar_score;
q.node_history.clone_from(&previous_nodes_traversed);
q.cumulative_distance = distance_traveled;
q.edge_direction = edge_direction.flip();
}
}
}
if new_queue_item_required_for_node {
queue.push(AStarQueueItem::new(
*n.get_to(),
astar_score,
previous_nodes_traversed,
distance_traveled,
edge_direction.flip(),
));
}
}
} else {
node_astar_scores.insert(*n.get_to(), astar_score);
queue.push(AStarQueueItem::new(
*n.get_to(),
astar_score,
previous_nodes_traversed,
distance_traveled,
edge_direction.flip(),
));
}
}
queue.sort_by(|a, b| a.score.partial_cmp(&b.score).unwrap());
if queue.is_empty() {
return None;
}
}
let score = queue[0].score;
let mut best_path = queue[0].node_history.clone();
best_path.push(target_node);
Some((score, best_path))
}
}
#[rustfmt::skip]
#[cfg(test)]
mod tests {
use crate::flowfields::sectors::sector_cost::SectorCostFields;
use super::*;
#[test]
fn node_count_default() {
let map_dimensions = MapDimensions::new(30, 30, 10, 0.5);
let sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let mut graph = PortalGraph::default();
graph.create_all_nodes(§or_portals, §or_cost_fields);
let result = graph.get_nodes().len();
let actual = 24; assert_eq!(actual, result);
}
#[test]
fn edge_count_internal() {
let map_dimensions = MapDimensions::new(30, 30, 10, 0.5);
let sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let mut graph = PortalGraph::default();
graph.create_all_nodes(§or_portals, §or_cost_fields);
graph.create_all_internal_edges(§or_portals, §or_cost_fields);
let result = graph.get_edges_internal().len();
let actual = 44; assert_eq!(actual, result);
}
#[test]
fn edge_count_external() {
let map_dimensions = MapDimensions::new(30, 30, 10, 0.5);
let sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let result = graph.get_edges_external().len();
let actual = 24;
assert_eq!(actual, result);
}
#[test]
fn edge_count_default() {
let map_dimensions = MapDimensions::new(30, 30, 10, 0.5);
let sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let result_internal = graph.get_edges_internal().len();
let internal = 44; assert_eq!(internal, result_internal);
let result_external = graph.get_edges_external().len();
let external = 24; assert_eq!(external, result_external);
}
#[test]
fn node_count_mutation() {
let map_dimensions = MapDimensions::new(20, 20, 10, 0.5);
let mut sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let mut graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let mutated_sector_id = SectorID::new(0, 0);
let mutated_field_cell =FieldCell::new(4, 9);
let value = 255;
sector_cost_fields.set_field_cell_value(mutated_sector_id, value, mutated_field_cell, &map_dimensions);
sector_portals.update_portals(mutated_sector_id, §or_cost_fields, &map_dimensions);
println!("graph before {:?}", graph);
graph.update_graph(mutated_sector_id, §or_portals, §or_cost_fields, &map_dimensions);
let result = graph.get_nodes().len();
let actual = 10;
println!("graph {:?}", graph);
assert_eq!(actual, result);
}
#[test]
fn edge_count_mutation() {
let map_dimensions = MapDimensions::new(20, 20, 10, 0.5);
let mut sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let mut graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let mutated_sector_id = SectorID::new(0, 0);
let mutated_field_cell =FieldCell::new(4, 9);
let value = 255;
sector_cost_fields.set_field_cell_value(mutated_sector_id, value, mutated_field_cell, &map_dimensions);
sector_portals.update_portals(mutated_sector_id, §or_cost_fields, &map_dimensions);
graph.update_graph(mutated_sector_id, §or_portals, §or_cost_fields, &map_dimensions);
let result_internal = graph.get_edges_internal().len();
let internal = 16;
assert_eq!(internal, result_internal);
let result_external = graph.get_edges_external().len();
let external = 10;
assert_eq!(external, result_external);
}
#[test]
fn multi_mutation() {
let map_dimensions = MapDimensions::new(20, 20, 10, 0.5);
let mut sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let mut graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let mutated_sector_id = SectorID::new(0, 0);
let mutated_field_cell =FieldCell::new(8, 9);
let value = 255;
sector_cost_fields.set_field_cell_value(mutated_sector_id, value, mutated_field_cell, &map_dimensions);
sector_portals.update_portals(mutated_sector_id, §or_cost_fields, &map_dimensions);
graph.update_graph(mutated_sector_id, §or_portals, §or_cost_fields, &map_dimensions);
let mutated_sector_id = SectorID::new(1, 0);
let mutated_field_cell =FieldCell::new(0, 8);
let value = 255;
sector_cost_fields.set_field_cell_value(mutated_sector_id, value, mutated_field_cell, &map_dimensions);
sector_portals.update_portals(mutated_sector_id, §or_cost_fields, &map_dimensions);
graph.update_graph(mutated_sector_id, §or_portals, §or_cost_fields, &map_dimensions);
let result_nodes = graph.get_nodes().len();
let actual_nodes = 12;
println!("nodes actual {}, result {}", actual_nodes, result_nodes);
assert_eq!(actual_nodes, result_nodes);
let result_internal = graph.get_edges_internal().len();
let actual_edges_internal = 26;
println!("edges_internal actual {},, result {}", actual_edges_internal, result_internal);
assert_eq!(actual_edges_internal, result_internal);
let result_external = graph.get_edges_external().len();
let actual_edges_external = 12;
println!("edges_external actual {}, result {}", actual_edges_external, result_external);
println!("edges ext {:?}", graph.get_edges_external());
assert_eq!(actual_edges_external, result_external);
}
#[test]
fn best_path_as_sector_portals() {
let map_dimensions = MapDimensions::new(30, 30, 10, 0.5);
let sector_cost_fields = SectorCostFields::new(&map_dimensions);
let mut sector_portals = SectorPortals::new(map_dimensions.get_length(), map_dimensions.get_depth(), map_dimensions.get_sector_resolution());
for (sector_id, _cost_fields) in sector_cost_fields.get_scaled().iter() {
let portals = sector_portals.get_mut();
match portals.get_mut(sector_id) {
Some(portals) => portals.recalculate_portals(§or_cost_fields, sector_id, &map_dimensions),
None => panic!("Key {:?} not found in Portals", sector_id),
}
}
let graph = PortalGraph::new(§or_portals, §or_cost_fields, &map_dimensions);
let source_sector = SectorID::new(0, 0);
let source_field = FieldCell::new(4, 9);
let source_weight = sector_cost_fields.get_scaled().get(&source_sector).unwrap().get_field_cell_value(source_field);
let source_portal_node = Node::new(source_sector, source_field, source_weight, Ordinal::South) ;
let target_sector = SectorID::new(0, 2);
let target_field = FieldCell::new(4, 0);
let target_weight = sector_cost_fields.get_scaled().get(&target_sector).unwrap().get_field_cell_value(target_field);
let target_portal_node = Node::new(target_sector, target_field, target_weight, Ordinal::North);
let mut best_path: Option<(i32, Vec<(SectorID, FieldCell)>)> = None;
graph.find_path_between_sector_portals(&mut best_path, source_portal_node, target_portal_node, 0);
let actual = vec![(SectorID::new(0, 0), FieldCell::new(4, 9)), (SectorID::new(0, 1), FieldCell::new(4, 0)), (SectorID::new(0, 1), FieldCell::new(4, 9)), (SectorID::new(0, 2), FieldCell::new(4, 0))];
assert_eq!(actual, best_path.unwrap().1);
}
}