diff options
Diffstat (limited to 'server/src/data/demands.rs')
| -rw-r--r-- | server/src/data/demands.rs | 94 | 
1 files changed, 94 insertions, 0 deletions
| diff --git a/server/src/data/demands.rs b/server/src/data/demands.rs new file mode 100644 index 00000000..2501e225 --- /dev/null +++ b/server/src/data/demands.rs @@ -0,0 +1,94 @@ +/* +    Hurry Curry! - a game about cooking +    Copyright 2024 metamuffin + +    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 <https://www.gnu.org/licenses/>. + +*/ +use super::Demand; +use crate::interaction::Recipe; +use hurrycurry_protocol::{ItemIndex, TileIndex}; +use std::collections::{HashMap, HashSet}; + +pub fn generate_demands( +    tiles: HashSet<TileIndex>, +    items: HashSet<ItemIndex>, +    raw_demands: &[(ItemIndex, Option<ItemIndex>, f32)], +    recipes: &[Recipe], +) -> Vec<Demand> { +    let recipes = recipes +        .iter() +        .filter(|r| r.tile().map(|t| tiles.contains(&t)).unwrap_or(true)) +        .collect::<Vec<_>>(); + +    let mut producable = HashMap::new(); + +    for i in &items { +        producable.insert(*i, 0.0); +    } + +    loop { +        let prod_count = producable.len(); + +        for r in &recipes { +            let output_count = r.outputs().iter().filter(|o| !items.contains(&o)).count(); +            let Some(ingred_cost) = r +                .inputs() +                .iter() +                .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 { duration, .. } => 2. + duration * 0.1, +                Recipe::Active { duration, .. } => 2. + duration, +                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; +        } +    } + +    raw_demands +        .iter() +        .filter_map(|(i, o, d)| { +            if let Some(cost) = producable.get(i) { +                Some(Demand { +                    from: *i, +                    to: *o, +                    duration: *d, +                    points: *cost as i64, +                }) +            } else { +                None +            } +        }) +        .collect() +} | 
