use std::{collections::{HashSet, HashMap}, io::Write, time::{Instant, Duration}}; use serde::{Serialize, Deserialize}; use uuid::Uuid; use wave_function_collapse::wave_function::{WaveFunction, NodeStateCollection, Node, collapsable_wave_function::{collapsable_wave_function::{CollapsableWaveFunction, CollapsedWaveFunction, CollapsedNodeState}, entropic_collapsable_wave_function::EntropicCollapsableWaveFunction}}; use image::{io::Reader as ImageReader, GenericImageView, DynamicImage, ImageFormat}; use colored::Colorize; use std::cmp; fn print_pixel(color: &[u8; 4]) { let character = "\u{2588}"; print!("{}{}", character.truecolor(color[0], color[1], color[2]), character.truecolor(color[0], color[1], color[2])); } #[derive(Hash, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)] struct ImageFragment { // the RGBA color per height per width pixels: Vec>, width: u32, height: u32 } impl ImageFragment { fn new_from_image(image: &DynamicImage, width_index: u32, height_index: u32, fragment_width: u32, fragment_height: u32) -> ImageFragment { let mut pixels: Vec> = Vec::new(); for index in 0..fragment_width { pixels.push(Vec::new()); for _ in 0..fragment_height { pixels[index as usize].push([0, 0, 0, 0]); } } for pixel_height_offset in 0..fragment_height { for pixel_width_offset in 0..fragment_width { let pixel_width_index = width_index + pixel_width_offset; let pixel_height_index = height_index + pixel_height_offset; let pixel = image.get_pixel(pixel_width_index, pixel_height_index); pixels[pixel_width_offset as usize][pixel_height_offset as usize] = pixel.0; } } ImageFragment { pixels, width: fragment_width, height: fragment_height } } fn is_overlapping(&self, other_image_fragment: &ImageFragment, width_offset: i8, height_offset: i8) -> bool { let mut is_at_least_one_pixel_nonoverlapping: bool = false; for self_height_index in cmp::max(0, height_offset)..cmp::min(self.height as i8, height_offset + self.height as i8) { let other_height_index = self_height_index - height_offset; for self_width_index in cmp::max(0, width_offset)..cmp::min(self.width as i8, width_offset + self.width as i8) { let other_width_index = self_width_index - width_offset; let other_pixel = other_image_fragment.pixels[other_width_index as usize][other_height_index as usize]; let self_pixel = self.pixels[self_width_index as usize][self_height_index as usize]; if other_pixel != self_pixel { is_at_least_one_pixel_nonoverlapping = true; break; } } } !is_at_least_one_pixel_nonoverlapping } #[allow(dead_code)] fn print(&self) { for height_index in 0..self.height as usize { for width_index in 0..self.width as usize { let color = self.pixels[width_index][height_index]; print_pixel(&color); } println!(); } } fn rotate(&self) -> Self { let mut pixels: Vec> = Vec::new(); for index in 0..self.height { pixels.push(Vec::new()); for _ in 0..self.width { pixels[index as usize].push([0, 0, 0, 0]); } } for height_index in 0..self.height { for width_index in 0..self.width { let source_color = self.pixels[width_index as usize][height_index as usize]; let destination_width_index = (self.height - 1) - height_index; let destination_height_index = width_index; pixels[destination_width_index as usize][destination_height_index as usize] = source_color; } } ImageFragment { pixels: pixels, width: self.height, height: self.width } } fn flip(&self) -> Self { let mut pixels: Vec> = Vec::new(); for index in 0..self.width { pixels.push(Vec::new()); for _ in 0..self.height { pixels[index as usize].push([0, 0, 0, 0]); } } for height_index in 0..self.height { for width_index in 0..self.width { let source_color = self.pixels[width_index as usize][height_index as usize]; let destination_width_index = (self.width - 1) - width_index; let destination_height_index = height_index; pixels[destination_width_index as usize][destination_height_index as usize] = source_color; } } ImageFragment { pixels: pixels, width: self.width, height: self.height } } } struct Canvas { width: u32, height: u32 } impl Canvas { fn new(width: u32, height: u32) -> Self { Canvas { width: width, height: height } } fn get_wave_function(&self, source_image_file_path: &str, fragment_width: u32, fragment_height: u32, is_reflection_permitted: bool, is_rotation_permitted: bool, is_periodic: bool, contains_ground: bool) -> WaveFunction { // get all of the possible image fragments from the original image let mut image_reader = ImageReader::open(source_image_file_path).expect("The source image file should exist at the provided file path."); image_reader.set_format(ImageFormat::Bmp); let image = image_reader.decode().unwrap(); let image_width = image.width(); let image_height = image.height(); let mut image_fragments: HashSet = HashSet::new(); let mut image_fragment_duplicates_total_per_image_fragment: HashMap = HashMap::new(); let mut ground_image_fragments: HashSet = HashSet::new(); for image_height_index in 0..(image_height - (fragment_height - 1)) { for image_width_index in 0..(image_width - (fragment_width - 1)) { let mut oriented_image_fragments: Vec = Vec::new(); let mut image_fragment = ImageFragment::new_from_image(&image, image_width_index, image_height_index, fragment_width, fragment_height); if image_height_index + 1 == (image_height - (fragment_height - 1)) { ground_image_fragments.insert(image_fragment.clone()); } oriented_image_fragments.push(image_fragment.clone()); if is_reflection_permitted { if is_rotation_permitted { image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.flip(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); } else { image_fragment = image_fragment.flip(); oriented_image_fragments.push(image_fragment.clone()); } } else if is_rotation_permitted { image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); image_fragment = image_fragment.rotate(); oriented_image_fragments.push(image_fragment.clone()); } for image_fragment in oriented_image_fragments.into_iter() { if !image_fragment_duplicates_total_per_image_fragment.contains_key(&image_fragment) { image_fragment_duplicates_total_per_image_fragment.insert(image_fragment.clone(), 1.0); } else { image_fragment_duplicates_total_per_image_fragment.insert(image_fragment.clone(), image_fragment_duplicates_total_per_image_fragment.get(&image_fragment).unwrap() + 1.0); } image_fragments.insert(image_fragment); } } } // construct node state collections such that only those image fragments that overlap can be next to each other let mut node_state_collections: Vec> = Vec::new(); // starting from the top-left, only permit those image fragments that would overlap in the remaining eight pixels // root pixel 1 pixel 2 // pixel 3 pixel 4 pixel 5 // pixel 6 pixel 7 pixel 8 let mut permitted_node_states_per_height_offset_per_width_offset_per_node_state: HashMap<&ImageFragment, HashMap>>> = HashMap::new(); for root_image_fragment in image_fragments.iter() { //println!("===================="); //println!("Root:"); //root_image_fragment.print(); let mut permitted_node_states_per_height_offset_per_width_offset: HashMap>> = HashMap::new(); for width_offset in -1..=1 as i8 { let mut permitted_node_states_per_height_offset: HashMap> = HashMap::new(); for height_offset in -1..=1 as i8 { // do not setup node state collection for root overlapping root if !(height_offset == 0 && width_offset == 0 || height_offset.abs() == 1 && width_offset.abs() == 1) { let mut permitted_node_states: Vec = Vec::new(); for other_image_fragment in image_fragments.iter() { if root_image_fragment.is_overlapping(other_image_fragment, width_offset, height_offset) { //println!("overlapping at {} {}", width_offset, height_offset); //other_image_fragment.print(); permitted_node_states.push(other_image_fragment.clone()); } } permitted_node_states_per_height_offset.insert(height_offset, permitted_node_states); } } permitted_node_states_per_height_offset_per_width_offset.insert(width_offset, permitted_node_states_per_height_offset); } permitted_node_states_per_height_offset_per_width_offset_per_node_state.insert(root_image_fragment, permitted_node_states_per_height_offset_per_width_offset); } // create distinct node state collections per offset height per offset width let mut node_state_collection_ids_per_height_offset_per_width_offset: HashMap>> = HashMap::new(); for (from_node_state, permitted_node_states_per_height_offset_per_width_offset) in permitted_node_states_per_height_offset_per_width_offset_per_node_state.into_iter() { for (width_offset, permitted_node_states_per_height_offset) in permitted_node_states_per_height_offset_per_width_offset.into_iter() { node_state_collection_ids_per_height_offset_per_width_offset.entry(width_offset).or_insert(HashMap::new()); for (height_offset, permitted_node_states) in permitted_node_states_per_height_offset.into_iter() { node_state_collection_ids_per_height_offset_per_width_offset.get_mut(&width_offset).unwrap().entry(height_offset).or_insert(Vec::new()); let node_state_collection_id = Uuid::new_v4().to_string(); let node_state_collection: NodeStateCollection = NodeStateCollection::new(node_state_collection_id.clone(), from_node_state.clone(), permitted_node_states); node_state_collection_ids_per_height_offset_per_width_offset.get_mut(&width_offset).unwrap().get_mut(&height_offset).unwrap().push(node_state_collection_id); node_state_collections.push(node_state_collection); } } } // construct nodes let mut nodes: Vec> = Vec::new(); // create grid of node IDs cooresponding to each image fragment's top-left corner let mut node_id_per_height_index_per_width_index: HashMap> = HashMap::new(); for node_width_index in 0..(self.width - (fragment_width - 1)) as usize { let mut node_id_per_height_index: HashMap = HashMap::new(); for node_height_index in 0..(self.height - (fragment_height - 1)) as usize { let node_id: String = format!("node_{}_{}", node_width_index, node_height_index); node_id_per_height_index.insert(node_height_index, node_id); } node_id_per_height_index_per_width_index.insert(node_width_index, node_id_per_height_index); } // create each node such that its relative node state collections are specified for node_width_index in 0..(self.width - (fragment_width - 1)) as i8 { for node_height_index in 0..(self.height - (fragment_height - 1)) as i8 { let node_id: &String = node_id_per_height_index_per_width_index.get(&(node_width_index as usize)).unwrap().get(&(node_height_index as usize)).unwrap(); let mut node_state_collection_ids_per_neighbor_node_id: HashMap> = HashMap::new(); for neighbor_width_offset in -1..=1 as i8 { for neighbor_height_offset in -1..=1 as i8 { if !(neighbor_width_offset == 0 && neighbor_height_offset == 0 || neighbor_width_offset.abs() == 1 && neighbor_height_offset.abs() == 1) { let mut neighbor_width_index = node_width_index + neighbor_width_offset; let mut neighbor_height_index = node_height_index + neighbor_height_offset; if is_periodic { if neighbor_width_index < 0 { neighbor_width_index += (self.width - (fragment_width - 1)) as i8; } else if neighbor_width_index >= (self.width - (fragment_width - 1)) as i8 { neighbor_width_index -= (self.width - (fragment_width - 1)) as i8; } if neighbor_height_index < 0 { neighbor_height_index += (self.height - (fragment_height - 1)) as i8; } else if neighbor_height_index >= (self.height - (fragment_height - 1)) as i8 { neighbor_height_index -= (self.height - (fragment_height - 1)) as i8; } } if neighbor_width_index >= 0 && neighbor_width_index < (self.width - (fragment_width - 1)) as i8 && neighbor_height_index >= 0 && neighbor_height_index < (self.height - (fragment_height - 1)) as i8 { let neighbor_node_id = node_id_per_height_index_per_width_index.get(&(neighbor_width_index as usize)).unwrap().get(&(neighbor_height_index as usize)).unwrap(); let node_state_collection_ids = node_state_collection_ids_per_height_offset_per_width_offset.get(&neighbor_width_offset).unwrap().get(&neighbor_height_offset).unwrap(); node_state_collection_ids_per_neighbor_node_id.insert(neighbor_node_id.clone(), node_state_collection_ids.clone()); } } } } let mut node_state_ratio_per_node_state_id: HashMap = HashMap::new(); if contains_ground { if node_height_index + 1 == (self.height - (fragment_height - 1)) as i8 { for (image_fragment, ratio) in image_fragment_duplicates_total_per_image_fragment.iter() { if ground_image_fragments.contains(image_fragment) { node_state_ratio_per_node_state_id.insert(image_fragment.clone(), *ratio); } } } else { for (image_fragment, ratio) in image_fragment_duplicates_total_per_image_fragment.iter() { if !ground_image_fragments.contains(image_fragment) { node_state_ratio_per_node_state_id.insert(image_fragment.clone(), *ratio); } } } } else { node_state_ratio_per_node_state_id = image_fragment_duplicates_total_per_image_fragment.clone(); } let node: Node = Node::new(node_id.clone(), node_state_ratio_per_node_state_id, node_state_collection_ids_per_neighbor_node_id); nodes.push(node); } } WaveFunction::new(nodes, node_state_collections) } fn print(&self, collapsed_wave_function: CollapsedWaveFunction, fragment_width: u32, fragment_height: u32) { let mut node_state_per_height_index_per_width_index: HashMap>> = HashMap::new(); for width_index in 0..self.width as usize { let mut node_state_per_height_index: HashMap> = HashMap::new(); for height_index in 0..self.height as usize { node_state_per_height_index.insert(height_index, None); } node_state_per_height_index_per_width_index.insert(width_index, node_state_per_height_index); } for (node_id, node_state) in collapsed_wave_function.node_state_per_node_id.into_iter() { let node_id_split = node_id.split("_").collect::>(); let node_width_index = node_id_split[1].parse::().unwrap(); let node_height_index = node_id_split[2].parse::().unwrap(); node_state_per_height_index_per_width_index.get_mut(&node_width_index).unwrap().insert(node_height_index, Some(node_state)); } let mut pixels: Vec> = Vec::new(); for _ in 0..self.width { let mut vec = Vec::new(); for _ in 0..self.height { vec.push([0 as u8, 0, 128, 0]); } pixels.push(vec); } for width_index in 0..(self.width - (fragment_width - 1)) as usize { for height_index in 0..(self.height - (fragment_height - 1)) as usize { let node_state = node_state_per_height_index_per_width_index.get(&width_index).unwrap().get(&height_index).unwrap().as_ref().unwrap(); if width_index + 1 == (self.width - (fragment_width - 1)) as usize || height_index + 1 == (self.height - (fragment_height - 1)) as usize { for pixel_height_index in 0..node_state.height as usize { for pixel_width_index in 0..node_state.width as usize { pixels[width_index + pixel_width_index][height_index + pixel_height_index] = node_state.pixels[pixel_width_index][pixel_height_index]; } } } else { pixels[width_index][height_index] = node_state.pixels[0][0]; } } } for height_index in 0..self.height as usize { for width_index in 0..self.width as usize { let color = pixels[width_index][height_index]; print_pixel(&color); } println!(""); } } fn print_step(&self, collapsed_node_states: &Vec>, step_index: usize) { let mut pixels: Vec> = Vec::new(); for _ in 0..self.width { let mut vec = Vec::new(); for _ in 0..self.height { vec.push([0 as u8, 0, 128, 0]); } pixels.push(vec); } for current_step_index in 0..=step_index { let collapsed_node_state = collapsed_node_states.get(current_step_index).unwrap(); let node_id_split = collapsed_node_state.node_id.split("_").collect::>(); let node_width_index = node_id_split[1].parse::().unwrap(); let node_height_index = node_id_split[2].parse::().unwrap(); if let Some(pixel_color) = &collapsed_node_state.node_state_id { if node_width_index + pixel_color.width as usize == self.width as usize || node_height_index + pixel_color.height as usize == self.height as usize { for pixel_height_index in 0..pixel_color.height as usize { for pixel_width_index in 0..pixel_color.width as usize{ pixels[node_width_index + pixel_width_index][node_height_index + pixel_height_index] = pixel_color.pixels[pixel_width_index][pixel_height_index]; } } } else { pixels[node_width_index][node_height_index] = pixel_color.pixels[0][0]; } } else { pixels[node_width_index][node_height_index] = [255, 0, 0, 255]; } } println!("Step {step_index} ======================================"); for height_index in 0..self.height as usize { for width_index in 0..self.width as usize { print_pixel(&pixels[width_index][height_index]); } println!(""); } } } #[allow(dead_code)] enum Image { Plant, Rooms, Houses } fn main() { std::env::set_var("RUST_LOG", "trace"); //pretty_env_logger::init(); let is_reflection_permitted: bool; let is_rotation_permitted: bool; let is_periodic: bool; let image_base64: String; let contains_ground: bool; let plant_image_base64: String = String::from("Qk2uBgAAAAAAADYAAAAoAAAAFwAAABcAAAABABgAAAAAAHgGAAAAAAAAAAAAAAAAAAAAAAAAV3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5AAAAV3q5V3q5V3q5V3q5V3q5V3q5V3q5V3q5AKoAV3q5V3q5V3q5V3q5V3q5V3q5V3q5AKoAV3q5V3q5V3q5V3q5V3q5V3q5AAAA8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoAAKoAAKoA8ui/8ui/8ui/8ui/8ui/AKoAAKoAAKoA8ui/8ui/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoA8ui/AKoAAKoA8ui/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/AKoAAKoA8ui/8ui/8ui/APL/8ui/8ui/AKoAAKoA8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoA8ui/8ui/APL/AKoAAPL/8ui/8ui/AKoA8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoAAKoAAKoA8ui/8ui/APL/8ui/8ui/8ui/AKoA8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/AKoA8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoAAKoAAKoA8ui/8ui/AAAA8ui/8ui/8ui/AKoAAKoAAKoA8ui/8ui/8ui/8ui/AKoA8ui/8ui/AKoAAKoA8ui/8ui/AKoAAKoA8ui/AKoA8ui/8ui/AAAA8ui/8ui/8ui/AKoA8ui/AKoAAKoA8ui/8ui/8ui/APL/8ui/8ui/8ui/AKoA8ui/8ui/AKoA8ui/8ui/APL/8ui/8ui/AAAA8ui/8ui/AKoAAKoA8ui/8ui/AKoAAKoA8ui/APL/AKoAAPL/8ui/8ui/AKoA8ui/AKoAAKoA8ui/APL/AKoAAPL/8ui/AAAA8ui/8ui/AKoA8ui/8ui/8ui/8ui/AKoA8ui/8ui/APL/8ui/8ui/AKoAAKoA8ui/AKoA8ui/8ui/8ui/APL/8ui/8ui/AAAA8ui/8ui/APL/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/AKoAAKoA8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/8ui/AAAA8ui/APL/AKoAAPL/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/AAAA8ui/8ui/APL/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/8ui/AKoAAKoA8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/8ui/8ui/8ui/AKoA8ui/8ui/8ui/8ui/APL/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/APL/8ui/8ui/8ui/8ui/8ui/8ui/8ui/APL/8ui/8ui/8ui/APL/AKoAAPL/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/APL/AKoAAPL/8ui/8ui/8ui/8ui/8ui/APL/AKoAAPL/8ui/8ui/8ui/APL/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/APL/8ui/8ui/8ui/8ui/8ui/8ui/8ui/APL/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/AAAA8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/8ui/AAAA"); let rooms_image_base64: String = String::from("Qk02AwAAAAAAADYAAAAoAAAAEAAAABAAAAABABgAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODgAAAAAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODgAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODg4ODgAAAA4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAA4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAA4ODg4ODg4ODg4ODg4ODg4ODgAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4ODgAAAAAAAAAAAA"); let houses_image_base64: String = String::from("Qk02AwAAAAAAADYAAAAoAAAAEAAAABAAAAABABgAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAFWqAFWqAFWqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAFWqAFWqAFWqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAACqAACqAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAAAAAAAAAAAAAFWqAFWqAAAAAFWqAFWqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAFWqAFWqAFWqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACqAACqAACqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); //================================================ // NOTE: This can be change for different examples let chosen_image = Image::Rooms; let draw_each_frame: bool = false; //================================================ match chosen_image { Image::Plant => { is_reflection_permitted = true; is_rotation_permitted = false; is_periodic = false; image_base64 = plant_image_base64; contains_ground = true; }, Image::Rooms => { is_reflection_permitted = true; is_rotation_permitted = true; is_periodic = true; image_base64 = rooms_image_base64; contains_ground = false; }, Image::Houses => { is_reflection_permitted = false; is_rotation_permitted = false; is_periodic = true; image_base64 = houses_image_base64; contains_ground = false; } } let mut file = tempfile::NamedTempFile::new().unwrap(); let bytes = base64::decode(image_base64).unwrap(); file.write(bytes.as_slice()).unwrap(); let file_path: &str = file.path().to_str().unwrap(); let canvas = Canvas::new(40, 40); let fragment_width: u32 = 3; let fragment_height: u32 = 3; let wave_function = canvas.get_wave_function(file_path, fragment_width, fragment_height, is_reflection_permitted, is_rotation_permitted, is_periodic, contains_ground); file.close().unwrap(); wave_function.validate().unwrap(); let mut random_instance = fastrand::Rng::new(); let random_seed = Some(random_instance.u64(..)); let mut collapsable_wave_function = wave_function.get_collapsable_wave_function::>(random_seed); let start = Instant::now(); let duration: Duration; if draw_each_frame { let collapsed_node_states = collapsable_wave_function.collapse_into_steps().unwrap(); duration = start.elapsed(); for step_index in 0..collapsed_node_states.len() { canvas.print_step(&collapsed_node_states, step_index); std::thread::sleep(std::time::Duration::from_millis(100)); } } else { let collapsed_wave_function = collapsable_wave_function.collapse().unwrap(); duration = start.elapsed(); canvas.print(collapsed_wave_function, fragment_width, fragment_height); } println!("Duration: {:?}", duration); }