use core::fmt;
use core::iter::FusedIterator;
use core::str::FromStr;
use dds_bridge::{Card, Deal, Hand, Seat};
use rand::{Rng, RngExt as _};
use thiserror::Error;
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[error("The deal is not a valid subset of a bridge deal")]
pub struct InvalidDeal;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Deck(Hand);
impl Deck {
pub const ALL: Self = Self(Hand::ALL);
pub const EMPTY: Self = Self(Hand::EMPTY);
#[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.0.len()
}
#[must_use]
#[inline]
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub const fn clear(&mut self) {
self.0 = Hand::EMPTY;
}
pub fn insert(&mut self, card: Card) -> bool {
self.0.insert(card)
}
#[must_use]
#[inline]
pub const fn take(&mut self) -> Hand {
core::mem::replace(&mut self.0, Hand::EMPTY)
}
#[must_use]
pub fn draw(&mut self, rng: &mut (impl Rng + ?Sized), n: usize) -> Hand {
let len = self.0.len();
if n >= len {
return self.take();
}
let mut hand = Hand::EMPTY;
for i in 0..n {
let bits = (0..rng.random_range(..len - i))
.fold(self.0.to_bits(), |bits, _| bits & (bits - 1));
let selected = Hand::from_bits_retain(bits & bits.wrapping_neg());
hand |= selected;
self.0 ^= selected;
}
hand
}
#[must_use]
pub fn pop(&mut self, rng: &mut (impl Rng + ?Sized)) -> Option<Card> {
self.draw(rng, 1).into_iter().next()
}
}
impl From<Hand> for Deck {
fn from(hand: Hand) -> Self {
Self(hand)
}
}
impl fmt::Display for Deck {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for Deck {
type Err = <Hand as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.parse::<Hand>().map(Self)
}
}
#[must_use]
pub fn full_deal(rng: &mut (impl Rng + ?Sized)) -> Deal {
let mut deck = Deck::ALL;
Deal::new(
deck.draw(rng, 13),
deck.draw(rng, 13),
deck.draw(rng, 13),
deck.take(),
)
}
#[derive(Debug)]
pub struct FillDeals<'a, R: Rng + ?Sized> {
rng: &'a mut R,
deal: Deal,
deck: Deck,
shortest: Seat,
}
impl<R: Rng + ?Sized> Iterator for FillDeals<'_, R> {
type Item = Deal;
fn next(&mut self) -> Option<Deal> {
let mut deck = self.deck;
let mut deal = self.deal;
let mut fill = |hand: &mut Hand| *hand |= deck.draw(self.rng, 13 - hand.len());
fill(&mut deal[self.shortest.lho()]);
fill(&mut deal[self.shortest.partner()]);
fill(&mut deal[self.shortest.rho()]);
deal[self.shortest] |= deck.take();
Some(deal)
}
}
impl<R: Rng + ?Sized> FusedIterator for FillDeals<'_, R> {}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub fn fill_deals<R: Rng + ?Sized>(
rng: &mut R,
deal: Deal,
) -> Result<FillDeals<'_, R>, InvalidDeal> {
Ok(FillDeals {
rng,
deal,
deck: Deck::from(!deal.validate_and_collect().ok_or(InvalidDeal)?),
#[allow(clippy::missing_panics_doc)]
shortest: Seat::ALL
.into_iter()
.min_by_key(|&seat| deal[seat].len())
.expect("Seat::ALL shall not be empty"),
})
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::Deck;
use core::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
impl Serialize for Deck {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.collect_str(self)
}
}
impl<'de> Deserialize<'de> for Deck {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = <&str>::deserialize(d)?;
Self::from_str(s).map_err(de::Error::custom)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn roundtrip(deck: Deck) {
assert_eq!(deck.to_string().parse::<Deck>().unwrap(), deck);
}
#[test]
fn full_and_empty_roundtrip() {
roundtrip(Deck::ALL);
roundtrip(Deck::EMPTY);
}
#[test]
fn partial_deck_roundtrip() {
let mut deck = Deck::EMPTY;
for s in ["♠A", "♥K", "♦Q", "♣J", "♠2"] {
deck.insert(s.parse().unwrap());
}
roundtrip(deck);
}
#[test]
fn parses_from_hand_notation() {
let deck: Deck = "AKQJ.T98.765.432".parse().unwrap();
assert_eq!(deck.len(), 13);
assert_eq!(deck.to_string(), "AKQJ.T98.765.432");
}
}