add button to clone solutions

This commit is contained in:
Crispy 2024-10-13 01:23:56 +02:00
parent 1ce5291777
commit 2720735a58
5 changed files with 42 additions and 29 deletions

View file

@ -57,7 +57,7 @@ blueprint rotation?
```json ```json
{ {
"level_id": "00_zeroes", "level_id": "00_zeroes",
"solution_id": "solution_0", "solution_id": 0,
"name": "unnamed 1", "name": "unnamed 1",
"board": "oo\nP*\n|-", "board": "oo\nP*\n|-",
"score": { "score": {
@ -71,7 +71,7 @@ blueprint rotation?
`blueprints/blueprint_0.json` `blueprints/blueprint_0.json`
```json ```json
{ {
"id": "blueprint_0", "id": 0,
"name": "zero_printer", "name": "zero_printer",
"board": "o -B I\n> * < \n" "board": "o -B I\n> * < \n"
} }

View file

@ -8,7 +8,7 @@ use raylib::prelude::*;
use crate::{ use crate::{
blueprint::Blueprint, blueprint::Blueprint,
draw_scaled_texture, draw_usize, draw_scaled_texture, draw_usize, get_free_id, get_scroll,
level::Level, level::Level,
marble_engine::{ marble_engine::{
board::Board, board::Board,
@ -18,7 +18,7 @@ use crate::{
}, },
simple_button, simple_option_button, slider, simple_button, simple_option_button, slider,
solution::{Score, Solution}, solution::{Score, Solution},
text_input, texture_option_button, get_scroll, userdata_dir, Scroll, Textures, text_input, texture_option_button, userdata_dir, Scroll, Textures,
}; };
const HEADER_HEIGHT: i32 = 40; const HEADER_HEIGHT: i32 = 40;
@ -254,16 +254,7 @@ impl Editor {
} }
} }
board.trim_size(0); board.trim_size(0);
let mut id = 0; let id = get_free_id(&self.blueprints, Blueprint::id);
'outer: loop {
for b in &self.blueprints {
if b.id() == id {
id += 1;
continue 'outer;
}
}
break;
}
let mut blueprint = Blueprint::new(&board, id); let mut blueprint = Blueprint::new(&board, id);
if !self.new_blueprint_name.is_empty() { if !self.new_blueprint_name.is_empty() {
blueprint.name = self.new_blueprint_name.clone(); blueprint.name = self.new_blueprint_name.clone();

View file

@ -203,10 +203,10 @@ impl Game {
solution_y += solution_entry_height + 10; solution_y += solution_entry_height + 10;
} }
let next_id = get_free_id(solutions, Solution::id);
if simple_button(d, level_list_width + 10, solution_y, entry_width, 30) { if simple_button(d, level_list_width + 10, solution_y, entry_width, 30) {
let n = solutions.len();
self.selected_solution = solutions.len(); self.selected_solution = solutions.len();
solutions.push(Solution::new(level, n)); solutions.push(Solution::new(level, next_id));
} }
d.draw_text( d.draw_text(
"new solution", "new solution",
@ -227,14 +227,23 @@ impl Game {
24, 24,
true, true,
); );
d.draw_text(solution.id(), column_x, y + 35, 10, Color::GRAY); let id_text = format!("{}", solution.id());
d.draw_text(&id_text, column_x, y + 35, 10, Color::GRAY);
if simple_button(d, column_x, y + 50, 220, 30) { if simple_button(d, column_x, y + 50, 220, 30) {
let cloned = solution.new_copy(next_id);
self.selected_solution = solutions.len();
solutions.push(cloned);
return;
}
d.draw_text("clone", column_x + 5, y + 55, 20, Color::WHITE);
if simple_button(d, column_x, y + 85, 220, 30) {
let mut editor = Editor::new(solution.clone(), level.clone()); let mut editor = Editor::new(solution.clone(), level.clone());
editor.center_view(d); editor.center_view(d);
self.open_editor = Some(editor); self.open_editor = Some(editor);
} }
d.draw_text("edit", column_x + 5, y + 55, 20, Color::WHITE); d.draw_text("edit", column_x + 5, y + 90, 20, Color::WHITE);
} }
} else { } else {
self.solutions.insert(level.id().to_owned(), Vec::new()); self.solutions.insert(level.id().to_owned(), Vec::new());
@ -263,7 +272,7 @@ fn get_levels() -> Vec<Level> {
add_level(d.path()); add_level(d.path());
} }
} }
levels.sort_by_key(Level::sort_order); levels.sort_unstable_by_key(Level::sort_order);
levels levels
} }
@ -275,7 +284,6 @@ fn get_solutions() -> HashMap<String, Vec<Solution>> {
if dir.path().is_dir() { if dir.path().is_dir() {
let level_name = dir.file_name().to_string_lossy().to_string(); let level_name = dir.file_name().to_string_lossy().to_string();
let mut solutions = Vec::new(); let mut solutions = Vec::new();
if let Ok(files) = read_dir(dir.path()) { if let Ok(files) = read_dir(dir.path()) {
for file in files.flatten() { for file in files.flatten() {
let s = read_to_string(file.path()) let s = read_to_string(file.path())
@ -286,12 +294,11 @@ fn get_solutions() -> HashMap<String, Vec<Solution>> {
solutions.push(solution) solutions.push(solution)
} }
} }
solutions.sort_unstable_by_key(Solution::id);
by_level.insert(level_name, solutions);
} }
by_level.insert(level_name, solutions);
} }
} }
} }
by_level by_level
} }

View file

@ -9,7 +9,7 @@ use crate::{level::Level, userdata_dir};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Solution { pub struct Solution {
solution_id: String, solution_id: usize,
level_id: String, level_id: String,
pub name: String, pub name: String,
pub board: String, pub board: String,
@ -25,18 +25,25 @@ pub struct Score {
} }
impl Solution { impl Solution {
pub fn new(level: &Level, number: usize) -> Self { pub fn new(level: &Level, id: usize) -> Self {
Self { Self {
solution_id: format!("solution_{number}"), solution_id: id,
level_id: level.id().to_owned(), level_id: level.id().to_owned(),
name: format!("Unnamed {number}"), name: format!("Unnamed {id}"),
board: level.init_board().unwrap_or(String::from(" ")), board: level.init_board().unwrap_or(String::from(" ")),
score: None, score: None,
} }
} }
pub fn id(&self) -> &str { pub fn new_copy(&self, id: usize) -> Self {
&self.solution_id let mut new = self.clone();
new.solution_id = id;
new.score = None;
new
}
pub fn id(&self) -> usize {
self.solution_id
} }
pub fn save(&self) { pub fn save(&self) {

View file

@ -307,3 +307,11 @@ pub fn get_scroll(rl: &RaylibHandle) -> Option<Scroll> {
None None
} }
} }
pub fn get_free_id<T>(items: &[T], id_fn: fn(&T) -> usize) -> usize {
let mut id = 0;
while items.iter().any(|i| id_fn(i) == id) {
id += 1;
}
id
}