#[derive(Eq, PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub enum Team {
T02,
T13,
}
impl Team {
pub fn from_n(n: usize) -> Self {
match n {
0 | 2 => Team::T02,
1 | 3 => Team::T13,
other => panic!("invalid team number: {}", other),
}
}
pub fn opponent(self) -> Team {
match self {
Team::T02 => Team::T13,
Team::T13 => Team::T02,
}
}
}
#[derive(Eq, PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub enum PlayerPos {
P0,
P1,
P2,
P3,
}
pub struct PlayerIterator {
current: PlayerPos,
remaining: usize,
}
impl Iterator for PlayerIterator {
type Item = PlayerPos;
fn next(&mut self) -> Option<PlayerPos> {
if self.remaining == 0 {
return None;
}
let r = self.current;
self.current = self.current.next();
self.remaining -= 1;
Some(r)
}
}
impl PlayerPos {
pub fn team(self) -> Team {
match self {
PlayerPos::P0 | PlayerPos::P2 => Team::T02,
PlayerPos::P1 | PlayerPos::P3 => Team::T13,
}
}
pub fn from_n(n: usize) -> Self {
match n {
0 => PlayerPos::P0,
1 => PlayerPos::P1,
2 => PlayerPos::P2,
3 => PlayerPos::P3,
other => panic!("invalid pos: {}", other),
}
}
pub fn is_partner(self, other: PlayerPos) -> bool {
self.team() == other.team()
}
pub fn next(self) -> PlayerPos {
match self {
PlayerPos::P0 => PlayerPos::P1,
PlayerPos::P1 => PlayerPos::P2,
PlayerPos::P2 => PlayerPos::P3,
PlayerPos::P3 => PlayerPos::P0,
}
}
pub fn next_n(self, n: usize) -> PlayerPos {
if n == 0 {
self
} else {
PlayerPos::from_n((self as usize + n) % 4)
}
}
pub fn prev(self) -> PlayerPos {
match self {
PlayerPos::P0 => PlayerPos::P3,
PlayerPos::P1 => PlayerPos::P0,
PlayerPos::P2 => PlayerPos::P1,
PlayerPos::P3 => PlayerPos::P2,
}
}
pub fn until_n(self, n: usize) -> PlayerIterator {
PlayerIterator {
current: self,
remaining: n,
}
}
pub fn distance_until(self, other: PlayerPos) -> usize {
(3 + other as usize - self as usize) % 4 + 1
}
pub fn until(self, other: PlayerPos) -> PlayerIterator {
let d = self.distance_until(other);
self.until_n(d)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_teams() {
assert_eq!(PlayerPos::P0.team(), PlayerPos::P2.team());
assert_eq!(PlayerPos::P0.team(), Team::T02);
assert_eq!(PlayerPos::P1.team(), PlayerPos::P3.team());
assert_eq!(PlayerPos::P1.team(), Team::T13);
assert!(PlayerPos::P0.team() != PlayerPos::P1.team());
}
#[test]
fn test_pos() {
let mut count = [0; 4];
for i in 0..4 {
for pos in PlayerPos::from_n(i).until(PlayerPos::from_n(0)) {
count[pos as usize] += 1;
}
for pos in PlayerPos::from_n(0).until(PlayerPos::from_n(i)) {
count[pos as usize] += 1;
}
}
for c in count.iter() {
assert!(*c == 5);
}
for i in 0..4 {
assert!(PlayerPos::from_n(i).next() == PlayerPos::from_n((i + 1) % 4));
assert!(PlayerPos::from_n(i) == PlayerPos::from_n((i + 1) % 4).prev());
assert!(PlayerPos::from_n(i).next().prev() == PlayerPos::from_n(i));
}
}
}