wOxlf/src/game/game_state.rs

142 lines
4.0 KiB
Rust

use std::collections::HashMap;
use std::str::FromStr;
use chrono::{DateTime, Duration, Utc};
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::error::WoxlfError;
use crate::game::player_data::PlayerData;
use crate::game::Phase;
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GameState {
pub game_name: String,
pub phase_number: u64,
pub current_phase: Phase,
pub starting_phase: Phase,
pub phase_end_time: DateTime<Utc>,
pub player_data: Vec<PlayerData>,
}
impl GameState {
pub fn new(starting_phase: Phase, starting_phase_duration: Duration, game_name: &str) -> Self {
let phase_end_time = Utc::now() + starting_phase_duration;
Self {
game_name: game_name.to_string(),
phase_number: 1,
current_phase: starting_phase,
phase_end_time,
player_data: vec![],
starting_phase,
}
}
pub fn get_player_from_channel(&self, channel_id: u64) -> Option<&PlayerData> {
self.player_data.iter().find(|p| p.channel == channel_id)
}
pub fn get_player_from_discord_id(&self, discord_id: u64) -> Option<&PlayerData> {
self.player_data.iter().find(|p| p.discord_id == discord_id)
}
pub fn get_player_from_channel_mut(&mut self, channel_id: u64) -> Option<&mut PlayerData> {
self.player_data
.iter_mut()
.find(|p| p.channel == channel_id)
}
pub fn get_player_by_codename(&self, codename: &str) -> Option<PlayerData> {
self.player_data
.iter()
.find(|p| p.codename.to_lowercase() == codename.to_lowercase())
.cloned()
}
pub fn next_phase(&mut self, duration: Duration) {
if self.current_phase == Phase::Night {
self.current_phase = Phase::Day
} else {
self.current_phase = Phase::Night
}
if self.current_phase == self.starting_phase {
self.phase_number += 1;
}
for player in &mut self.player_data {
player.clear()
}
self.set_phase_end_time(duration);
}
pub fn set_phase_end_time(&mut self, duration: Duration) {
self.phase_end_time = Utc::now() + duration;
}
pub fn add_time_to_phase(&mut self, duration: Duration) {
self.phase_end_time = self.phase_end_time + duration;
}
pub fn get_vote_tallies(&self) -> HashMap<String, u32> {
let mut vote_set: HashMap<String, u32> = HashMap::new();
for player in &self.player_data {
if let Some(vote_target) = player.vote_target {
let target = self.get_player_from_discord_id(vote_target);
if let Some(target) = target {
*vote_set.entry(target.codename.clone()).or_insert(0) += 1;
}
}
}
vote_set
}
}
#[derive(Debug, Clone)]
pub struct PhaseDuration(Duration);
impl From<PhaseDuration> for Duration {
fn from(dur: PhaseDuration) -> Self {
dur.0
}
}
impl FromStr for PhaseDuration {
type Err = WoxlfError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let re = Regex::new(r"(((?P<hour>[0-9]*)h)?((?P<min>[0-9]*)m)?)").unwrap();
let mut duration = Duration::hours(0);
if re.is_match(s) {
let cap = re.captures_iter(s).next().unwrap();
if let Some(hour_str) = cap.name("hour") {
let hours: i64 = hour_str
.as_str()
.parse()
.map_err(|_| WoxlfError::DurationParseError)?;
duration = duration + Duration::hours(hours);
}
if let Some(minute_str) = cap.name("min") {
let minutes: i64 = minute_str
.as_str()
.parse()
.map_err(|_| WoxlfError::DurationParseError)?;
duration = duration + Duration::minutes(minutes);
}
Ok(PhaseDuration(duration))
} else {
Err(WoxlfError::DurationParseError)
}
}
}