Skip to content

Commit

Permalink
Fix for field_of_movement algorithm (#142)
Browse files Browse the repository at this point in the history
> Adresses #127
  • Loading branch information
ManevilleF authored Jan 31, 2024
1 parent 5663143 commit 5bd6d49
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

* (**BREAKING**) `a_star` `cost` function parameter now takes two adjacent `Hex`
nodes instead of one, allowing for more use cases (#130, #128)
* Fixed `field_of_movement` algorithm (#142, #127)

### Dependencies

Expand Down
49 changes: 35 additions & 14 deletions src/algorithms/field_of_movement.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::Hex;
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
usize,
};

/// Computes a field of movement around `coord` given a `budget`.
/// This algorithm takes a `cost` function, which calculates and
Expand All @@ -13,6 +16,11 @@ use std::collections::{HashMap, HashSet};
/// in order to avoid the possibility of unlimited movement range (i.e. a `Hex`
/// instance will always have a minimum movement `cost` of 1).
///
/// # Warning
///
/// The implementation of this function is pretty naive and has a high
/// complexity. It is not suitable for production use
///
/// # Examples
///
/// - Compute field of movement with no boundaries and some wall tiles that
Expand Down Expand Up @@ -56,24 +64,37 @@ pub fn field_of_movement(
budget: u32,
cost: impl Fn(Hex) -> Option<u32>,
) -> HashSet<Hex> {
let mut computed_costs = HashMap::new();
let mut computed_costs = HashMap::with_capacity(Hex::range_count(budget) as usize);
computed_costs.insert(coord, 0);
(1..=budget)
.flat_map(|i| coord.ring(i))
.filter_map(|coord| {
let coord_cost = cost(coord)?;
let neighbor_cost = coord

// We cache the rings and costs
let rings: Vec<(Hex, u32)> = coord
.rings(1..=budget)
.flatten()
.filter_map(|h| cost(h).map(|c| (h, c)))
.collect();

let mut loop_again = true;
while loop_again {
loop_again = false;
for (coord, coord_cost) in &rings {
let Some(neighbor_cost) = coord
.all_neighbors()
.into_iter()
.filter_map(|n| computed_costs.get(&n))
.min()?;
.min()
else {
continue;
};
let computed_cost = coord_cost + 1 + neighbor_cost;
if computed_cost <= budget {
computed_costs.insert(coord, computed_cost);
Some(coord)
} else {
None
let res = computed_costs.insert(*coord, computed_cost);
if !loop_again && (res.is_none() || res != Some(computed_cost)) {
loop_again = true;
}
})
}
}
computed_costs
.into_iter()
.filter_map(|(coord, cost)| (cost <= budget).then_some(coord))
.collect()
}

0 comments on commit 5bd6d49

Please sign in to comment.