use crate::battle::BattleRules;
use crate::error::{WeaselError, WeaselResult};
use crate::team::TeamId;
pub type PlayerId = u64;
pub(crate) struct Rights<R: BattleRules> {
data: Vec<(PlayerId, Vec<TeamId<R>>)>,
}
impl<R: BattleRules> Rights<R> {
pub(crate) fn new() -> Self {
Self { data: Vec::new() }
}
fn cleanup_players(&mut self) {
self.data.retain(|(_, rights)| !rights.is_empty());
}
fn add(&mut self, player: PlayerId, team: &TeamId<R>) {
if let Some((_, rights)) = self.data.iter_mut().find(|(e, _)| *e == player) {
if rights.iter_mut().find(|e| *e == team).is_none() {
rights.push(team.clone());
}
} else {
self.data.push((player, vec![team.clone()]));
}
}
fn remove(&mut self, player: PlayerId, team: &TeamId<R>) {
if let Some((_, rights)) = self.data.iter_mut().find(|(e, _)| *e == player) {
let index = rights.iter().position(|e| e == team);
if let Some(index) = index {
rights.remove(index);
}
}
self.cleanup_players();
}
fn clear(&mut self) {
self.data.clear();
}
fn get(&self) -> impl Iterator<Item = (PlayerId, &[TeamId<R>])> {
self.data.iter().map(|(player, vec)| (*player, &vec[..]))
}
fn check(&self, player: PlayerId, team: &TeamId<R>) -> bool {
if let Some((_, rights)) = self.data.iter().find(|(e, _)| *e == player) {
return rights.iter().any(|e| e == team);
}
false
}
fn remove_team(&mut self, team: &TeamId<R>) {
for (_, rights) in &mut self.data {
let index = rights.iter().position(|e| e == team);
if let Some(index) = index {
rights.remove(index);
}
}
self.cleanup_players();
}
fn remove_player(&mut self, player: PlayerId) {
let index = self.data.iter().position(|(e, _)| *e == player);
if let Some(index) = index {
self.data.remove(index);
}
}
}
pub struct RightsHandle<'a, R>
where
R: BattleRules,
{
rights: &'a Rights<R>,
}
impl<'a, R> RightsHandle<'a, R>
where
R: BattleRules,
{
pub(crate) fn new(rights: &'a Rights<R>) -> Self {
Self { rights }
}
pub fn get(&self) -> impl Iterator<Item = (PlayerId, &[TeamId<R>])> {
self.rights.get()
}
pub fn check(&self, player: PlayerId, team: &TeamId<R>) -> bool {
self.rights.check(player, team)
}
}
pub struct RightsHandleMut<'a, R, I>
where
R: BattleRules,
I: Iterator<Item = &'a TeamId<R>>,
{
rights: &'a mut Rights<R>,
teams: I,
}
impl<'a, R, I> RightsHandleMut<'a, R, I>
where
R: BattleRules,
I: Iterator<Item = &'a TeamId<R>>,
{
pub(crate) fn new(rights: &'a mut Rights<R>, teams: I) -> Self {
Self { rights, teams }
}
pub fn add(&mut self, player: PlayerId, team: &TeamId<R>) -> WeaselResult<(), R> {
if !self.teams.any(|x| x == team) {
return Err(WeaselError::TeamNotFound(team.clone()));
}
self.rights.add(player, team);
Ok(())
}
pub fn remove(&mut self, player: PlayerId, team: &TeamId<R>) {
self.rights.remove(player, team);
}
pub fn clear(&mut self) {
self.rights.clear();
}
pub fn remove_team(&mut self, team: &TeamId<R>) {
self.rights.remove_team(team);
}
pub fn remove_player(&mut self, player: PlayerId) {
self.rights.remove_player(player);
}
pub fn get(&self) -> impl Iterator<Item = (PlayerId, &[TeamId<R>])> {
self.rights.get()
}
pub fn check(&self, player: PlayerId, team: &TeamId<R>) -> bool {
self.rights.check(player, team)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::battle::Battle;
use crate::{battle_rules, rules::empty::*};
const PLAYER_1_ID: PlayerId = 1;
const PLAYER_2_ID: PlayerId = 2;
const TEAM_1_ID: u32 = 1;
const TEAM_2_ID: u32 = 2;
battle_rules! {}
#[test]
fn change_rights() {
let mut rights: Rights<CustomRules> = Rights::new();
rights.add(PLAYER_1_ID, &TEAM_1_ID);
assert_eq!(rights.data.len(), 1);
rights.add(PLAYER_1_ID, &TEAM_2_ID);
assert_eq!(rights.data.len(), 1);
rights.add(PLAYER_2_ID, &TEAM_1_ID);
assert_eq!(rights.data.len(), 2);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), true);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_2_ID), true);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_1_ID), true);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_2_ID), false);
rights.remove(PLAYER_1_ID, &TEAM_2_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_2_ID), false);
rights.remove(PLAYER_2_ID, &TEAM_1_ID);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_1_ID), false);
assert_eq!(rights.data.len(), 1);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), true);
rights.clear();
assert_eq!(rights.data.len(), 0);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), false);
}
#[test]
fn remove_team() {
let mut rights: Rights<CustomRules> = Rights::new();
rights.add(PLAYER_1_ID, &TEAM_1_ID);
rights.add(PLAYER_2_ID, &TEAM_1_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), true);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_1_ID), true);
rights.add(PLAYER_1_ID, &TEAM_2_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_2_ID), true);
assert_eq!(rights.data.len(), 2);
rights.remove_team(&TEAM_1_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), false);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_1_ID), false);
assert_eq!(rights.data.len(), 1);
}
#[test]
fn remove_player() {
let mut rights: Rights<CustomRules> = Rights::new();
rights.add(PLAYER_1_ID, &TEAM_1_ID);
rights.add(PLAYER_2_ID, &TEAM_1_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), true);
assert_eq!(rights.check(PLAYER_2_ID, &TEAM_1_ID), true);
assert_eq!(rights.data.len(), 2);
rights.remove_player(PLAYER_1_ID);
assert_eq!(rights.check(PLAYER_1_ID, &TEAM_1_ID), false);
assert_eq!(rights.data.len(), 1);
}
#[test]
fn handle() {
let mut battle = Battle::builder(CustomRules::new()).build();
assert_eq!(
battle.rights_mut().add(PLAYER_1_ID, &TEAM_1_ID).err(),
Some(WeaselError::TeamNotFound(TEAM_1_ID))
);
assert_eq!(battle.rights().get().count(), 0);
}
}