use crate::bin::Bin;
use crate::error::{Error, Result};
use crate::item::{Item, ItemId};
pub fn packing_algorithm<'a>(
bin: Bin<'a>,
items: &'a Vec<Item<'_>>,
) -> Result<Vec<Vec<&'a ItemId>>> {
if !items.iter().all(|item| bin.fits(item)) {
return Err(Error::AllItemsMustFit(format!(
"All items must fit within the bin dimensions."
)));
}
let mut items_to_pack = items.clone();
items_to_pack.sort_by(|a, b| b.cmp(&a));
let mut packed_bins: Vec<Bin<'a>> = Vec::new();
let mut bin_currently_packing = bin.clone_as_empty_bin();
loop {
match (
items_to_pack.is_empty(),
bin_currently_packing.items.is_empty(),
) {
(true, true) => break,
(true, false) => {
packed_bins.push(bin_currently_packing);
break;
}
(false, _) => {
if let Some(packed_item_index) = items_to_pack
.clone()
.into_iter()
.enumerate()
.find_map(|(item_index, item)| {
bin_currently_packing.try_packing(item).map(|_| item_index)
})
{
items_to_pack.remove(packed_item_index);
} else {
let packed_bin =
std::mem::replace(&mut bin_currently_packing, bin.clone_as_empty_bin());
packed_bins.push(packed_bin);
}
}
}
}
Ok(packed_bins
.into_iter()
.map(|bin| bin.items.into_iter().map(|item| item.id).collect())
.collect())
}