Added latest docs for game
This commit is contained in:
@@ -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>,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.\
|
||||
|
||||
@@ -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
4
rogue_lib/src/main.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
let seed = rand::random();
|
||||
rogue_lib::run_console("Jack".to_string(), seed);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user