#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release mod algo; use eframe::egui; use eframe::egui::{Frame, Ui}; use eframe::emath::Numeric; use std::collections::HashSet; use std::ops::RangeInclusive; use tsp_utility::graph::{EdgesVec, VerticesVec}; use tsp_utility::gui::lengths_table::{UpdatePending, draw_lengths_table}; fn main() -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 400.0]), ..Default::default() }; eframe::run_native( "Ants simulation", options, Box::new(|_cc| Ok(Box::::default())), ) } enum ViewState { Stop, Running { lastUpdateTimestamp: u64 }, VertexMove { vertexId: usize }, } enum GlobalState { Edit {}, Running { view_state: ViewState }, } struct MyApp { edges: EdgesVec<()>, vertices: VerticesVec, vertex_update: UpdatePending, population_size: usize, rounds: usize, mutation_chance: f64, state: GlobalState, } impl Default for MyApp { fn default() -> Self { return Self { edges: EdgesVec::new(), vertices: VerticesVec::new(), vertex_update: UpdatePending::NoChange, population_size: 2, rounds: 1, mutation_chance: 0.1, state: GlobalState::Edit {}, }; } } fn _slider( ui: &mut Ui, name: &str, storage: &mut T, range: RangeInclusive, step: f64, ) { let label = ui.label(name); ui.scope(|ui| { ui.spacing_mut().slider_width = ui.available_width() - ui.spacing().interact_size.x - ui.spacing().button_padding.x * 2.0; ui.add(egui::Slider::new(storage, range).step_by(step)) .labelled_by(label.id); }); } impl eframe::App for MyApp { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ui, |ui| match self.state { GlobalState::Edit {} => { match self.vertex_update { UpdatePending::NoChange => {} UpdatePending::Add => { let new_vi = self.vertices.add(HashSet::new()); let mut newEdgesSet = HashSet::new(); for (vi, v) in self.vertices.iter_indexed_mut() { if (vi == new_vi) { continue; } let ei = self.edges.add(new_vi, vi, 1.0, ()); newEdgesSet.insert(ei); v.insert(ei); } self.vertices[new_vi] = newEdgesSet; self.vertex_update = UpdatePending::NoChange; } UpdatePending::Remove(vi) => { let mut eis = Vec::with_capacity(self.vertices[vi].len()); for ei in self.vertices[vi].iter() { eis.push(*ei) } for ei in eis { self.vertices[self.edges[ei].another(vi)].remove(&ei); self.edges.remove(ei); } self.vertices.remove(vi); self.vertex_update = UpdatePending::NoChange; } } edit_panel(self, ui) } GlobalState::Running { .. } => { ui.add_enabled_ui(false, |ui| edit_panel(self, ui)); ui.ctx().show_viewport_immediate( egui::ViewportId::from_hash_of("Visualisation"), egui::ViewportBuilder::default() .with_title("Visualisation") .with_inner_size([640.0, 480.0]) .with_resizable(false), |ui, _| { egui::CentralPanel::default() .frame(Frame::default().inner_margin(0.0)) .show(ui, |ui| visualization_panel(self, ui)); }, ); } }); } } fn edit_panel(data: &mut MyApp, ui: &mut Ui) { let run: bool; _slider( ui, "Population size", &mut data.population_size, 2..=1000, 1.0, ); ui.label(""); _slider(ui, "Rounds", &mut data.rounds, 1..=100, 1.0); ui.label(""); _slider( ui, "Mutation chance", &mut data.mutation_chance, 0.0..=1.0, 0.001, ); ui.horizontal(|ui| { if ui.button("Add vertex").clicked() { data.vertex_update = UpdatePending::Add; } ui.separator(); let run = ui.button("Run").clicked(); }); draw_lengths_table( ui, &mut data.vertices, &mut data.edges, &mut data.vertex_update, ) } fn visualization_panel(data: &mut MyApp, ui: &mut Ui) { ui.horizontal(|ui| { if ui.button("Exit").clicked() {} if ui.button("Step").clicked() {} ui.label(""); }); }