148 lines
4.3 KiB
Rust
148 lines
4.3 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 get_player_by_codename_mut(&mut self, codename: &str) -> Option<&mut PlayerData> {
|
|
self.player_data
|
|
.iter_mut()
|
|
.find(|p| p.codename.to_lowercase() == codename.to_lowercase())
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|