Entities
- priority in config now works - changed behavior with mut self - modified box for the console
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
cell::{Confusion, Effect, InstantDamage},
|
cell::{Confusion, Effect, InstantDamage},
|
||||||
entities::Behavior,
|
entities::{Behavior, RandomMovement},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
@@ -65,7 +65,7 @@ pub struct ConfigPlayer {
|
|||||||
pub struct ConfigEntity {
|
pub struct ConfigEntity {
|
||||||
pub floors: Range<usize>,
|
pub floors: Range<usize>,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub decider: Box<dyn Behavior>,
|
pub behavior: Box<dyn Behavior>,
|
||||||
pub health: i32,
|
pub health: i32,
|
||||||
pub attack: i32,
|
pub attack: i32,
|
||||||
pub priority: u32,
|
pub priority: u32,
|
||||||
@@ -96,12 +96,19 @@ impl Default for Config {
|
|||||||
ConfigEffect {
|
ConfigEffect {
|
||||||
effect: Box::new(Confusion(10)),
|
effect: Box::new(Confusion(10)),
|
||||||
floors: 0..255,
|
floors: 0..255,
|
||||||
priority: 1,
|
priority: 10,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
effects_total: 45,
|
effects_total: 45,
|
||||||
entities: vec![],
|
entities: vec![ConfigEntity {
|
||||||
entities_total: 0,
|
floors: 0..255,
|
||||||
|
name: "Basic enemy".to_string(),
|
||||||
|
behavior: Box::new(RandomMovement::new()),
|
||||||
|
health: 30,
|
||||||
|
attack: 10,
|
||||||
|
priority: 1,
|
||||||
|
}],
|
||||||
|
entities_total: 10,
|
||||||
player_stats: ConfigPlayer {
|
player_stats: ConfigPlayer {
|
||||||
health: 100,
|
health: 100,
|
||||||
attack: 10,
|
attack: 10,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use super::{
|
use super::{
|
||||||
cell::Effect,
|
cell::{Cell, Effect},
|
||||||
floor::{Floor, FloorView},
|
floor::{Floor, FloorView},
|
||||||
};
|
};
|
||||||
use dyn_clone::{clone_trait_object, DynClone};
|
use dyn_clone::{clone_trait_object, DynClone};
|
||||||
use rand::Rng;
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_pcg::Pcg32;
|
use rand_pcg::Pcg32;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::VecDeque, fmt::Display, mem};
|
use std::{collections::VecDeque, fmt::Display, mem};
|
||||||
@@ -17,12 +17,13 @@ pub struct Position(pub usize, pub usize);
|
|||||||
|
|
||||||
/// Indica la direzione dove una entità sta guardando.\
|
/// Indica la direzione dove una entità sta guardando.\
|
||||||
/// È possibile anche non guardare in nessuna direzione tramite None.
|
/// È possibile anche non guardare in nessuna direzione tramite None.
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Deserialize, Serialize)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy, Default, Debug, Deserialize, Serialize)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
#[default]
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ impl Display for Direction {
|
|||||||
pub struct Entity {
|
pub struct Entity {
|
||||||
name: String,
|
name: String,
|
||||||
effects: VecDeque<Box<dyn Effect>>,
|
effects: VecDeque<Box<dyn Effect>>,
|
||||||
behavior: Box<dyn Behavior>,
|
behavior: Option<Box<dyn Behavior>>,
|
||||||
pub buffer: Action,
|
pub buffer: Action,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
@@ -106,7 +107,7 @@ impl Entity {
|
|||||||
pub fn new(name: String, health: i32, attack: i32, behavior: Box<dyn Behavior>) -> Self {
|
pub fn new(name: String, health: i32, attack: i32, behavior: Box<dyn Behavior>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
behavior,
|
behavior: Some(behavior),
|
||||||
position: Position(0, 0),
|
position: Position(0, 0),
|
||||||
attack,
|
attack,
|
||||||
health,
|
health,
|
||||||
@@ -164,33 +165,41 @@ impl Entity {
|
|||||||
/// Permette all'entità di mostrare il piano in cui si trova e di fare una mossa.\
|
/// Permette all'entità di mostrare il piano in cui si trova e di fare una mossa.\
|
||||||
/// Il piano viene mostrato tramite il behavior dell'entità e successivamente viene chiesto di fare un'azione.\
|
/// Il piano viene mostrato tramite il behavior dell'entità e successivamente viene chiesto di fare un'azione.\
|
||||||
/// Dopodichè vengono calcolati tutti gli effetti che devono essere applicati all'entità.\
|
/// Dopodichè vengono calcolati tutti gli effetti che devono essere applicati all'entità.\
|
||||||
/// Nel caso in cui l'entità non sia più in vita questo metodo ritornerà false
|
/// Nel caso in cui l'entità non sia più in vita questo metodo ritornerà None
|
||||||
/// e non permetterà all'entità di fare update.\
|
/// e l' entità smetterà di esistere.\
|
||||||
/// Nel caso in cui l'entità non riesca a fare l'update viene ritornato false.\
|
/// Nel caso in cui l'entità non riesca a fare l'update viene ritornato None.\
|
||||||
/// Cio significa che l'entità verrà rimossa dal gioco.
|
/// Cio significa che l'entità verrà rimossa dal gioco.
|
||||||
pub fn update(&mut self, floor: &mut Floor) -> bool {
|
pub fn update(mut self, floor: &mut Floor) -> Option<Self> {
|
||||||
|
let mut behavior = mem::take(&mut self.behavior).unwrap();
|
||||||
|
|
||||||
if !self.is_alive() {
|
if !self.is_alive() {
|
||||||
self.behavior.you_died(floor.get_limited_view_floor(self));
|
return self.die(behavior, floor);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.behavior.update(floor.get_limited_view_floor(self));
|
behavior.update(floor.get_limited_view_floor(&self));
|
||||||
let action = self.compute_action(floor);
|
let action = self.compute_action(&mut behavior, floor);
|
||||||
if action.is_none() {
|
if action.is_none() {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_alive() {
|
if !self.is_alive() {
|
||||||
self.behavior.you_died(floor.get_limited_view_floor(self));
|
return self.die(behavior, floor);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compute_effects(floor);
|
self.compute_effects(floor);
|
||||||
if !self.is_alive() {
|
if !self.is_alive() {
|
||||||
self.behavior.you_died(floor.get_limited_view_floor(self));
|
return self.die(behavior, floor);
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
true
|
|
||||||
|
self.behavior = Some(behavior);
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// metodo usato per la rimozione dell' entità e del suo behavior
|
||||||
|
fn die(self, mut behavior: Box<dyn Behavior>, floor: &Floor) -> Option<Self> {
|
||||||
|
let view = floor.get_limited_view_floor(&self);
|
||||||
|
behavior.on_death(view);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// calcola gli effetti e li applica all'entità.
|
/// calcola gli effetti e li applica all'entità.
|
||||||
@@ -204,8 +213,8 @@ impl Entity {
|
|||||||
}
|
}
|
||||||
/// prende una decisione e applica l'azione da fare
|
/// prende una decisione e applica l'azione da fare
|
||||||
/// L'azione compiuta viene restituita, altrimenti None
|
/// L'azione compiuta viene restituita, altrimenti None
|
||||||
fn compute_action(&mut self, floor: &mut Floor) -> Option<Action> {
|
fn compute_action(&mut self, behavior: &mut Box<dyn Behavior>, floor: &mut Floor) -> Option<Action> {
|
||||||
let action = self.behavior.get_next_action()?;
|
let action = behavior.get_next_action()?;
|
||||||
let action = match self.buffer {
|
let action = match self.buffer {
|
||||||
Action::DoNothing => action,
|
Action::DoNothing => action,
|
||||||
_ => mem::replace(&mut self.buffer, Action::DoNothing),
|
_ => mem::replace(&mut self.buffer, Action::DoNothing),
|
||||||
@@ -236,10 +245,11 @@ impl Display for Entity {
|
|||||||
|
|
||||||
/// Azione che una qualsiasi entità può fare.
|
/// Azione che una qualsiasi entità può fare.
|
||||||
/// L'azione DoNothing permette all'entità di saltare il turno nel caso in cui sia utile.
|
/// L'azione DoNothing permette all'entità di saltare il turno nel caso in cui sia utile.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Move(Direction),
|
Move(Direction),
|
||||||
//Attack(Direction),
|
//Attack(Direction),
|
||||||
|
#[default]
|
||||||
DoNothing,
|
DoNothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +267,7 @@ impl Action {
|
|||||||
direction.move_from(&mut entity.position);
|
direction.move_from(&mut entity.position);
|
||||||
entity.direction = direction;
|
entity.direction = direction;
|
||||||
|
|
||||||
let cell = floor.get_cell(&entity.position);
|
let cell = floor.get_cell_mut(&entity.position);
|
||||||
cell.entity_over(entity);
|
cell.entity_over(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,12 +293,14 @@ pub trait Behavior: DynClone + core::fmt::Debug {
|
|||||||
/// In questo metodo viene passata una struttura che contiene una rappresentazione del
|
/// In questo metodo viene passata una struttura che contiene una rappresentazione del
|
||||||
/// piano semplice, avente solo delle informazioni parziali.\
|
/// piano semplice, avente solo delle informazioni parziali.\
|
||||||
/// Questo serve a mostrare eventualmente delle possibili informazioni all'utente
|
/// Questo serve a mostrare eventualmente delle possibili informazioni all'utente
|
||||||
/// o di registrare dei valori per l'algoritmo di generazione delle azioni.
|
/// o di registrare dei valori per l'algoritmo di generazione delle azioni.\
|
||||||
fn update(&self, floor: FloorView);
|
/// Non è necessario implementarla.
|
||||||
|
fn update(&mut self, _view: FloorView) {}
|
||||||
/// Funzione che viene richiamata quando l'entità muore.\
|
/// Funzione che viene richiamata quando l'entità muore.\
|
||||||
/// I parametri servono a far vedere un'ultima volta i dati del piano corrente all'entità
|
/// I parametri servono a far vedere un'ultima volta i dati del piano corrente all'entità
|
||||||
/// in modo che possa eventualmente fare ulteriori calcoli.
|
/// in modo che possa eventualmente fare ulteriori calcoli.\
|
||||||
fn you_died(&self, floor: FloorView);
|
/// Non è necessario implementarla.
|
||||||
|
fn on_death(&mut self, _view: FloorView) {}
|
||||||
/// Genera una azione che poi verrà usata per l'entità associata.\
|
/// Genera una azione che poi verrà usata per l'entità associata.\
|
||||||
/// L'azione può essere generata in qualunque modo: casuale, sempre la stessa,
|
/// L'azione può essere generata in qualunque modo: casuale, sempre la stessa,
|
||||||
/// tramite interazione con console, o tramite una connessione ad un client.\
|
/// tramite interazione con console, o tramite una connessione ad un client.\
|
||||||
@@ -296,7 +308,7 @@ pub trait Behavior: DynClone + core::fmt::Debug {
|
|||||||
/// Nel caso in cui venga restituito None come valore, l'entità verrà rimossa dal gioco.\
|
/// Nel caso in cui venga restituito None come valore, l'entità verrà rimossa dal gioco.\
|
||||||
/// Questo viene fatto in modo che si possa avere una possibilità di rimozione del giocatore,
|
/// Questo viene fatto in modo che si possa avere una possibilità di rimozione del giocatore,
|
||||||
/// ma anche una possibilità che alcune entità rare possano sparire.
|
/// ma anche una possibilità che alcune entità rare possano sparire.
|
||||||
fn get_next_action(&self) -> Option<Action>;
|
fn get_next_action(&mut self) -> Option<Action>;
|
||||||
}
|
}
|
||||||
clone_trait_object!(Behavior);
|
clone_trait_object!(Behavior);
|
||||||
|
|
||||||
@@ -306,9 +318,37 @@ clone_trait_object!(Behavior);
|
|||||||
pub struct Immovable;
|
pub struct Immovable;
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl Behavior for Immovable {
|
impl Behavior for Immovable {
|
||||||
fn update(&self, _floor: FloorView) {}
|
fn get_next_action(&mut self) -> Option<Action> {
|
||||||
fn you_died(&self, _floor: FloorView) {}
|
|
||||||
fn get_next_action(&self) -> Option<Action> {
|
|
||||||
Some(Action::DoNothing)
|
Some(Action::DoNothing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Semplice implementazione di un possibile comportamento di una entità.\
|
||||||
|
/// In questo caso l'entità si mouverà in maniera casuale evitando le caselle speciali.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RandomMovement {
|
||||||
|
action: Action,
|
||||||
|
rng: Pcg32,
|
||||||
|
}
|
||||||
|
impl RandomMovement {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
action: Action::DoNothing,
|
||||||
|
rng: Pcg32::seed_from_u64(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[typetag::serde]
|
||||||
|
impl Behavior for RandomMovement {
|
||||||
|
fn update(&mut self, view: FloorView) {
|
||||||
|
let dir = Direction::random(&mut self.rng);
|
||||||
|
let mut pos = view.entity.position.clone();
|
||||||
|
dir.move_from(&mut pos);
|
||||||
|
if let Cell::Empty = view.floor.get_cell(&pos) {
|
||||||
|
self.action = Action::Move(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_next_action(&mut self) -> Option<Action> {
|
||||||
|
Some(mem::take(&mut self.action))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,13 +68,25 @@ impl Floor {
|
|||||||
/// Nel caso in cui la posizione non sia all'interno del piano, essa viene modificata
|
/// Nel caso in cui la posizione non sia all'interno del piano, essa viene modificata
|
||||||
/// facendola rientrare nei limiti di esso.\
|
/// facendola rientrare nei limiti di esso.\
|
||||||
/// Es. pos(2,3) ma il piano è di max 2 allora diventa -> pos(2,2)
|
/// Es. pos(2,3) ma il piano è di max 2 allora diventa -> pos(2,2)
|
||||||
pub fn get_cell(&mut self, pos: &Position) -> &mut Cell {
|
pub fn get_cell_mut(&mut self, pos: &Position) -> &mut Cell {
|
||||||
let len = self.grid.len() - 1;
|
let len = self.grid.len() - 1;
|
||||||
let x = pos.0.min(len);
|
let x = pos.0.min(len);
|
||||||
let y = pos.1.min(len);
|
let y = pos.1.min(len);
|
||||||
&mut self.grid[x][y]
|
&mut self.grid[x][y]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restituisce la cella nella posizione indicata.\
|
||||||
|
/// Con essa si può leggere la cella senza però la possibilità di 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(&self, pos: &Position) -> &Cell {
|
||||||
|
let len = self.grid.len() - 1;
|
||||||
|
let x = pos.0.min(len);
|
||||||
|
let y = pos.1.min(len);
|
||||||
|
&self.grid[x][y]
|
||||||
|
}
|
||||||
|
|
||||||
/// Restituisce la posizione dell'entrata del piano.\
|
/// Restituisce la posizione dell'entrata del piano.\
|
||||||
/// Utile come spawn per quando i giocatori arrivano al piano.
|
/// Utile come spawn per quando i giocatori arrivano al piano.
|
||||||
pub fn get_entrance(&mut self) -> Position {
|
pub fn get_entrance(&mut self) -> Position {
|
||||||
@@ -93,20 +105,6 @@ impl Floor {
|
|||||||
.expect("Entrance of the floor should be inside the grid!")
|
.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 next_floor = 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 {
|
|
||||||
next_floor.push(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_floor
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ritorna un eventuale giocatore che si trova sopra la cella di uscita del piano.\
|
/// Ritorna un eventuale giocatore che si trova sopra la cella di uscita del piano.\
|
||||||
/// Nel caso in cui non ci siano giocatori sopra, questo metodo ritornerà None.
|
/// Nel caso in cui non ci siano giocatori sopra, questo metodo ritornerà None.
|
||||||
pub fn get_player_at_exit(&mut self) -> Option<Entity> {
|
pub fn get_player_at_exit(&mut self) -> Option<Entity> {
|
||||||
@@ -130,11 +128,21 @@ impl Floor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fa l'update di tutti i giocatori e rimuove quelli non più in vita
|
||||||
|
pub fn update_players(&mut self) {
|
||||||
|
for _ in 0..self.players.len() {
|
||||||
|
let player = self.players.pop_front().unwrap();
|
||||||
|
if let Some(player) = player.update(self) {
|
||||||
|
self.players.push_back(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Fa l'update di tutte le entità e rimuove eventualmente quelle non più in vita
|
/// Fa l'update di tutte le entità e rimuove eventualmente quelle non più in vita
|
||||||
pub fn update_entities(&mut self) {
|
pub fn update_entities(&mut self) {
|
||||||
for _ in 0..self.entities.len() {
|
for _ in 0..self.entities.len() {
|
||||||
let mut entity = self.entities.pop_front().unwrap();
|
let entity = self.entities.pop_front().unwrap();
|
||||||
if entity.update(self) {
|
if let Some(entity) = entity.update(self) {
|
||||||
self.entities.push_back(entity);
|
self.entities.push_back(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub struct Dungeon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Dungeon {
|
impl Dungeon {
|
||||||
/// Crea una nuova istanza di un dungeon con le configurazioni i default
|
/// Crea una nuova istanza di un dungeon con le configurazioni di default
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::new_with(Config::default())
|
Self::new_with(Config::default())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,16 +74,20 @@ impl<'a> Generator<'a> {
|
|||||||
self.rand_place_effects(&mut grid);
|
self.rand_place_effects(&mut grid);
|
||||||
Floor::new(self.level, self.rng, vec![], grid)
|
Floor::new(self.level, self.rng, vec![], grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// todo!() docs
|
||||||
|
fn rand_place_entities(&mut self, grid: &mut Vec<Vec<Cell>>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
/// piazza gli effetti della confgurazione in modo casuale su tutto il piano.\
|
/// piazza gli effetti della confgurazione in modo casuale su tutto il piano.\
|
||||||
/// essi vengono piazzati solamente sulle celle Empty
|
/// essi vengono piazzati solamente sulle celle Empty
|
||||||
fn rand_place_effects(&mut self, grid: &mut Vec<Vec<Cell>>) {
|
fn rand_place_effects(&mut self, grid: &mut Vec<Vec<Cell>>) {
|
||||||
let total = self.config.effects_total;
|
let effects = vec_filter(&self.config.effects, |e| {
|
||||||
let original = &self.config.effects;
|
e.floors.contains(&self.level).then(|| (e.priority, e))
|
||||||
let effects = Self::vec_filter(original, |val| val.floors.contains(&self.level));
|
});
|
||||||
|
|
||||||
for _ in 0..total {
|
for _ in 0..self.config.effects_total {
|
||||||
let index = self.rng.gen_range(0..effects.len());
|
let effect = vec_get_sample(&effects, &mut self.rng).effect.clone();
|
||||||
let effect = effects[index].effect.clone();
|
|
||||||
let cell = Cell::Special(effect);
|
let cell = Cell::Special(effect);
|
||||||
self.rand_place(grid, cell, 0..self.size, 0..self.size);
|
self.rand_place(grid, cell, 0..self.size, 0..self.size);
|
||||||
}
|
}
|
||||||
@@ -106,14 +110,29 @@ impl<'a> Generator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// crea una vista del vettore passato in input dopo aver applicato la funzione di filtro
|
}
|
||||||
fn vec_filter<T: Clone>(original: &Vec<T>, filter: impl Fn(&T) -> bool) -> Vec<T> {
|
|
||||||
original
|
/// crea una vista del vettore passato in input dopo aver applicato la funzione di filtro
|
||||||
.clone()
|
pub fn vec_filter<T, F>(original: &Vec<T>, filter: F) -> Vec<(f32, &T)>
|
||||||
.into_iter()
|
where
|
||||||
.filter_map(|val| filter(&val).then(|| val))
|
F: FnMut(&T) -> Option<(u32, &T)>,
|
||||||
.collect()
|
{
|
||||||
}
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// todo!() docs
|
||||||
|
pub fn vec_get_sample<'a, T>(vec: &Vec<(f32, &'a T)>, rng: &mut Pcg32) -> &'a T {
|
||||||
|
let sample = rng.gen_range(0.0..1.0);
|
||||||
|
vec.iter().filter(|(p, _)| *p >= sample).next().unwrap().1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utile per la generazione del labirinto.\
|
/// Utile per la generazione del labirinto.\
|
||||||
|
|||||||
@@ -56,10 +56,41 @@ pub fn run_console(player: String, seed: u64) {
|
|||||||
game.add_player(player, Box::new(ConsoleInput));
|
game.add_player(player, Box::new(ConsoleInput));
|
||||||
|
|
||||||
while game.has_players() {
|
while game.has_players() {
|
||||||
|
let _ = game.save("save.json");
|
||||||
game.compute_turn();
|
game.compute_turn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// todo!() add docs
|
||||||
|
pub fn box_of(
|
||||||
|
size: usize,
|
||||||
|
title: String,
|
||||||
|
iter: impl Iterator<Item = String>,
|
||||||
|
) -> impl Iterator<Item = String> {
|
||||||
|
assert!(
|
||||||
|
size >= title.len(),
|
||||||
|
"Title must not exceed the size of the box!"
|
||||||
|
);
|
||||||
|
|
||||||
|
let len = (size - title.len()) / 2;
|
||||||
|
let correction = if 2 * len + title.len() < size { 1 } else { 0 };
|
||||||
|
|
||||||
|
std::iter::once("╔".to_string())
|
||||||
|
.chain(std::iter::repeat("═".to_string()).take(len + 1))
|
||||||
|
.chain(std::iter::once(title))
|
||||||
|
.chain(std::iter::repeat("═".to_string()).take(len + 1 + correction))
|
||||||
|
.chain(std::iter::once("╗\n".to_string()))
|
||||||
|
.chain(iter.map(|string| {
|
||||||
|
std::iter::once("║ ".to_string())
|
||||||
|
.chain(std::iter::once(string))
|
||||||
|
.chain(std::iter::once(" ║\n".to_string()))
|
||||||
|
.collect()
|
||||||
|
}))
|
||||||
|
.chain(std::iter::once("╚".to_string()))
|
||||||
|
.chain(std::iter::repeat("═".to_string()).take(size + 2))
|
||||||
|
.chain(std::iter::once("╝\n".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
const COLOR_RESET: &str = "\x1b[0m";
|
const COLOR_RESET: &str = "\x1b[0m";
|
||||||
const COLOR_EFFECT: &str = "\x1b[95m";
|
const COLOR_EFFECT: &str = "\x1b[95m";
|
||||||
const COLOR_ENEMY: &str = "\x1b[38;5;1m";
|
const COLOR_ENEMY: &str = "\x1b[38;5;1m";
|
||||||
@@ -77,9 +108,8 @@ impl ConsoleInput {
|
|||||||
let mut term = console::Term::stdout();
|
let mut term = console::Term::stdout();
|
||||||
let _ = term.clear_screen();
|
let _ = term.clear_screen();
|
||||||
let _ = term.write_fmt(format_args!(
|
let _ = term.write_fmt(format_args!(
|
||||||
"{}Floor lv.{:2} - {}\n{other}\n",
|
"{}{}\n{other}\n",
|
||||||
Self::floor_as_string(&floor),
|
Self::floor_as_string(&floor),
|
||||||
floor.floor.get_level(),
|
|
||||||
Self::entity_as_string(floor.entity),
|
Self::entity_as_string(floor.entity),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -122,33 +152,19 @@ impl ConsoleInput {
|
|||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
Self::box_of(size, iter).collect()
|
let title = format!(" Floor lv.{:2} ", floor.floor.get_level());
|
||||||
}
|
box_of(size, title, iter).collect()
|
||||||
/// todo!() add docs
|
|
||||||
fn box_of(size: usize, iter: impl Iterator<Item = String>) -> impl Iterator<Item = String> {
|
|
||||||
std::iter::once("╔".to_string())
|
|
||||||
.chain(std::iter::repeat("═".to_string()).take(size + 2))
|
|
||||||
.chain(std::iter::once("╗\n".to_string()))
|
|
||||||
.chain(iter.map(|string| {
|
|
||||||
std::iter::once("║ ".to_string())
|
|
||||||
.chain(std::iter::once(string))
|
|
||||||
.chain(std::iter::once(" ║\n".to_string()))
|
|
||||||
.collect()
|
|
||||||
}))
|
|
||||||
.chain(std::iter::once("╚".to_string()))
|
|
||||||
.chain(std::iter::repeat("═".to_string()).take(size + 2))
|
|
||||||
.chain(std::iter::once("╝\n".to_string()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl Behavior for ConsoleInput {
|
impl Behavior for ConsoleInput {
|
||||||
fn update(&self, floor: FloorView) {
|
fn update(&mut self, floor: FloorView) {
|
||||||
self.print_floor(floor, "".to_string());
|
self.print_floor(floor, "".to_string());
|
||||||
}
|
}
|
||||||
fn you_died(&self, floor: FloorView) {
|
fn on_death(&mut self, floor: FloorView) {
|
||||||
self.print_floor(floor, "YOU DIED!".to_string());
|
self.print_floor(floor, "YOU DIED!".to_string());
|
||||||
}
|
}
|
||||||
fn get_next_action(&self) -> Option<Action> {
|
fn get_next_action(&mut self) -> Option<Action> {
|
||||||
let mut term = console::Term::stdout();
|
let mut term = console::Term::stdout();
|
||||||
let _ = term.write("Insert your action [wasd or space for nothing]: ".as_bytes());
|
let _ = term.write("Insert your action [wasd or space for nothing]: ".as_bytes());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user