diff --git a/lab1/src/gui/board.rs b/lab1/src/gui/board.rs new file mode 100644 index 0000000..2cf9318 --- /dev/null +++ b/lab1/src/gui/board.rs @@ -0,0 +1,41 @@ +use eframe::egui::{Color32, CornerRadius, Pos2, Rect, Ui, Vec2}; +use crate::algo::Board; + +pub(crate) fn get_board_size(board_size: usize) -> Vec2 { + return Vec2::new(10.0 * board_size as f32, 10.0 * board_size as f32); +} + +pub(crate) fn draw_board(ui: &mut Ui, board: &Board) { + let painter = ui.painter(); + painter.rect_filled( + ui.available_rect_before_wrap(), + CornerRadius::from(0), + Color32::from_rgb(50, 50, 150), + ); + + for y in 0..board.len() { + for x in 0..board.len() { + if y % 2 == x % 2 { + painter.rect_filled( + Rect::from_min_max( + Pos2::new((10 * x) as f32, (10 * y) as f32), + Pos2::new( + (10 * (x + 1)) as f32, + (10 * (y + 1)) as f32, + ), + ), + CornerRadius::from(0), + Color32::from_rgb(200, 200, 255), + ); + } + } + } + + for i in 0..board.len() { + painter.circle_filled( + Pos2::new((10 * board[i] + 5) as f32, (10 * i + 5) as f32), + 3.0, + Color32::from_rgb(255, 50, 0), + ); + } +} diff --git a/lab1/src/gui/data.rs b/lab1/src/gui/data.rs new file mode 100644 index 0000000..f778513 --- /dev/null +++ b/lab1/src/gui/data.rs @@ -0,0 +1,24 @@ +use crate::algo::{AnnealingConfig, Board}; + +pub(crate) struct MyApp { + pub simulationConfig: AnnealingConfig, + pub boardSize: usize, + pub _isFirstFrame: bool, + pub result: Option, +} + +impl MyApp { + pub(crate) fn new() -> Self { + return Self { + simulationConfig: AnnealingConfig { + initialTemperature: 30.0, + targetTemperature: 0.5, + cooldownCoefficient: 0.99, + iterationsPerAge: 100, + }, + boardSize: 20, + _isFirstFrame: true, + result: None, + }; + } +} diff --git a/lab1/src/gui/input.rs b/lab1/src/gui/input.rs new file mode 100644 index 0000000..675dc9f --- /dev/null +++ b/lab1/src/gui/input.rs @@ -0,0 +1,54 @@ +use crate::algo; +use crate::gui::data::MyApp; +use bgtu_ai_utility::gui::labeled_slider; +use eframe::egui::Ui; +use rand::rng; + +pub(crate) fn input(ui: &mut Ui, data: &mut MyApp) { + ui.add_enabled_ui(matches!(data.result, None), |ui| { + labeled_slider(ui, "Board size:", &mut data.boardSize, 2..=50, 1.0); + ui.label(""); + + labeled_slider( + ui, + "Initial temperature:", + &mut data.simulationConfig.initialTemperature, + data.simulationConfig.targetTemperature + 0.01..=100.0, + 0.01, + ); + ui.label(""); + labeled_slider( + ui, + "Target Temperature:", + &mut data.simulationConfig.targetTemperature, + 0.0..=data.simulationConfig.initialTemperature - 0.1, + 0.01, + ); + ui.label(""); + labeled_slider( + ui, + "Cooldown coefficient:", + &mut data.simulationConfig.cooldownCoefficient, + 0.001..=0.999, + 0.001, + ); + ui.label(""); + + labeled_slider( + ui, + "Iterations per age:", + &mut data.simulationConfig.iterationsPerAge, + 1..=1000, + 1.0, + ); + + ui.label(""); + if ui.button("Calculate").clicked() { + data.result = Some(algo::simulateAnnealing( + data.boardSize, + &data.simulationConfig, + &mut rng(), + )) + } + }); +} \ No newline at end of file diff --git a/lab1/src/gui/mod.rs b/lab1/src/gui/mod.rs new file mode 100644 index 0000000..ff36d5a --- /dev/null +++ b/lab1/src/gui/mod.rs @@ -0,0 +1,7 @@ +mod input; +mod data; +mod board; + +pub(crate) use board::{draw_board, get_board_size}; +pub(crate) use data::MyApp; +pub(crate) use input::input; diff --git a/lab1/src/main.rs b/lab1/src/main.rs index 0dbdf98..c1d37c4 100644 --- a/lab1/src/main.rs +++ b/lab1/src/main.rs @@ -1,150 +1,36 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release mod algo; +mod gui; -use bgtu_ai_utility::gui::{boot_eframe, labeled_slider}; +use bgtu_ai_utility::gui::{boot_eframe, subwindow}; use eframe::egui; -use eframe::egui::{CornerRadius, Frame}; -use eframe::epaint::{Color32, Pos2, Rect}; -use rand::SeedableRng; -use std::time::{SystemTime, UNIX_EPOCH}; fn main() -> eframe::Result { - return boot_eframe(||MyApp::new()) + return boot_eframe(|| gui::MyApp::new()); } -struct MyApp { - simulationConfig: algo::AnnealingConfig, - boardSize: usize, - _isFirstFrame: bool, - result: Option, -} - -impl MyApp { - fn new() -> Self { - return Self { - simulationConfig: algo::AnnealingConfig { - initialTemperature: 30.0, - targetTemperature: 0.5, - cooldownCoefficient: 0.99, - iterationsPerAge: 100, - }, - boardSize: 20, - _isFirstFrame: true, - result: None, - } - } -} - -impl eframe::App for MyApp { +impl eframe::App for gui::MyApp { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ui, |ui| { - ui.add_enabled_ui(matches!(self.result, None), |ui| { - labeled_slider(ui, "Board size:", &mut self.boardSize, 2..=50, 1.0); - ui.label(""); + gui::input(ui, self); - labeled_slider( - ui, - "Initial temperature:", - &mut self.simulationConfig.initialTemperature, - self.simulationConfig.targetTemperature + 0.01..=100.0, - 0.01, - ); - ui.label(""); - labeled_slider( - ui, - "Target Temperature:", - &mut self.simulationConfig.targetTemperature, - 0.0..=self.simulationConfig.initialTemperature - 0.1, - 0.01, - ); - ui.label(""); - labeled_slider( - ui, - "Cooldown coefficient:", - &mut self.simulationConfig.cooldownCoefficient, - 0.001..=0.999, - 0.001, - ); - ui.label(""); - - labeled_slider( - ui, - "Iterations per age:", - &mut self.simulationConfig.iterationsPerAge, - 1..=1000, - 1.0, - ); - - ui.label(""); - if ui.button("Calculate").clicked() { - self.result = Some(algo::simulateAnnealing( - self.boardSize, - &self.simulationConfig, - &mut rand::rngs::SmallRng::seed_from_u64( - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - ), - )) - } - }); - - match self.result.clone() { + match &self.result { None => {} - Some(board) => ui.ctx().show_viewport_immediate( - egui::ViewportId::from_hash_of("board"), - egui::ViewportBuilder::default() - .with_title("Board") - .with_inner_size([ - 10.0 * self.boardSize as f32, - 10.0 * self.boardSize as f32, - ]) - .with_resizable(false), - |ui, _| { - egui::CentralPanel::default() - .frame(Frame::default().inner_margin(0.0)) - .show(ui, |ui| { - let painter = ui.painter(); - painter.rect_filled( - ui.available_rect_before_wrap(), - CornerRadius::from(0), - Color32::from_rgb(50, 50, 150), - ); - - for y in 0..self.boardSize { - for x in 0..self.boardSize { - if y % 2 == x % 2 { - painter.rect_filled( - Rect::from_min_max( - Pos2::new((10 * x) as f32, (10 * y) as f32), - Pos2::new( - (10 * (x + 1)) as f32, - (10 * (y + 1)) as f32, - ), - ), - CornerRadius::from(0), - Color32::from_rgb(200, 200, 255), - ); - } - } - } - - for i in 0..self.boardSize { - painter.circle_filled( - Pos2::new((10 * board[i] + 5) as f32, (10 * i + 5) as f32), - 3.0, - Color32::from_rgb(255, 50, 0), - ); - } - - if ui.input(|i| i.viewport().close_requested()) { - self.result = None - } - }); - }, - ), + Some(board) => { + subwindow( + ui, + "board", + "Board", + |vb| { + return vb + .with_inner_size(gui::get_board_size(self.boardSize)) + .with_resizable(false); + }, + |ui| gui::draw_board(ui, board), + ) + .on_close(|| self.result = None); + } }; }); }