use derive_more::{AsMut, AsRef};
use std::fmt::Display;
use std::iter::IntoIterator;
use std::ops::{Index, IndexMut};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, AsMut, AsRef)]
pub struct PerPlayer<T, const P: usize> {
data: [T; P],
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct PlayerIndex<const P: usize>(usize);
impl<T, const P: usize> PerPlayer<T, P> {
pub fn new(data: [T; P]) -> Self {
PerPlayer { data }
}
pub fn generate<F: FnMut(PlayerIndex<P>) -> T>(gen_elem: F) -> Self {
let indexes: [PlayerIndex<P>; P] = PlayerIndex::all()
.collect::<Vec<PlayerIndex<P>>>()
.try_into()
.unwrap();
PerPlayer::new(indexes.map(gen_elem))
}
pub fn num_players(&self) -> usize {
P
}
pub fn get(&self, i: usize) -> Option<&T> {
if i < P {
Some(&self.data[i])
} else {
log::warn!("PerPlayer<{}>::get({}): index out of range", P, i);
None
}
}
pub fn get_mut(&mut self, i: usize) -> Option<&mut T> {
if i < P {
Some(&mut self.data[i])
} else {
log::warn!("PerPlayer<{}>::get_mut({}): index out of range", P, i);
None
}
}
pub fn for_player(&self, idx: PlayerIndex<P>) -> &T {
unsafe { self.data.get_unchecked(idx.0) }
}
pub fn for_player_mut(&mut self, idx: PlayerIndex<P>) -> &mut T {
unsafe { self.data.get_unchecked_mut(idx.0) }
}
}
impl<T: Clone, const P: usize> PerPlayer<T, P> {
pub fn init_with(value: T) -> Self {
PerPlayer::generate(|_| value.clone())
}
pub fn for_each<F: FnMut(&T)>(&self, f: F) {
self.data.iter().for_each(f)
}
pub fn for_each_with_index<F: FnMut(PlayerIndex<P>, &T)>(&self, mut f: F) {
let mut indexes = PlayerIndex::all();
self.data.iter().for_each(move |elem| {
let index = indexes.next().unwrap();
f(index, elem)
});
}
pub fn map<U, F: FnMut(T) -> U>(&self, f: F) -> PerPlayer<U, P> {
PerPlayer::new(self.data.clone().map(f))
}
pub fn map_with_index<U, F: FnMut(PlayerIndex<P>, T) -> U>(&self, mut f: F) -> PerPlayer<U, P> {
let mut indexes = PlayerIndex::all();
PerPlayer::new(self.data.clone().map(move |elem| {
let index = indexes.next().unwrap();
f(index, elem)
}))
}
}
impl<T: core::fmt::Debug, const P: usize> PerPlayer<Option<T>, P> {
pub fn all_some(self) -> Option<PerPlayer<T, P>> {
self.data
.into_iter()
.collect::<Option<Vec<T>>>()
.map(|vec| PerPlayer::new(vec.try_into().unwrap()))
}
}
impl<T: Default, const P: usize> Default for PerPlayer<T, P> {
fn default() -> Self {
PerPlayer::generate(|_| T::default())
}
}
impl<T, const P: usize> From<[T; P]> for PerPlayer<T, P> {
fn from(data: [T; P]) -> Self {
PerPlayer::new(data)
}
}
impl<T, const P: usize> PerPlayer<T, P> {
pub fn iter(&self) -> <&[T; P] as IntoIterator>::IntoIter {
self.data.iter()
}
pub fn iter_mut(&mut self) -> <&mut [T; P] as IntoIterator>::IntoIter {
self.data.iter_mut()
}
}
impl<T, const P: usize> IntoIterator for PerPlayer<T, P> {
type Item = <[T; P] as IntoIterator>::Item;
type IntoIter = <[T; P] as IntoIterator>::IntoIter;
fn into_iter(self) -> <[T; P] as IntoIterator>::IntoIter {
self.data.into_iter()
}
}
impl<'a, T, const P: usize> IntoIterator for &'a PerPlayer<T, P> {
type Item = <&'a [T; P] as IntoIterator>::Item;
type IntoIter = <&'a [T; P] as IntoIterator>::IntoIter;
fn into_iter(self) -> <&'a [T; P] as IntoIterator>::IntoIter {
self.data.iter()
}
}
impl<'a, T, const P: usize> IntoIterator for &'a mut PerPlayer<T, P> {
type Item = <&'a mut [T; P] as IntoIterator>::Item;
type IntoIter = <&'a mut [T; P] as IntoIterator>::IntoIter;
fn into_iter(self) -> <&'a mut [T; P] as IntoIterator>::IntoIter {
self.data.iter_mut()
}
}
impl<const P: usize> PlayerIndex<P> {
pub fn new(index: usize) -> Option<Self> {
if index < P {
Some(PlayerIndex(index))
} else {
log::warn!("PlayerIndex<{}>::new({}): index out of range", P, index);
None
}
}
pub fn as_usize(&self) -> usize {
self.0
}
pub fn num_players(&self) -> usize {
P
}
pub fn all() -> PlayerIndexes<P> {
PlayerIndexes::new()
}
pub fn next(&self) -> Self {
PlayerIndex((self.0 + 1) % P)
}
pub fn previous(&self) -> Self {
PlayerIndex((self.0 + P - 1) % P)
}
}
impl<const P: usize> From<PlayerIndex<P>> for usize {
fn from(index: PlayerIndex<P>) -> usize {
index.as_usize()
}
}
impl<const P: usize> Display for PlayerIndex<P> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(fmt, "P{}", self.0)
}
}
impl<T, const P: usize> Index<PlayerIndex<P>> for PerPlayer<T, P> {
type Output = T;
fn index(&self, idx: PlayerIndex<P>) -> &T {
self.for_player(idx)
}
}
impl<T, const P: usize> IndexMut<PlayerIndex<P>> for PerPlayer<T, P> {
fn index_mut(&mut self, idx: PlayerIndex<P>) -> &mut T {
self.for_player_mut(idx)
}
}
pub struct PlayerIndexes<const P: usize> {
next: usize,
back: usize,
}
impl<const P: usize> PlayerIndexes<P> {
fn new() -> Self {
PlayerIndexes { next: 0, back: P }
}
}
impl<const P: usize> Iterator for PlayerIndexes<P> {
type Item = PlayerIndex<P>;
fn next(&mut self) -> Option<PlayerIndex<P>> {
if self.next < self.back {
let index = PlayerIndex(self.next);
self.next += 1;
Some(index)
} else {
None
}
}
}
impl<const P: usize> DoubleEndedIterator for PlayerIndexes<P> {
fn next_back(&mut self) -> Option<PlayerIndex<P>> {
if self.next < self.back {
self.back -= 1;
Some(PlayerIndex(self.back))
} else {
None
}
}
}
pub mod for1 {
use super::PlayerIndex;
pub const P0: PlayerIndex<1> = PlayerIndex(0);
}
pub mod for2 {
use super::{PerPlayer, PlayerIndex};
pub const P0: PlayerIndex<2> = PlayerIndex(0);
pub const P1: PlayerIndex<2> = PlayerIndex(1);
pub const ROW: PlayerIndex<2> = P0;
pub const COL: PlayerIndex<2> = P1;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Move<M0, M1> {
P0(M0),
P1(M1),
}
pub fn per_player_moves<M0, M1>(
p0_moves: Vec<M0>,
p1_moves: Vec<M1>,
) -> PerPlayer<Vec<Move<M0, M1>>, 2> {
PerPlayer::new([
p0_moves.into_iter().map(|m| Move::P0(m)).collect(),
p1_moves.into_iter().map(|m| Move::P1(m)).collect(),
])
}
}
pub mod for3 {
use super::{PerPlayer, PlayerIndex};
pub const P0: PlayerIndex<3> = PlayerIndex(0);
pub const P1: PlayerIndex<3> = PlayerIndex(1);
pub const P2: PlayerIndex<3> = PlayerIndex(2);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Move<M0, M1, M2> {
P0(M0),
P1(M1),
P2(M2),
}
pub fn per_player_moves<M0, M1, M2>(
p0_moves: Vec<M0>,
p1_moves: Vec<M1>,
p2_moves: Vec<M2>,
) -> PerPlayer<Vec<Move<M0, M1, M2>>, 3> {
PerPlayer::new([
p0_moves.into_iter().map(|m| Move::P0(m)).collect(),
p1_moves.into_iter().map(|m| Move::P1(m)).collect(),
p2_moves.into_iter().map(|m| Move::P2(m)).collect(),
])
}
}
pub mod for4 {
use super::{PerPlayer, PlayerIndex};
pub const P0: PlayerIndex<4> = PlayerIndex(0);
pub const P1: PlayerIndex<4> = PlayerIndex(1);
pub const P2: PlayerIndex<4> = PlayerIndex(2);
pub const P3: PlayerIndex<4> = PlayerIndex(3);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Move<M0, M1, M2, M3> {
P0(M0),
P1(M1),
P2(M2),
P3(M3),
}
pub fn per_player_moves<M0, M1, M2, M3>(
p0_moves: Vec<M0>,
p1_moves: Vec<M1>,
p2_moves: Vec<M2>,
p3_moves: Vec<M3>,
) -> PerPlayer<Vec<Move<M0, M1, M2, M3>>, 4> {
PerPlayer::new([
p0_moves.into_iter().map(|m| Move::P0(m)).collect(),
p1_moves.into_iter().map(|m| Move::P1(m)).collect(),
p2_moves.into_iter().map(|m| Move::P2(m)).collect(),
p3_moves.into_iter().map(|m| Move::P3(m)).collect(),
])
}
}
pub mod for5 {
use super::PlayerIndex;
pub const P0: PlayerIndex<5> = PlayerIndex(0);
pub const P1: PlayerIndex<5> = PlayerIndex(1);
pub const P2: PlayerIndex<5> = PlayerIndex(2);
pub const P3: PlayerIndex<5> = PlayerIndex(3);
pub const P4: PlayerIndex<5> = PlayerIndex(4);
}
pub mod for6 {
use super::PlayerIndex;
pub const P0: PlayerIndex<6> = PlayerIndex(0);
pub const P1: PlayerIndex<6> = PlayerIndex(1);
pub const P2: PlayerIndex<6> = PlayerIndex(2);
pub const P3: PlayerIndex<6> = PlayerIndex(3);
pub const P4: PlayerIndex<6> = PlayerIndex(4);
pub const P5: PlayerIndex<6> = PlayerIndex(5);
}
pub mod for7 {
use super::PlayerIndex;
pub const P0: PlayerIndex<7> = PlayerIndex(0);
pub const P1: PlayerIndex<7> = PlayerIndex(1);
pub const P2: PlayerIndex<7> = PlayerIndex(2);
pub const P3: PlayerIndex<7> = PlayerIndex(3);
pub const P4: PlayerIndex<7> = PlayerIndex(4);
pub const P5: PlayerIndex<7> = PlayerIndex(5);
pub const P6: PlayerIndex<7> = PlayerIndex(6);
}
pub mod for8 {
use super::PlayerIndex;
pub const P0: PlayerIndex<8> = PlayerIndex(0);
pub const P1: PlayerIndex<8> = PlayerIndex(1);
pub const P2: PlayerIndex<8> = PlayerIndex(2);
pub const P3: PlayerIndex<8> = PlayerIndex(3);
pub const P4: PlayerIndex<8> = PlayerIndex(4);
pub const P5: PlayerIndex<8> = PlayerIndex(5);
pub const P6: PlayerIndex<8> = PlayerIndex(6);
pub const P7: PlayerIndex<8> = PlayerIndex(7);
}
pub mod for9 {
use super::PlayerIndex;
pub const P0: PlayerIndex<9> = PlayerIndex(0);
pub const P1: PlayerIndex<9> = PlayerIndex(1);
pub const P2: PlayerIndex<9> = PlayerIndex(2);
pub const P3: PlayerIndex<9> = PlayerIndex(3);
pub const P4: PlayerIndex<9> = PlayerIndex(4);
pub const P5: PlayerIndex<9> = PlayerIndex(5);
pub const P6: PlayerIndex<9> = PlayerIndex(6);
pub const P7: PlayerIndex<9> = PlayerIndex(7);
pub const P8: PlayerIndex<9> = PlayerIndex(8);
}
pub mod for10 {
use super::PlayerIndex;
pub const P0: PlayerIndex<10> = PlayerIndex(0);
pub const P1: PlayerIndex<10> = PlayerIndex(1);
pub const P2: PlayerIndex<10> = PlayerIndex(2);
pub const P3: PlayerIndex<10> = PlayerIndex(3);
pub const P4: PlayerIndex<10> = PlayerIndex(4);
pub const P5: PlayerIndex<10> = PlayerIndex(5);
pub const P6: PlayerIndex<10> = PlayerIndex(6);
pub const P7: PlayerIndex<10> = PlayerIndex(7);
pub const P8: PlayerIndex<10> = PlayerIndex(8);
pub const P9: PlayerIndex<10> = PlayerIndex(9);
}
pub mod for11 {
use super::PlayerIndex;
pub const P0: PlayerIndex<11> = PlayerIndex(0);
pub const P1: PlayerIndex<11> = PlayerIndex(1);
pub const P2: PlayerIndex<11> = PlayerIndex(2);
pub const P3: PlayerIndex<11> = PlayerIndex(3);
pub const P4: PlayerIndex<11> = PlayerIndex(4);
pub const P5: PlayerIndex<11> = PlayerIndex(5);
pub const P6: PlayerIndex<11> = PlayerIndex(6);
pub const P7: PlayerIndex<11> = PlayerIndex(7);
pub const P8: PlayerIndex<11> = PlayerIndex(8);
pub const P9: PlayerIndex<11> = PlayerIndex(9);
pub const P10: PlayerIndex<11> = PlayerIndex(10);
}
pub mod for12 {
use super::PlayerIndex;
pub const P0: PlayerIndex<12> = PlayerIndex(0);
pub const P1: PlayerIndex<12> = PlayerIndex(1);
pub const P2: PlayerIndex<12> = PlayerIndex(2);
pub const P3: PlayerIndex<12> = PlayerIndex(3);
pub const P4: PlayerIndex<12> = PlayerIndex(4);
pub const P5: PlayerIndex<12> = PlayerIndex(5);
pub const P6: PlayerIndex<12> = PlayerIndex(6);
pub const P7: PlayerIndex<12> = PlayerIndex(7);
pub const P8: PlayerIndex<12> = PlayerIndex(8);
pub const P9: PlayerIndex<12> = PlayerIndex(9);
pub const P10: PlayerIndex<12> = PlayerIndex(10);
pub const P11: PlayerIndex<12> = PlayerIndex(11);
}
pub mod for13 {
use super::PlayerIndex;
pub const P0: PlayerIndex<13> = PlayerIndex(0);
pub const P1: PlayerIndex<13> = PlayerIndex(1);
pub const P2: PlayerIndex<13> = PlayerIndex(2);
pub const P3: PlayerIndex<13> = PlayerIndex(3);
pub const P4: PlayerIndex<13> = PlayerIndex(4);
pub const P5: PlayerIndex<13> = PlayerIndex(5);
pub const P6: PlayerIndex<13> = PlayerIndex(6);
pub const P7: PlayerIndex<13> = PlayerIndex(7);
pub const P8: PlayerIndex<13> = PlayerIndex(8);
pub const P9: PlayerIndex<13> = PlayerIndex(9);
pub const P10: PlayerIndex<13> = PlayerIndex(10);
pub const P11: PlayerIndex<13> = PlayerIndex(11);
pub const P12: PlayerIndex<13> = PlayerIndex(12);
}
pub mod for14 {
use super::PlayerIndex;
pub const P0: PlayerIndex<14> = PlayerIndex(0);
pub const P1: PlayerIndex<14> = PlayerIndex(1);
pub const P2: PlayerIndex<14> = PlayerIndex(2);
pub const P3: PlayerIndex<14> = PlayerIndex(3);
pub const P4: PlayerIndex<14> = PlayerIndex(4);
pub const P5: PlayerIndex<14> = PlayerIndex(5);
pub const P6: PlayerIndex<14> = PlayerIndex(6);
pub const P7: PlayerIndex<14> = PlayerIndex(7);
pub const P8: PlayerIndex<14> = PlayerIndex(8);
pub const P9: PlayerIndex<14> = PlayerIndex(9);
pub const P10: PlayerIndex<14> = PlayerIndex(10);
pub const P11: PlayerIndex<14> = PlayerIndex(11);
pub const P12: PlayerIndex<14> = PlayerIndex(12);
pub const P13: PlayerIndex<14> = PlayerIndex(13);
}
pub mod for15 {
use super::PlayerIndex;
pub const P0: PlayerIndex<15> = PlayerIndex(0);
pub const P1: PlayerIndex<15> = PlayerIndex(1);
pub const P2: PlayerIndex<15> = PlayerIndex(2);
pub const P3: PlayerIndex<15> = PlayerIndex(3);
pub const P4: PlayerIndex<15> = PlayerIndex(4);
pub const P5: PlayerIndex<15> = PlayerIndex(5);
pub const P6: PlayerIndex<15> = PlayerIndex(6);
pub const P7: PlayerIndex<15> = PlayerIndex(7);
pub const P8: PlayerIndex<15> = PlayerIndex(8);
pub const P9: PlayerIndex<15> = PlayerIndex(9);
pub const P10: PlayerIndex<15> = PlayerIndex(10);
pub const P11: PlayerIndex<15> = PlayerIndex(11);
pub const P12: PlayerIndex<15> = PlayerIndex(12);
pub const P13: PlayerIndex<15> = PlayerIndex(13);
pub const P14: PlayerIndex<15> = PlayerIndex(14);
}
pub mod for16 {
use super::PlayerIndex;
pub const P0: PlayerIndex<16> = PlayerIndex(0);
pub const P1: PlayerIndex<16> = PlayerIndex(1);
pub const P2: PlayerIndex<16> = PlayerIndex(2);
pub const P3: PlayerIndex<16> = PlayerIndex(3);
pub const P4: PlayerIndex<16> = PlayerIndex(4);
pub const P5: PlayerIndex<16> = PlayerIndex(5);
pub const P6: PlayerIndex<16> = PlayerIndex(6);
pub const P7: PlayerIndex<16> = PlayerIndex(7);
pub const P8: PlayerIndex<16> = PlayerIndex(8);
pub const P9: PlayerIndex<16> = PlayerIndex(9);
pub const P10: PlayerIndex<16> = PlayerIndex(10);
pub const P11: PlayerIndex<16> = PlayerIndex(11);
pub const P12: PlayerIndex<16> = PlayerIndex(12);
pub const P13: PlayerIndex<16> = PlayerIndex(13);
pub const P14: PlayerIndex<16> = PlayerIndex(14);
pub const P15: PlayerIndex<16> = PlayerIndex(15);
}