Added latest docs for game

This commit is contained in:
2024-05-31 09:15:09 +02:00
parent 9df26d931b
commit 4030abf186
6 changed files with 83 additions and 42 deletions

View File

@@ -206,7 +206,10 @@ pub struct FloorView<'a> {
pub floor: &'a Floor,
}
/// todo!() add docs
/// Struttura di mezzo usata per far visualizzare una cella e
/// l'eventuale entità che si trova sopra.\
/// Questa truttura viene usata solamente per prendere i valori in modo read-only
/// e viene utilizzata da FloorView nel metodo get_grid.
pub struct CellView<'a> {
pub position: Position,
pub entity: Option<&'a Entity>,

View File

@@ -92,7 +92,7 @@ impl Dungeon {
pub fn compute_turn(&mut self) {
let moved = self.floors.iter_mut().fold(None, |moved, floor| {
if floor.has_players() {
let _ = floor.update_players(); //todo!() evantually return the dead players? idk
let _ = floor.update_players();
floor.update_entities();
}

View File

@@ -16,8 +16,6 @@ use std::{
ops::Range,
};
// todo!() enemies vec configuration?
/// Generatore del gioco che può creare dei piani del dungeon.
/// Idealmente questo generatore si comporta come il pattern Factory.
/// Per far si che funzioni ha bisongo di un seed per la generazione del piano
@@ -81,15 +79,18 @@ impl<'a> Generator<'a> {
Floor::new(self.level, self.rng, entities, grid)
}
/// todo!() docs
/// Permette di piazzare delle entità in modo casuale nell piano passato.\
/// Le entità verranno messe solamente sopra celle Empty e non sopvrapposte fra di loro.\
/// Alla fine verrà restituito un vettore contenente tutte le entità che dovrà poi essere associato
/// al piano in fase di creazione.
fn rand_place_entities(&mut self, grid: &mut Vec<Vec<Cell>>) -> Vec<Entity> {
let entities = vec_filter(&self.config.entities, |e| {
let entities = ProbVec::new(&self.config.entities, |e| {
e.floors.contains(&self.level).then(|| (e.priority, e))
});
let mut result: Vec<Entity> = vec![];
for _ in 0..self.config.entities_total {
let config = vec_get_sample(&entities, &mut self.rng).clone();
let config = entities.sample(&mut self.rng).clone();
let mut entity = Entity::new(
config.name.clone(),
config.health,
@@ -111,20 +112,19 @@ impl<'a> Generator<'a> {
/// piazza gli effetti della confgurazione in modo casuale su tutto il piano.\
/// essi vengono piazzati solamente sulle celle Empty
fn rand_place_effects(&mut self, grid: &mut Vec<Vec<Cell>>) {
let effects = vec_filter(&self.config.effects, |e| {
let effects = ProbVec::new(&self.config.effects, |e| {
e.floors.contains(&self.level).then(|| (e.priority, e))
});
for _ in 0..self.config.effects_total {
let effect = vec_get_sample(&effects, &mut self.rng).effect.clone();
let effect = effects.sample(&mut self.rng).effect.clone();
let cell = Cell::Special(effect);
let pos = self.rand_empty_cell_pos(grid, 0..self.size, 0..self.size);
grid[pos.0][pos.1] = cell;
}
}
/// piazza una cella in un punto casuale del piano.\
/// il metodo contiuna a provare a piazzare la cella finche non trova una cella Empty.
/// todo!() docs
/// piazza una cella in un punto casuale tra i range inseriti.\
/// il metodo continua a provare a piazzare la cella finche non trova una cella Empty.
fn rand_empty_cell_pos(
&mut self,
grid: &mut Vec<Vec<Cell>>,
@@ -141,27 +141,49 @@ impl<'a> Generator<'a> {
}
}
/// crea una vista del vettore passato in input dopo aver applicato la funzione di filtro
pub fn vec_filter<T, F>(original: &Vec<T>, filter: F) -> Vec<(f32, &T)>
where
F: FnMut(&T) -> Option<(u32, &T)>,
{
let temp = original.iter().filter_map(filter).collect::<Vec<_>>();
let max = temp.iter().fold(0, |a, b| a.max(b.0)) + 1;
let total = temp.iter().map(|(p, _)| (max - *p) as f32).sum::<f32>();
let mut accum = 0.0;
temp.into_iter()
.map(|(p, item)| {
accum += (max - p) as f32 / total;
(accum, item)
})
.collect()
pub struct ProbVec<'a, T> {
prob: Vec<(f32, &'a T)>,
}
/// todo!() docs
pub fn vec_get_sample<'a, T>(vec: &Vec<(f32, &'a T)>, rng: &mut impl Rng) -> &'a T {
let sample = rng.gen_range(0.0..1.0);
vec.iter().filter(|(p, _)| *p >= sample).next().unwrap().1
impl<'a, T> ProbVec<'a, T> {
/// Crea una vista del vettore passato in input dopo aver applicato la funzione di filtro.\
/// Il vettore risultante avrà una tupla contenente l'elemento T e la sua probabilità
/// di essere scelto fra tutti gli elementi del vettore.\
/// Quindi la somma di tutte le probabilità sarà 1.0 (floating arithmetic permettendo).\
/// La funzione passata in input deve restituire un valore che più vicino a 0 è, maggiore la priorità
/// dell'elemento di essere selezionato.\
/// L'algoritmo poi penserà a trasformare le priorità in probabilità secondo questa logica:\
/// A, priorità 1 e B, priorità 2 => A, 0.66 e B, 0.33\
/// Ciò significa che A ha probabilità doppia rispetto a B di essere scelta.
pub fn new<F>(original: &'a Vec<T>, filter: F) -> Self
where
F: FnMut(&T) -> Option<(u32, &T)>,
{
let temp = original.iter().filter_map(filter).collect::<Vec<_>>();
let max = temp.iter().fold(0, |a, b| a.max(b.0)) + 1;
let total = temp.iter().map(|(p, _)| (max - *p) as f32).sum::<f32>();
let mut accum = 0.0;
let prob = temp
.into_iter()
.map(|(p, item)| {
accum += (max - p) as f32 / total;
(accum, item)
})
.collect();
Self { prob }
}
/// Dato un vettore generato secondo la funzione vec_filter, essa ne prende un valore casuale
/// utilizzando le probabilità interne del vettore.\
pub fn sample(&self, rng: &mut impl Rng) -> &'a T {
let sample = rng.gen_range(0.0..1.0);
self.prob
.iter()
.filter(|(p, _)| *p >= sample)
.next()
.unwrap()
.1
}
}
/// Utile per la generazione del labirinto.\

View File

@@ -61,7 +61,12 @@ pub fn run_console(player: String, seed: u64) {
}
}
/// todo!() add docs
/// Permette di aggiungere all'iteratore passato in input una box
/// intesa come una cornice attorno alle stringhe passate.\
/// Questa funzione è utile nel casoin cui le stringhe generate dall'iteratore
/// abbiano tutte la stessa lunghezza.\
/// La cornice generata sarà composta dai seguenti caratteri: ║ ═ ╔ ╗ ╚ ╝.\
/// Eventualmente si può passare un titolo da aggiungere in cima alla cornice.
pub fn box_of(
size: usize,
title: String,
@@ -91,10 +96,13 @@ pub fn box_of(
.chain(std::iter::once("\n".to_string()))
}
// list of colors and other formatting thigy
// https://misc.flogisoft.com/bash/tip_colors_and_formatting
// https://gist.github.com/JBlond/2fea43a3049b38287e5e9cefc87b2124
const COLOR_RESET: &str = "\x1b[0m";
const COLOR_EFFECT: &str = "\x1b[95m";
const COLOR_ENEMY: &str = "\x1b[38;5;1m";
const COLOR_PLAYER: &str = "\x1b[38;5;166m";
const COLOR_PLAYER: &str = "\x1b[38;5;208m";
const COLOR_PLAYER_HEALTH: &str = "\x1b[31m";
/// Implementazione di una possibile interfaccia console.\
@@ -103,7 +111,8 @@ const COLOR_PLAYER_HEALTH: &str = "\x1b[31m";
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ConsoleInput;
impl ConsoleInput {
/// todo!() add docs
/// Stampa il piano passato in input.\
/// Verranno usate altre funzioni di appoggio per formattare al meglio gli oggetti passati.
fn print_floor(&self, floor: FloorView, other: String) {
let mut term = console::Term::stdout();
let _ = term.clear_screen();
@@ -113,7 +122,8 @@ impl ConsoleInput {
Self::entity_as_string(floor.entity),
));
}
/// todo!() add docs
/// Permette di prendere una stringa con le informazioni dell'entità.\
/// Alcune di esse sono il nome, la vita massima e quanto ne rimane sottoforma di HP bar.
fn entity_as_string(entity: &Entity) -> String {
let times = 20;
let health_bar = (entity.get_health() * times) / entity.get_health_max();
@@ -127,7 +137,9 @@ impl ConsoleInput {
entity.get_health_max()
)
}
/// todo!() add docs
/// Permette di prendere una stringa con le informazioni del piano.\
/// Il risultato sarà una vista del piano con raggio 5 (scelto arbitrariamente),
/// e che quindi restituirà una porzione di campo 10x10 evidenziando eventuali celle o entità.
fn floor_as_string(floor: &FloorView) -> String {
let view = 5;
let size = (2 * view) * 3;
@@ -186,11 +198,11 @@ impl Behavior for ConsoleInput {
let _ = term.write_line("[z] => for doing nothing");
let _ = term.write_line("[q] => for exit the game");
let _ = term.write("Press ANY button to continue...".as_bytes());
let _ = term.read_char();
let _ = term.clear_line();
let _ = term.read_char(); // waiting for user acknowledgment
let _ = term.clear_line(); // clear line "press button..."
let _ = term.clear_last_lines(4); // this number is from the previous message (4 total lines of help)
let _ = term.move_cursor_up(1);
let _ = term.move_cursor_right(prompt.len());
let _ = term.move_cursor_up(1); // moving up since the first write_line put me down by one
let _ = term.move_cursor_right(prompt.len()); // moving at the end of the prompt
}
_ => (),
}

4
rogue_lib/src/main.rs Normal file
View File

@@ -0,0 +1,4 @@
fn main() {
let seed = rand::random();
rogue_lib::run_console("Jack".to_string(), seed);
}

View File

@@ -346,12 +346,12 @@ fn test_game_initial_config() {
fn test_generator_priority() {
let mut vec = vec![(1_u32, &"a"), (3, &"b"), (2, &"c")].into_iter();
let vec1 = vec!["", "", ""];
let vec = rogue_lib::generator::vec_filter(&vec1, |_| vec.next());
let prob = rogue_lib::generator::ProbVec::new(&vec1, |_| vec.next());
let mut sum: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
let mut rng = <rand_pcg::Pcg32 as rand::SeedableRng>::seed_from_u64(0);
let tot = 600000;
for _ in 0..tot {
let sample = rogue_lib::generator::vec_get_sample(&vec, &mut rng);
let sample = prob.sample(&mut rng);
let val = sum.entry(*sample).or_default();
*val += 1;
}