rust/mapgen/src/lib.rs
author alfadur
Sun, 04 Nov 2018 04:43:30 +0300
changeset 14132 0c5b9cfda9ab
child 14133 b04dac00e8e2
permissions -rw-r--r--
add a higher level map generation lib to load yaml templates into somewhere

use std::{
    collections::hash_map::HashMap,
    borrow::Borrow,
    mem::replace
};
use serde::{Deserialize};
use serde_derive::{Deserialize};
use serde_yaml;
use integral_geometry::{Point, Size, Rect};
use landgen::{
    outline_template::OutlineTemplate
};
use rand::{thread_rng, Rng};

#[derive(Deserialize)]
struct PointDesc {
    x: u32,
    y: u32
}

#[derive(Deserialize)]
struct RectDesc {
    x: u32,
    y: u32,
    w: u32,
    h: u32
}

#[derive(Deserialize)]
struct TemplateDesc {
    width: usize,
    height: usize,
    can_flip: bool,
    can_invert: bool,
    can_mirror: bool,
    is_negative: bool,
    put_girders: bool,
    max_hedgehogs: u8,
    outline_points: Vec<Vec<RectDesc>>,
    fill_points: Vec<PointDesc>
}

#[derive(Deserialize)]
struct TemplateCollectionDesc {
    templates: Vec<TemplateDesc>,
    template_types: HashMap<String, Vec<usize>>
}

impl From<&TemplateDesc> for OutlineTemplate {
    fn from(desc: &TemplateDesc) -> Self {
        OutlineTemplate {
            islands: desc.outline_points.iter()
                .map(|v| v.iter()
                    .map(|r| Rect::new(r.x as i32, r.y as i32, r.w, r.h))
                    .collect())
                .collect(),
            fill_points: desc.fill_points.iter()
                .map(|p| Point::new(p.x as i32, p.y as i32))
                .collect(),
            size: Size::new(desc.width, desc.height),
            can_flip: desc.can_flip,
            can_invert: desc.can_invert,
            can_mirror: desc.can_mirror,
            is_negative: desc.is_negative
        }
    }
}

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
struct TemplateType(String);

impl Borrow<str> for TemplateType {
    fn borrow(&self) -> &str {
        self.0.as_str()
    }
}

#[derive(Debug)]
pub struct MapGenerator {
    pub(crate) templates: HashMap<TemplateType, Vec<OutlineTemplate>>
}

impl MapGenerator {
    pub fn new() -> Self {
        Self { templates: HashMap::new() }
    }

    pub fn import_yaml_templates(&mut self, text: &str) {
        let mut desc: TemplateCollectionDesc = serde_yaml::from_str(text).unwrap();
        let templates = replace(&mut desc.templates, vec![]);
        self.templates = desc.template_types.into_iter()
            .map(|(size, indices)|
                (TemplateType(size), indices.iter()
                    .map(|i| (&templates[*i]).into())
                    .collect()))
            .collect();
    }

    pub fn get_template(&self, template_type: &str) -> Option<&OutlineTemplate> {
        self.templates.get(template_type).and_then(|t| thread_rng().choose(t))
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        MapGenerator,
        TemplateType
    };

    #[test]
    fn simple_load() {
        let text = r#"
templates:
  -
    width: 3072
    height: 1424
    can_flip: false
    can_invert: false
    can_mirror: true
    is_negative: false
    put_girders: true
    max_hedgehogs: 18
    outline_points:
      -
        - {x: 748, y: 1424, w: 1, h: 1}
        - {x: 636, y: 1252, w: 208, h: 72}
        - {x: 898, y: 1110, w: 308, h: 60}
        - {x: 1128, y: 1252, w: 434, h: 40}
        - {x: 1574, y: 1112, w: 332, h: 40}
        - {x: 1802, y: 1238, w: 226, h: 36}
        - {x: 1930, y: 1424, w: 1, h: 1}
    fill_points:
      - {x: 1023, y: 0}

template_types:
    test: [0]

"#;

        let mut generator = MapGenerator::new();
        generator.import_yaml_templates(&text);

        assert!(generator.templates.contains_key(&TemplateType("test".to_string())));

        let template = generator.get_template("test").unwrap();

        assert_eq!(template.islands[0].len(), 7);
    }
}