Skip to main content

server/domain/players/
roles.rs

1use constants::*;
2use serde::{Deserialize, Serialize};
3
4use super::{Dealer, Pone};
5use crate::domain::{CutsForDeal, PLAYER0, PLAYER1};
6
7/// Represents the roles assigned to players in a round.
8///
9/// This struct captures which player is the dealer and which is the pone
10/// (non-dealer) in the game.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
12pub struct Roles {
13    dealer: Dealer,
14    pone: Pone,
15}
16
17/// Trait for types that contain player roles.
18pub trait HasRoles {
19    /// Returns an immutable reference to the roles.
20    fn roles(&self) -> &Roles;
21
22    /// Returns a mutable reference to the roles.
23    fn roles_mut(&mut self) -> &mut Roles;
24
25    /// Returns an immutable reference to the dealer.
26    #[must_use]
27    fn dealer(&self) -> &Dealer {
28        &self.roles().dealer
29    }
30
31    /// Returns an immutable reference to the pone (non-dealer).
32    #[must_use]
33    fn pone(&self) -> &Pone {
34        &self.roles().pone
35    }
36}
37
38impl Roles {
39    /// Creates a new `Roles` assignment given the dealer.
40    ///
41    /// The pone is automatically inferred as the opponent of the dealer.
42    pub fn new(dealer: Dealer) -> Self {
43        Self {
44            dealer,
45            pone: dealer.opponent(),
46        }
47    }
48
49    /// Constructs roles, if possible, from a set of cuts.
50    ///
51    /// Returns `None` if the roles cannot be determined (e.g., cuts are equal or incomplete).
52    #[must_use]
53    pub fn from_cuts(cuts: &CutsForDeal) -> Option<Self> {
54        use std::cmp::Ordering;
55
56        let defined_cuts = cuts.iter().filter_map(|c| *c).collect::<Vec<_>>();
57
58        (defined_cuts.len() == PLAYER_COUNT)
59            .then(|| {
60                let dealer = match defined_cuts[PLAYER0]
61                    .face()
62                    .rank()
63                    .cmp(&defined_cuts[PLAYER1].face().rank())
64                {
65                    Ordering::Less => Some(Dealer::from(PLAYER0)),
66                    Ordering::Greater => Some(Dealer::from(PLAYER1)),
67                    Ordering::Equal => None,
68                };
69
70                dealer.map(Self::new)
71            })
72            .flatten()
73    }
74
75    /// Returns an immutable reference to the dealer.
76    #[must_use]
77    pub fn dealer(&self) -> &Dealer {
78        &self.dealer
79    }
80
81    /// Returns an immutable reference to the pone.
82    #[must_use]
83    pub fn pone(&self) -> &Pone {
84        &self.pone
85    }
86
87    /// Swaps the dealer and pone roles in place.
88    pub fn swap(&mut self) {
89        let was_dealer = self.dealer.player();
90        let was_pone = self.pone.player();
91        self.dealer = Dealer::from(was_pone);
92        self.pone = Pone::from(was_dealer);
93    }
94}
95
96impl std::fmt::Display for Roles {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        let Self { dealer, pone } = self;
99        write!(f, "{dealer}, {pone}",)
100    }
101}