Hi All, I have some working code but would be interested in suggestions on how to make it more idiomatic and/or cleaner. The algorithm is that I build the union of sets and then take the intersection of that large set with another, smaller set. It feels like I should be able to use the Union and Intersection structures more cleanly rather than my current, verbose "iterate and insert into a temporary set" code.
// Build a set of all the tiles that are illuminated in the map
let mut illuminated_tiles = HashSet::new();
let mut query_light = <(&Point, &FieldOfLight)>::query();
query_light.iter(ecs)
.for_each(|(pt, fol)| {
let lit_tiles = field_of_view_set(*pt, fol.radius, map);
// illuminated_tiles = illuminated_tiles.union(&lit_tiles).collect::<HashSet<Point>>();
for pt in lit_tiles.into_iter() {
illuminated_tiles.insert(pt);
}
});
// The viewable tiles is the intersection between the actors
// view radius and the set of illuminated tiles
let mut query_view = <(&Point, &mut FieldOfView)>::query();
query_view.iter_mut(ecs)
.filter(|(_, fov)| fov.is_dirty )
.for_each(|(pt, fov)| {
let pt = *pt;
let view_set = field_of_view_set(pt, fov.radius, map);
let intersection = illuminated_tiles.intersection(&view_set);
let mut view_set = HashSet::new();
for pt in intersection {
view_set.insert(*pt);
}
fov.visible_tiles = view_set;
fov.is_dirty = false;
});
// Build a set of all the tiles that are illuminated in the map
let mut query_light = <(&Point, &FieldOfLight)>::query();
let illuminated_tiles = query_light
.iter(ecs)
.flat_map(|(pt, fol)| field_of_view_set(*pt, fol.radius, map))
.collect::<HashSet<_>>();
This worked perfectly and seems very clean. The other solution (using extend) also worked. If you were doing a code review would you prefer one over the other?
EDIT: wish I could mark more than one response as the Solution.
That worked too. I feel a little dumb missing the & operator on HashSet. I assumed the default behavior of intersection would do what this does. Thank you.
EDIT: after refactors the code looks like the following. The & looks a little magical to me (something I'd expect to see in ruby) but I'll get used to it.
// Build a set of all the tiles that are illuminated in the map
let mut query_light = <(&Point, &FieldOfLight)>::query();
let illuminated_tiles = query_light.iter(ecs)
.flat_map(|(pt, fol)| field_of_view_set(*pt, fol.radius, map))
.collect::<HashSet<_>>();
// The viewable tiles is the intersection between the actors
// view radius and the set of illuminated tiles
let mut query_view = <(&Point, &mut FieldOfView)>::query();
query_view.iter_mut(ecs)
.filter(|(_, fov)| fov.is_dirty )
.for_each(|(pt, fov)| {
fov.visible_tiles = &illuminated_tiles & &field_of_view_set(*pt, fov.radius, map);
fov.is_dirty = false;
});