#[macro_use] extern crate serde_derive; extern crate serde; extern crate serde_json; use std::io::BufWriter; use std::io::BufReader; use std::fs::File; use std::ops::{Add, Sub, Div}; use std::collections::HashMap; // use nalgebra::Vector3; #[macro_use] extern crate log; extern crate simplelog; use simplelog::*; #[derive(Clone, Debug, Serialize, Deserialize, Copy, Eq, PartialEq, Hash)] struct V3 { x: i32, y: i32, z: i32 } impl V3 { fn new(x: i32, y: i32, z: i32) -> V3 { V3 { x: x, y: y, z: z } } fn neighbors(self) -> [V3;6] { let o = self.offsets(); [ self+o[0], self+o[1], self+o[2], self+o[3], self+o[4], self+o[5] ] } fn offsets(self) -> [V3;6] { [ V3::new(1,0,0), V3::new(-1,0,0), V3::new(0,1,0), V3::new(0,-1,0), V3::new(0,0,1), V3::new(0,0,-1), ] } } impl Add for V3 { type Output = V3; fn add(self, other: V3) -> V3 { V3 { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z, } } } impl Add for V3 { type Output = V3; fn add(self, other: i32) -> V3 { V3 { x: self.x + other, y: self.y + other, z: self.z + other, } } } impl<'a, 'b> Add<&'b V3> for &'a V3 { type Output = V3; fn add(self, other: &'b V3) -> V3 { V3 { x: self.x + other.x, y: self.y + other.y, z: self.z + other.z, } } } // impl Sub for V3 { // type Output = V3; // fn sub(self, other: V3) -> V3 { // V3 { // x: self.x - other.x, // y: self.y - other.y, // z: self.z - other.z, // } // } // } // #[derive(Clone, Debug)] // struct Voxel { // id: String, // // adjacency: HashMap<&'static str, u16>, // adjacency: HashMap>, // // offsets: [V3; 6] // } /// A graphics tile as ex- or imported from a 3d program #[derive(Clone, Debug, Serialize, Deserialize)] struct GfxTile { name: String, pos: Vec, } fn unitized_grid(vol: &HashMap, divisor: i32) -> HashMap { vol.iter().map(|(k,v)| (V3{x: k.x/divisor, y: k.y/divisor, z: k.z/divisor},v.clone())).collect() } fn guess_gridsize(vol: &HashMap) -> i32{ let mut x_positions: Vec = vol.iter().map(|(k,v)| k.x).collect(); x_positions.sort(); x_positions.dedup(); let mut dist_count: HashMap = HashMap::new(); let mut last: Option = None; for px in x_positions { if let Some(l) = last { let delta = px.abs() - l; let c = dist_count.entry(delta.abs()).or_insert(1); *c += 1; } last = Some(px.abs()); } let mut grid = 1; let mut maxcount = 0; for (size, count) in dist_count { if count > maxcount { grid = size; maxcount = count; } } // dbg!(&grid); grid } fn train_volume(vol: &HashMap) -> HashMap>> { let mut trained: HashMap>> = HashMap::new(); for (pos, tilename) in vol { // lookup neighbors let tile = trained.entry(tilename.clone()).or_insert( HashMap::new() ); for p_o in pos.offsets().iter() { let p_n = p_o + pos; if let Some(neighbor) = vol.get(&p_n) { if let Some(neighbor_tile) = tile.get_mut(&p_o) { neighbor_tile.push(neighbor.clone()); } else { tile.insert(p_o.clone(), vec![neighbor.clone()]); } } } } trained } fn load_export(path: &'static str) -> HashMap { let reader = BufReader::new(File::open(path).unwrap()); let loaded_tiles: Vec = serde_json::from_reader(reader).unwrap(); loaded_tiles .iter() .map(|x| { (V3::new(x.pos[0] as i32, x.pos[1] as i32, x.pos[2] as i32), x.name.clone()) }) .collect() } fn get_adjacent_tiles(grid: &HashMap, training_data: &HashMap>>) -> HashMap { let mut adjacents: HashMap = HashMap::new(); for (pos, tile) in grid { } adjacents } fn get_unsolved_neighbors(cell: &V3, grid: &HashMap) -> Vec { let mut neighbors = vec![]; for n in &cell.neighbors() { if !grid.contains_key(n) { neighbors.push(n.clone()); } } neighbors } fn wfc_solver(training_data: HashMap>>) -> HashMap { let mut new_grid: HashMap = HashMap::new(); // init start conditions new_grid.insert(V3::new(10, 0, 0), String::from("grass")); for (pos, name) in &new_grid { for unsolved_neighbor in get_unsolved_neighbors(pos, &new_grid) { println!("Solving {:?} (next to {})", unsolved_neighbor, name); let trained_data_for_this_tile = training_data.get(name).unwrap(); } } new_grid } fn main() { let _ = simplelog::SimpleLogger::init(LevelFilter::Info, Config::default()); let mut import_volume: HashMap = HashMap::new(); let imported_tiles = load_export("out.json"); let gridsize = guess_gridsize(&imported_tiles); info!("Detected grid size: {}", gridsize); let imported_tiles = unitized_grid(&imported_tiles, gridsize); info!("Tiles imported: {}", imported_tiles.len()); for (pos, tile) in imported_tiles { import_volume.insert(pos, tile); } let training_data = train_volume(&import_volume); info!("Training done: {} tiles", training_data.len()); // for (tilename, adjacency_map) in training_data { // println!("\n{}", tilename); // for (pos, fitting_tiles) in adjacency_map{ // println!("{:?}{:?}", pos, fitting_tiles); // } // } let new_grid: HashMap = HashMap::new(); wfc_solver(training_data); // dbg!(&vol); // let mut adj_map: HashMap = HashMap::new(); }