1#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "serde", serde(transparent))]
12pub struct PlayerId(u32);
13
14impl PlayerId {
15 pub const CHANCE: Self = Self(u32::MAX);
22
23 #[must_use]
28 pub const fn new(index: u32) -> Self {
29 Self(index)
30 }
31
32 #[must_use]
34 pub const fn index(self) -> u32 {
35 self.0
36 }
37
38 #[must_use]
40 pub const fn is_chance(self) -> bool {
41 self.0 == Self::CHANCE.0
42 }
43}
44
45impl core::fmt::Display for PlayerId {
46 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47 if self.is_chance() {
48 f.write_str("chance")
49 } else {
50 write!(f, "p{}", self.0)
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::PlayerId;
58
59 #[test]
60 fn index_round_trips() {
61 assert_eq!(PlayerId::new(3).index(), 3);
62 }
63
64 #[test]
65 fn chance_is_distinct_and_flagged() {
66 assert!(PlayerId::CHANCE.is_chance());
67 assert!(!PlayerId::new(0).is_chance());
68 assert_ne!(PlayerId::CHANCE, PlayerId::new(0));
69 }
70
71 #[test]
72 fn ordering_is_by_index() {
73 assert!(PlayerId::new(0) < PlayerId::new(1));
74 assert!(PlayerId::new(2) < PlayerId::CHANCE);
75 }
76
77 #[test]
78 fn display() {
79 assert_eq!(PlayerId::new(1).to_string(), "p1");
80 assert_eq!(PlayerId::CHANCE.to_string(), "chance");
81 }
82}