/* Hurry Curry! - a game about cooking Copyright (C) 2025 Hurry Curry! Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use hurrycurry_protocol::{Demand, ItemIndex, Recipe, TileIndex, glam::IVec2}; use log::debug; use std::collections::{HashMap, HashSet}; pub fn filter_demands_and_recipes( initial_map: &HashMap, Option)>, demands: &mut Vec, recipes: &mut Vec, ) { debug!( "running demand filter with {} recipes and {} demands", recipes.len(), demands.len() ); let map_tiles = initial_map .values() .flat_map(|(t, _)| t) .copied() .collect::>(); let map_items = initial_map .values() .flat_map(|(_, i)| i) .copied() .collect::>(); // Remove tile-bound recipes that cant be performed recipes.retain(|r| r.tile().is_none_or(|t| map_tiles.contains(&t))); let mut producable = HashMap::new(); // Items already in the map have no cost producable.extend(map_items.iter().map(|i| (*i, 0.0))); loop { let prod_count = producable.len(); for r in &*recipes { let output_count = r.outputs().filter(|o| !map_items.contains(o)).count(); let Some(ingred_cost) = r .inputs() .map(|i| producable.get(&i).copied()) .reduce(|a, b| { if let (Some(a), Some(b)) = (a, b) { Some(a + b) } else { None } }) .unwrap_or(Some(0.)) else { continue; }; let base_cost = match r { Recipe::Passive { speed, .. } => 2. + (1. / speed) * 0.1, Recipe::Active { speed, .. } => 2. + (1. / speed), Recipe::Instant { .. } => 1., }; let output_cost = (ingred_cost + base_cost) / output_count as f32; for o in r.outputs() { let cost = producable.entry(o).or_insert(f32::INFINITY); *cost = cost.min(output_cost); } } if prod_count == producable.len() { break; } } recipes.retain(|r| { r.inputs().all(|o| producable.contains_key(&o)) && r.outputs().all(|o| producable.contains_key(&o)) }); demands.retain_mut(|d| { if let Some(&cost) = producable.get(&d.input) { d.points = cost as i64; true } else { false } }); debug!( "{} applicable recipes and {} demands selected", recipes.len(), demands.len() ) }