use fmc::items::{ItemId, ItemStack};
#[derive(Hash, PartialEq, Eq)]
pub struct Pattern {
pub(super) inner: Vec<Vec<Option<ItemId>>>,
}
impl From<&[ItemStack]> for Pattern {
fn from(grid: &[ItemStack]) -> Self {
let grid_size = (grid.len() as f32).sqrt() as usize;
assert!(grid_size.pow(2) == grid.len());
let mut max_row = 0;
let mut max_col = 0;
let mut min_row = grid_size;
let mut min_col = grid_size;
for (i, row) in grid.chunks(grid_size).enumerate() {
for (j, item_stack) in row.iter().enumerate() {
if !item_stack.is_empty() {
if i > max_row {
max_row = i;
}
if i < min_row {
min_row = i;
}
if j > max_col {
max_col = j;
}
if j < min_col {
min_col = j;
}
}
}
}
let mut inner = Vec::new();
for row in grid.chunks(grid_size).take(max_row + 1).skip(min_row) {
let mut pattern_row = Vec::new();
for item_stack in row.iter().take(max_col + 1).skip(min_col) {
if let Some(item) = item_stack.item() {
pattern_row.push(Some(item.id));
} else {
pattern_row.push(None);
}
}
inner.push(pattern_row);
}
return Pattern { inner };
}
}
pub struct Recipe {
pub(super) required_amount: Vec<Vec<u32>>,
pub(super) output: ItemStack,
}
impl Recipe {
pub(super) fn craft(&self, input: &mut [ItemStack], mut amount: u32) -> Option<ItemStack> {
amount = std::cmp::min(
amount / self.output.size(),
self.get_craftable_amount(input) / self.output.size(),
);
if amount == 0 {
return None;
}
input
.iter_mut()
.filter(|x| !x.is_empty())
.zip(self.required_amount.iter().flatten().filter(|&x| *x > 0))
.for_each(|(item_stack, required)| {
item_stack.take(required * amount);
});
let mut output = self.output.clone();
output.set_size(amount * self.output.size());
return Some(output);
}
pub(super) fn get_craftable_amount(&self, input: &[ItemStack]) -> u32 {
let mut amount_can_craft = u32::MAX;
input
.iter()
.filter(|&x| !x.is_empty())
.zip(self.required_amount.iter().flatten().filter(|&x| *x > 0))
.for_each(|(item_stack, required)| {
let can_craft = item_stack.size() / required;
if can_craft < amount_can_craft {
amount_can_craft = can_craft;
}
});
if amount_can_craft < u32::MAX {
return amount_can_craft * self.output.size();
} else {
return 0;
}
}
pub fn output(&self) -> &ItemStack {
return &self.output;
}
}