solution saving and loading

This commit is contained in:
Crispy 2024-10-06 16:29:45 +02:00
parent c4381ac1a1
commit 0c2d241745
6 changed files with 72 additions and 21 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/target
/user

View file

@ -4,7 +4,6 @@
logic mostly like https://git.crispypin.cc/CrispyPin/marble
## todo
solution saving & loading
cleanup: unpowered texture names x_off -> x
input/output display
grow grid automatically while editing

View file

@ -64,6 +64,7 @@ enum SimState {
pub enum ExitState {
Dont,
ExitAndSave,
Save,
ExitNoSave,
}
@ -100,18 +101,10 @@ impl Editor {
&self.level.id()
}
pub fn save(&mut self) {
todo!()
}
pub fn source_board(&self) -> &Board {
&self.source_board
}
pub fn load_board(&mut self, board: Board) {
self.source_board = board;
}
fn start_sim(&mut self) {
self.machine.reset();
self.machine.set_board(self.source_board.clone());
@ -278,6 +271,10 @@ impl Editor {
self.exit_menu = true;
}
d.draw_text("exit", 10, 10, 20, Color::WHITE);
if simple_button(d, 90, 5, 80, 30) {
self.exit_state = ExitState::Save;
}
d.draw_text("save", 95, 10, 20, Color::WHITE);
}
}

View file

@ -13,7 +13,6 @@ mod util;
use editor::{Editor, ExitState};
use level::Level;
use marble_engine::board::Board;
use solution::Solution;
use util::*;
@ -40,8 +39,6 @@ fn main() {
let mut game = Game::new(&mut rl, &thread);
game.run(&mut rl, &thread);
// let board = Board::parse(&read_to_string("boards/adder.mbl").unwrap());
// game.load_board(board);
}
impl Game {
@ -52,7 +49,7 @@ impl Game {
Self {
levels: get_levels(),
solutions: HashMap::new(),
solutions: get_solutions(),
open_editor: None,
textures,
selected_level: 0,
@ -69,13 +66,20 @@ impl Game {
editor.draw(&mut d, &self.textures);
match editor.get_exit_state() {
ExitState::Dont => (),
ExitState::ExitNoSave => self.open_editor = None,
ExitState::ExitAndSave => {
self.solutions.get_mut(editor.level_id()).unwrap()
[self.selected_solution]
.board = editor.source_board().to_string();
let solution = &mut self.solutions.get_mut(editor.level_id()).unwrap()
[self.selected_solution];
solution.board = editor.source_board().to_string();
solution.save();
self.open_editor = None;
}
ExitState::Save => {
let solution = &mut self.solutions.get_mut(editor.level_id()).unwrap()
[self.selected_solution];
solution.board = editor.source_board().to_string();
solution.save();
}
ExitState::ExitNoSave => self.open_editor = None,
}
} else {
self.draw(&mut d);
@ -227,3 +231,33 @@ fn get_levels() -> Vec<Level> {
levels.sort_by(|a, b| a.id().cmp(b.id()));
levels
}
fn get_solutions() -> HashMap<String, Vec<Solution>> {
let mut levels = HashMap::new();
let solution_dir = userdata_dir().join("solutions");
if let Ok(dir_contents) = read_dir(solution_dir) {
for dir in dir_contents.flatten() {
if dir.path().is_dir() {
let level_name = dir.file_name().to_string_lossy().to_string();
let mut solutions = Vec::new();
if let Ok(files) = read_dir(dir.path()) {
for file in files.flatten() {
let s = read_to_string(file.path())
.ok()
.as_deref()
.map(|s| serde_json::from_str(s).ok())
.flatten();
if let Some(solution) = s {
solutions.push(solution)
}
}
levels.insert(level_name, solutions);
}
}
}
}
levels
}

View file

@ -1,13 +1,19 @@
use std::{
fs::{self, File},
io::Write,
};
use serde::{Deserialize, Serialize};
use crate::level::Level;
use crate::{level::Level, userdata_dir};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Solution {
// solution_id: String,
solution_id: String,
level_id: String, // redundant?
pub name: String,
pub board: String,
#[serde(default)]
pub score: Option<Score>,
}
@ -21,7 +27,7 @@ pub struct Score {
impl Solution {
pub fn new(level: &Level, number: usize) -> Self {
Self {
// solution_id: format!("solution_{number}"),
solution_id: format!("solution_{number}"),
level_id: level.id().to_owned(),
name: format!("Unnamed {number}"),
board: level
@ -32,6 +38,16 @@ impl Solution {
}
}
pub fn save(&self) {
let dir = userdata_dir().join("solutions").join(&self.level_id);
fs::create_dir_all(&dir).unwrap();
let path = dir.join(&format!("{}.json", &self.solution_id));
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 level_id(&self) -> &str {
&self.level_id
}

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, fs::read_dir};
use std::{collections::HashMap, fs::read_dir, path::PathBuf};
use raylib::prelude::*;
@ -188,3 +188,7 @@ pub fn shrink_rec(rec: Rectangle, a: f32) -> Rectangle {
height: rec.height - a * 2.,
}
}
pub fn userdata_dir()->PathBuf{
PathBuf::from("user")
}