fn generate_building_shapes<R: Rng>(rng: &mut R, grid: &SparseGrid<LandmassCell>) -> Vec<BuildingShape> {
  /// Finds the most optimal spot to place the next building if possible
  fn generate_next_building<R: Rng>(rng: &mut R, grid: &SparseGrid<Value>) -> Option<BuildingShape> {
    let size_x = rng.gen_range(MIN_BUILDING_SIZE..MAX_BUILDING_SIZE);
    let size_y = rng.gen_range(MIN_BUILDING_SIZE..MAX_BUILDING_SIZE);
    let size = IVec2::new(size_x as i32, size_y as i32);

    grid.cells()
      .filter_map(|(pos, _)| {
        let building = BuildingShape {
          edge_min: pos,
          edge_max: pos + size - IVec2::ONE
        };

        // The number of adjacent building cells is used to 'score'
        // each position when picking a spot to place the next building
        get_neighbor_count_if_vacant(grid, &building)
          .map(|n| (n, building))
      })
      .max_by_key(|e| e.0)
      .map(|(_, building)| building)
  }

  fn put_building_in_vacancy(grid: &mut SparseGrid<Value>, building: &BuildingShape, i: usize) {
    for x in building.edge_min.x..=building.edge_max.x {
      for y in building.edge_min.y..=building.edge_max.y {
        if let Some(value @ &mut Value::Vacant) = grid.get_mut(IVec2::new(x, y)) {
          *value = Value::Occupied(i);
        } else {
          panic!("`put_building_in_vacancy` requires that all positions be vacant");
        };
      };
    };
  }

  /// Returns the number of occupied cells around this building as long as all cells inside the building are vacant
  fn get_neighbor_count_if_vacant(grid: &SparseGrid<Value>, building: &BuildingShape) -> Option<usize> {
    let min = building.edge_min - IVec2::ONE;
    let max = building.edge_max + IVec2::ONE;
    let mut neighbor_count = 0;
    for x in min.x..=max.x {
      let is_edge_x = x == min.x || x == max.x;
      for y in min.y..=max.y {
        let is_edge_y = y == min.y || y == max.y;

        match (is_edge_x || is_edge_y, grid.get(IVec2::new(x, y))) {
          // If the current point is an edge (one block outside the building),
          // and it is occupied, then increment the neighbor count
          (true, Some(&Value::Occupied(_))) => neighbor_count += 1,
          // If the current point is not an edge (actually inside the building),
          // and it is not vacant then this building is not vacant, terminate
          (false, None | Some(&Value::Occupied(_))) => return None,
          // If the current point is an edge and is null, terminate
          // This is to prevent buildings from being placed right next to edges
          (true, None) => return None,
          _ => ()
        };
      };
    };

    Some(neighbor_count)
  }

  #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  enum Value {
    Vacant,
    Occupied(usize)
  }

  let mut grid = grid.cells()
    .filter_map(|(pos, _)| match ivec2_rem_euclid_2(pos) {
      true => Some((pos / 2, Value::Vacant)),
      false => None
    })
    .collect::<SparseGrid<Value>>();
  let mut i = 0;
  let mut buildings = Vec::new();
  while let Some(building) = generate_next_building(rng, &grid) {
    put_building_in_vacancy(&mut grid, &building, i);
    buildings.push(building);
    i += 1;
  };

  buildings
}
/// Populates the landmass with randomly sized buildings until it is completely full
Populates the landmass with randomly sized buildings until it is completely full
Populates the landmass with randomly sized buildings until it is completely full
fn generate_building_shapes<R: Rng>(rng: &mut R, grid: &SparseGrid<LandmassCell>) -> Vec<BuildingShape> {
  /// Finds the most optimal spot to place the next building if possible
  fn generate_next_building<R: Rng>(rng: &mut R, grid: &SparseGrid<Value>) -> Option<BuildingShape> {
    let size_x = rng.gen_range(MIN_BUILDING_SIZE..MAX_BUILDING_SIZE);
    let size_y = rng.gen_range(MIN_BUILDING_SIZE..MAX_BUILDING_SIZE);
    let size = IVec2::new(size_x as i32, size_y as i32);
    grid.cells()
      .filter_map(|(pos, _)| {
        let building = BuildingShape {
          edge_min: pos,
          edge_max: pos + size - IVec2::ONE
        };
        // The number of adjacent building cells is used to 'score'
        // each position when picking a spot to place the next building
        get_neighbor_count_if_vacant(grid, &building)
          .map(|n| (n, building))
      })
      .max_by_key(|e| e.0)
      .map(|(_, building)| building)
  }
  fn put_building_in_vacancy(grid: &mut SparseGrid<Value>, building: &BuildingShape, i: usize) {
    for x in building.edge_min.x..=building.edge_max.x {
      for y in building.edge_min.y..=building.edge_max.y {
        if let Some(value @ &mut Value::Vacant) = grid.get_mut(IVec2::new(x, y)) {
          *value = Value::Occupied(i);
        } else {
          panic!("`put_building_in_vacancy` requires that all positions be vacant");
        };
      };
    };
  }
  /// Returns the number of occupied cells around this building as long as all cells inside the building are vacant
  fn get_neighbor_count_if_vacant(grid: &SparseGrid<Value>, building: &BuildingShape) -> Option<usize> {
    let min = building.edge_min - IVec2::ONE;
    let max = building.edge_max + IVec2::ONE;
    let mut neighbor_count = 0;
    for x in min.x..=max.x {
      let is_edge_x = x == min.x || x == max.x;
      for y in min.y..=max.y {
        let is_edge_y = y == min.y || y == max.y;
        match (is_edge_x || is_edge_y, grid.get(IVec2::new(x, y))) {
          // If the current point is an edge (one block outside the building),
          // and it is occupied, then increment the neighbor count
          (true, Some(&Value::Occupied(_))) => neighbor_count += 1,
          // If the current point is not an edge (actually inside the building),
          // and it is not vacant then this building is not vacant, terminate
          (false, None | Some(&Value::Occupied(_))) => return None,
          // If the current point is an edge and is null, terminate
          // This is to prevent buildings from being placed right next to edges
          (true, None) => return None,
          _ => ()
        };
      };
    };
    Some(neighbor_count)
  }
  #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  enum Value {
    Vacant,
    Occupied(usize)
  }
  let mut grid = grid.cells()
    .filter_map(|(pos, _)| match ivec2_rem_euclid_2(pos) {
      true => Some((pos / 2, Value::Vacant)),
      false => None
    })
    .collect::<SparseGrid<Value>>();
  let mut i = 0;
  let mut buildings = Vec::new();
  while let Some(building) = generate_next_building(rng, &grid) {
    put_building_in_vacancy(&mut grid, &building, i);
    buildings.push(building);
    i += 1;
  };
  buildings
}
fn generate_building_shapes < R : Rng > ( rng : & mut R , grid : & SparseGrid < LandmassCell > ) -> Vec < BuildingShape > { /// Finds the most optimal spot to place the next building if possible fn generate_next_building < R : Rng > ( rng : & mut R , grid : & SparseGrid < Value > ) -> Option < BuildingShape > { let size_x = rng . gen_range ( MIN_BUILDING_SIZE .. MAX_BUILDING_SIZE ) ; let size_y = rng . gen_range ( MIN_BUILDING_SIZE .. MAX_BUILDING_SIZE ) ; let size = IVec2 :: new ( size_x as i32 , size_y as i32 ) ; grid . cells ( ) . filter_map ( | ( pos , _ ) | { let building = BuildingShape { edge_min : pos , edge_max : pos + size - IVec2 :: ONE } ; // The number of adjacent building cells is used to 'score' // each position when picking a spot to place the next building get_neighbor_count_if_vacant ( grid , & building ) . map ( | n | ( n , building ) ) } ) . max_by_key ( | e | e . 0 ) . map ( | ( _ , building ) | building ) } fn put_building_in_vacancy ( grid : & mut SparseGrid < Value > , building : & BuildingShape , i : usize ) { for x in building . edge_min . x ..= building . edge_max . x { for y in building . edge_min . y ..= building . edge_max . y { if let Some ( value @ & mut Value :: Vacant ) = grid . get_mut ( IVec2 :: new ( x , y ) ) { * value = Value :: Occupied ( i ) ; } else { panic ! ( " " ) ; } ; } ; } ; } /// Returns the number of occupied cells around this building as long as all cells inside the building are vacant fn get_neighbor_count_if_vacant ( grid : & SparseGrid < Value > , building : & BuildingShape ) -> Option < usize > { let min = building . edge_min - IVec2 :: ONE ; let max = building . edge_max + IVec2 :: ONE ; let mut neighbor_count = 0 ; for x in min . x ..= max . x { let is_edge_x = x == min . x || x == max . x ; for y in min . y ..= max . y { let is_edge_y = y == min . y || y == max . y ; match ( is_edge_x || is_edge_y , grid . get ( IVec2 :: new ( x , y ) ) ) { // If the current point is an edge (one block outside the building), // and it is occupied, then increment the neighbor count ( true , Some ( & Value :: Occupied ( _ ) ) ) => neighbor_count += 1 , // If the current point is not an edge (actually inside the building), // and it is not vacant then this building is not vacant, terminate ( false , None | Some ( & Value :: Occupied ( _ ) ) ) => return None , // If the current point is an edge and is null, terminate // This is to prevent buildings from being placed right next to edges ( true , None ) => return None , _ => ( ) } ; } ; } ; Some ( neighbor_count ) } # [ derive ( Debug Copy Clone PartialEq Eq ) ] enum Value { Vacant , Occupied ( usize ) } let mut grid = grid . cells ( ) . filter_map ( | ( pos , _ ) | match ivec2_rem_euclid_2 ( pos ) { true => Some ( ( pos / 2 , Value :: Vacant ) ) , false => None } ) . collect :: < SparseGrid < Value > > ( ) ; let mut i = 0 ; let mut buildings = Vec :: new ( ) ; while let Some ( building ) = generate_next_building ( rng , & grid ) { put_building_in_vacancy ( & mut grid , & building , i ) ; buildings . push ( building ) ; i += 1 ; } ; buildings }
Populates the landmass with randomly sized buildings until it is completely full
Populates the landmass with randomly sized buildings until it is completely full
rng
&mut R
grid
&SparseGrid<LandmassCell>
rng
&mut R
grid
&SparseGrid<LandmassCell>