// Copyright Marcus Del Favero 2025
// Licensed under the GNU AGPLv3 with an exception, see `README.md` for details
use super::Vm;

use crate::utils::component_finder::{self, BLOCK, UNASSIGNED};

impl Vm {
	/**
	 * Fills in all connected components or "holes" of the block map except the
	 * largest one.
	 *
	 * The purpose of this method is to prevent players from being physically
	 * separated by the blocks so they cannot fight each other and the game would
	 * be boring.
	 *
	 * This method works by performing flood fill on all non-block (non-positive)
	 * cells to identify the connected components (regions in which players
	 * aren't separated). Then the largest connected component is kept with all
	 * others being "filled" in by setting their value to be one (corresponding
	 * to being a block with the threshold).
	 *
	 * Note that if the world size is greater than the range of the blocks, some
	 * holes might be unnecessarily removed, and if the world size is smaller,
	 * players still might be able to be isolated.
	 */
	pub(super) fn fill_holes(&mut self) -> Result<(), String> {
		let bmap = Vm::get_top(&mut self.stack)?;

		let mut data = bmap.iter().map(|&x| if x > 0.0 { BLOCK } else { UNASSIGNED }).collect::<Box<[u32]>>();
		let blocks_per_component = component_finder::find(self.grid_size, &mut data);

		let Some(largest_component) = blocks_per_component.into_iter().enumerate().max_by_key(|(_, n)| *n).map(|(i, _)| i as u32) else {
			return Ok(());
		};

		assert!(data.len() == bmap.len());

		for i in 0..data.len() {
			if data[i] != BLOCK && data[i] != largest_component {
				bmap[i] = 1.0;
			}
		}

		Ok(())
	}
}
