screeps_pathfinding/utils/
movement_costs.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4use screeps::constants::Terrain;
5use screeps::local::{LocalCostMatrix, LocalRoomTerrain};
6use screeps::{Position, RoomName, RoomXY};
7
8use super::cache::{LCMCache, TerrainCache};
9
10pub fn get_movement_cost_lcm_from_terrain(
11    room_terrain: &LocalRoomTerrain,
12    plain_cost: u8,
13    swamp_cost: u8,
14) -> LocalCostMatrix {
15    let mut cm = LocalCostMatrix::new();
16
17    for (xy, val) in cm.iter_mut() {
18        *val = match room_terrain.get_xy(xy) {
19            Terrain::Wall => u8::MAX,
20            Terrain::Plain => plain_cost,
21            Terrain::Swamp => swamp_cost,
22        }
23    }
24
25    cm
26}
27
28/// Builds a cost function closure that pulls costs from a `LocalCostMatrix`.
29///
30/// # Example
31/// ```rust
32/// use screeps::{LocalRoomTerrain, Position, RoomCoordinate, RoomXY};
33///
34/// let room_terrain = LocalRoomTerrain::new_from_bits(Box::new([0; 2500])); // Terrain that's all plains
35/// let plain_cost = 1;
36/// let swamp_cost = 5;
37/// let costs = screeps_pathfinding::utils::movement_costs::get_movement_cost_lcm_from_terrain(&room_terrain, plain_cost, swamp_cost);
38///
39/// let roomxy_costs_fn = screeps_pathfinding::utils::movement_costs::movement_costs_from_lcm(&costs);
40///
41/// let xy = RoomXY::checked_new(24, 18).unwrap();
42/// assert_eq!(roomxy_costs_fn(xy), plain_cost as u32);
43///
44/// let position_costs_fn = screeps_pathfinding::utils::movement_costs::movement_costs_from_lcm(&costs);
45///
46/// let pos = Position::new(
47///     RoomCoordinate::try_from(24).unwrap(),
48///     RoomCoordinate::try_from(18).unwrap(),
49///     "E5N6".parse().unwrap(),
50/// );
51/// assert_eq!(position_costs_fn(pos), plain_cost as u32);
52/// ```
53pub fn movement_costs_from_lcm<T>(lcm: &LocalCostMatrix) -> impl Fn(T) -> u32 + '_
54where
55    T: Into<RoomXY>,
56{
57    |xy| {
58        let value = lcm.get(xy.into());
59        match value {
60            u8::MAX => u32::MAX,
61            _ => value as u32,
62        }
63    }
64}
65
66/// Builds a cost function closure that pulls costs from a `LocalCostMatrix`.
67///
68/// # Example
69/// ```rust
70/// use screeps::{LocalRoomTerrain, Position, RoomCoordinate, RoomXY};
71///
72/// let room_terrain = LocalRoomTerrain::new_from_bits(Box::new([0; 2500])); // Terrain that's all plains
73/// let plain_cost = 1;
74/// let swamp_cost = 5;
75/// let costs = screeps_pathfinding::utils::movement_costs::get_movement_cost_lcm_from_terrain(&room_terrain, plain_cost, swamp_cost);
76///
77/// let roomxy_costs_fn = screeps_pathfinding::utils::movement_costs::astar_movement_costs_from_lcm(&costs);
78///
79/// let xy = RoomXY::checked_new(24, 18).unwrap();
80/// assert_eq!(roomxy_costs_fn(xy), Some(plain_cost as u32));
81///
82/// let position_costs_fn = screeps_pathfinding::utils::movement_costs::astar_movement_costs_from_lcm(&costs);
83///
84/// let pos = Position::new(
85///     RoomCoordinate::try_from(24).unwrap(),
86///     RoomCoordinate::try_from(18).unwrap(),
87///     "E5N6".parse().unwrap(),
88/// );
89/// assert_eq!(position_costs_fn(pos), Some(plain_cost as u32));
90/// ```
91pub fn astar_movement_costs_from_lcm<T>(lcm: &LocalCostMatrix) -> impl Fn(T) -> Option<u32> + '_
92where
93    T: Into<RoomXY>,
94{
95    |xy| {
96        let value = lcm.get(xy.into());
97        match value {
98            u8::MAX => None,
99            _ => Some(value as u32),
100        }
101    }
102}
103/// Utility function to create an LCM generation closure from a terrain cache and terrain costs.
104pub fn get_lcm_generation_closure_from_terrain_cache(
105    terrain_cache_ref: Rc<RefCell<TerrainCache>>,
106    plain_cost: u8,
107    swamp_cost: u8,
108    default_cost: u8,
109) -> impl Clone + Fn(&RoomName) -> LocalCostMatrix {
110    move |room_name: &RoomName| {
111        let mut cm = LocalCostMatrix::new_with_value(default_cost);
112
113        if let Ok(mut terrain_cache) = terrain_cache_ref.try_borrow_mut() {
114            if let Some(room_terrain) = terrain_cache.get_terrain(room_name) {
115                for (xy, val) in cm.iter_mut() {
116                    *val = match room_terrain.get_xy(xy) {
117                        Terrain::Wall => u8::MAX,
118                        Terrain::Plain => plain_cost,
119                        Terrain::Swamp => swamp_cost,
120                    }
121                }
122            }
123        }
124
125        cm
126    }
127}
128
129/// Utility function to create a movement costs closure from an LCM cache.
130pub fn movement_costs_from_lcm_cache<
131    'a,
132    'b,
133    F: Clone + Fn(&RoomName) -> LocalCostMatrix + 'a + 'b,
134>(
135    lcm_cache_ref: &'b RefCell<LCMCache>,
136    generator_fn: F,
137) -> impl Fn(Position) -> Option<u32> + 'b {
138    move |pos: Position| {
139        let mut lcm_cache = lcm_cache_ref.borrow_mut();
140        let lcm = lcm_cache.get_lcm(&pos.room_name(), generator_fn.clone());
141        let value = lcm.get(pos.into());
142        match value {
143            u8::MAX => None,
144            _ => Some(value as u32),
145        }
146    }
147}