+impl Rank {
+ #[must_use]
+ pub fn value(&self) -> u8 {
+ self.0 + 1
+ }
+}
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub struct Suit(u8);
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct Card(u8);
+impl Card {
+ #[must_use]
+ pub fn is_joker(&self) -> bool {
+ usize::from(self.0) >= NUM_RANKS * NUM_SUITS
+ }
+ #[must_use]
+ pub fn rank(&self) -> Option<Rank> {
+ (!self.is_joker()).then_some(Rank(self.0 >> 2))
+ }
+ #[must_use]
+ pub fn suit(&self) -> Option<Suit> {
+ (!self.is_joker()).then_some(Suit(self.0 & 3))
+ }
+}
+
+#[derive(Clone, Copy)]
+pub enum WithOrWithoutJokers {
+ WithJokers,
+ WithoutJokers,
+}
+
+#[must_use]
+pub fn deck(j: WithOrWithoutJokers) -> Vec<Card> {
+ let limit = u8::try_from(match j {
+ WithOrWithoutJokers::WithJokers => NUM_CARDS,
+ WithOrWithoutJokers::WithoutJokers => NUM_SUITS * NUM_RANKS,
+ })
+ .expect("Too many cards?");
+ (0..limit).map(Card).collect()
+}