use std::{ fs::{self, File}, io::Write, path::PathBuf, }; use serde::{Deserialize, Serialize}; use crate::{level::Level, userdata_dir}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Solution { solution_id: usize, level_id: String, pub name: String, pub board: String, #[serde(default)] pub score: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Score { pub cycles: usize, pub tiles: usize, } impl Solution { pub fn new(level: &Level, id: usize) -> Self { Self { solution_id: id, level_id: level.id().to_owned(), name: format!("Unnamed {id}"), board: level.init_board().unwrap_or(String::from(" ")), score: None, } } pub fn new_copy(&self, id: usize) -> Self { let mut new = self.clone(); new.solution_id = id; new.score = None; new } pub fn id(&self) -> usize { self.solution_id } fn path(&self) -> PathBuf { let dir = userdata_dir().join("solutions").join(&self.level_id); fs::create_dir_all(&dir).unwrap(); dir.join(format!("solution_{}.json", &self.solution_id)) } pub fn save(&self) { let path = self.path(); let json = serde_json::to_string_pretty(self).unwrap(); let mut file = File::create(path).unwrap(); file.write_all(json.as_bytes()).unwrap(); } pub fn remove_file(&self) { let path = self.path(); if let Err(e) = fs::remove_file(path) { eprint!("Error removing solution file: {e}"); } } pub fn score_text(&self) -> String { if let Some(score) = &self.score { format!("C: {} T: {}", score.cycles, score.tiles) } else { "unsolved".into() } } }