Files
upo-rust/src/es03_game/floor.rs
Berack96 8862941152 Maze Genetation
- added maze gen
- refactored Generator
- added config for maze gen
- changed floor display to 3x instead of 2x
2024-05-18 17:49:23 +02:00

174 lines
5.9 KiB
Rust

use super::{
cell::Cell,
entities::{Entity, Position},
};
use rand_pcg::Pcg32;
use serde::{Deserialize, Serialize};
use std::{collections::VecDeque, fmt::Display};
/// Indica un piano del dungeon, in essa si possono trovare le celle in cui si
/// cammina e le entità che abitano il piano.\
/// Per poter accedere a questa struttura è necessario utilizzare FloorPtr e fare get()
#[derive(Clone, Deserialize, Serialize)]
pub struct Floor {
level: usize,
grid: Vec<Vec<Cell>>,
players: VecDeque<Entity>,
entities: VecDeque<Entity>,
rng: Pcg32,
}
impl Floor {
/// Crea un nuovo piano al livello indicato.\
/// Il piano viene creato a partire dai parametri passati in input, che sono tutte cose necessarie ad esso.
pub fn new(level: usize, rng: Pcg32, entities: Vec<Entity>, grid: Vec<Vec<Cell>>) -> Self {
Self {
level,
rng,
players: VecDeque::new(),
entities: VecDeque::from(entities),
grid,
}
}
/// Aggiunge un giocatore al piano e lo inserisce all'entrata.
pub fn add_player(&mut self, mut player: Entity) {
// todo!() check collision with other entities
player.position = self.get_entrance();
self.players.push_back(player);
}
/// Indica se il piano ha almeno un giocatore in vita o meno
pub fn has_players(&self) -> bool {
self.players.iter().any(|player| player.is_alive())
}
/// Restituisce il livello di profondità del piano
pub fn get_level(&self) -> usize {
self.level
}
/// Restituisce il generatore di numeri casuali utilizzato per qualunque cosa
/// inerente al piano (generazione di entità, applicazione di effetti...)
pub fn get_rng(&mut self) -> &mut Pcg32 {
&mut self.rng
}
/// Restituisce la cella nella posizione indicata.\
/// Con essa si può fare cio che si vuole, e quindi anche modificarla.\
/// Nel caso in cui la posizione non sia all'interno del piano, essa viene modificata
/// facendola rientrare nei limiti di esso.\
/// Es. pos(2,3) ma il piano è di max 2 allora diventa -> pos(2,2)
pub fn get_cell(&mut self, pos: &mut Position) -> &mut Cell {
let len = self.grid.len() - 1;
pos.0 = pos.0.min(len);
pos.1 = pos.1.min(len);
&mut self.grid[pos.0][pos.1]
}
/// Restituisce la posizione dell'entrata del piano.\
/// Utile come spawn per quando i giocatori arrivano al piano.
pub fn get_entrance(&mut self) -> Position {
self.grid
.iter()
.enumerate()
.find_map(|(x, vec)| {
vec.iter().enumerate().find_map(|(y, cell)| {
if let Cell::Entance = cell {
Some(Position(x, y))
} else {
None
}
})
})
.expect("Entrance of the floor should be inside the grid!")
}
/// Fa l'update di tutti i giocatori e rimuove eventualmente quelli non più in vita, restituendoli dentro un vec
pub fn update_players(&mut self) -> Vec<Entity> {
let mut remove = vec![];
for _ in 0..self.players.len() {
let mut player = self.players.pop_front().unwrap();
if player.update(self) {
self.players.push_back(player);
} else {
remove.push(player);
}
}
remove
}
/// Fa l'update di tutte le entità e rimuove eventualmente quelle non più in vita
pub fn update_entities(&mut self) {
for _ in 0..self.entities.len() {
let mut entity = self.entities.pop_front().unwrap();
if entity.update(self) {
self.entities.push_back(entity);
}
}
}
/// Crea una view del piano con l'entità partecipante all'update.
pub fn get_limited_view_floor<'a>(&'a self, entity: &'a Entity) -> FloorView<'a> {
FloorView::new(self, entity)
}
}
/// Struttura di mezzo tra un piano e il gioco vero e proprio.\
/// Utilizzata per la comunicazione con le entità per poter aggiornare quello che vedono.\
/// Infatti internamente ha solo alcuni pezzi del gioco per non far mostrare tutto.\
pub struct FloorView<'a> {
pub entity: &'a Entity,
pub floor: &'a Floor,
}
impl<'a> FloorView<'a> {
/// Crea una vista del gioco corrente secondo la visione dell'entità passata in intput.\
/// Il SimpleFloor risultante avrà il piano, entità, livello e giocatori che si trovano
/// in questo momento sul piano dell'entità passata in input.
pub fn new(floor: &'a Floor, entity: &'a Entity) -> Self {
Self {
entity: &entity,
floor: &floor,
}
}
/// Rappresentazione del piano come matrice di char
pub fn as_char_grid(&self) -> Vec<Vec<char>> {
let grid = &self.floor.grid;
let size = grid.len();
let mut grid = (0..size)
.map(|y| {
(0..size)
.flat_map(|x| {
let cell = &grid[x][y];
let ch = cell.as_char();
match cell {
Cell::Wall => [ch, ch, ch],
_ => [' ', ch, ' '],
}
})
.chain(std::iter::once('\n'))
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
let pos = &self.entity.position;
grid[pos.1][pos.0 * 3 + 1] = self.entity.direction.as_char();
grid
}
}
impl<'a> Display for FloorView<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let grid: String = self
.as_char_grid()
.iter()
.rev()
.map(|row| row.iter().collect::<String>())
.collect();
write!(f, "{}\n{}", grid, self.entity)
}
}