Skip to main content

Round

Struct Round 

Source
pub struct Round { /* private fields */ }
Expand description

One deal of gin rummy

See the module documentation for the flow. Construct with Round::from_deal or, under the rand feature, Round::deal.

With the serde feature, a Round serializes to a plain snapshot of its position, and deserialization re-validates every invariant — a corrupt snapshot is rejected, never trusted.

Implementations§

Source§

impl Round

Source

pub fn from_deal( rules: Rules, dealer: Player, hands: [Hand; 2], upcard: Card, stock: Vec<Card>, ) -> Result<Self, DealError>

Construct a round from a fixed initial deal

stock is face-down draw order: the last element is drawn first. The upcard starts the discard pile, and the non-dealer moves first.

§Errors

When the hands are not 10 cards each, the stock is not the remaining 31 cards, or any card appears twice.

Source

pub fn deal(rules: Rules, dealer: Player, rng: &mut (impl Rng + ?Sized)) -> Self

Shuffle and deal a fresh round: 10 cards to each player, an upcard, and a randomly ordered 31-card stock

Source

pub const fn rules(&self) -> &Rules

The scoring rules of this round

Source

pub const fn dealer(&self) -> Player

The dealer of this round

Source

pub const fn non_dealer(&self) -> Player

The non-dealer, who receives the first upcard offer

Source

pub const fn phase(&self) -> Phase

The current phase

Source

pub const fn turn(&self) -> Option<Player>

The player to act, or None once the round is finished

During the layoff phase this is the defender.

Source

pub const fn hand(&self, player: Player) -> Hand

The hand of a player

Both hands are visible by design; bots enforce their own information hygiene.

Source

pub fn discard_pile(&self) -> &[Card]

The discard pile; the top card is the last element

Source

pub fn stock(&self) -> &[Card]

The face-down stock; the top card is the last element

The full order is visible by design; bots enforce their own information hygiene.

Source

pub const fn knock_limit(&self) -> u8

The knock limit in effect for this round

Rules::knock_limit, capped by the opening upcard’s value under an Oklahoma ruleset (Rules::oklahoma). Read the limit here rather than from the rules.

Source

pub const fn initial_upcard(&self) -> Card

The opening upcard that seeded the discard pile

Remembered even after the card is drawn; under Rules::oklahoma it sets knock_limit.

Source

pub const fn knocker(&self) -> Option<Player>

The player who knocked or declared big gin, if any

Source

pub fn spread(&self) -> impl Iterator<Item = Meld> + '_

The knocker’s spread, extended by any layoffs so far

Empty before a knock.

Source

pub fn laid_off(&self) -> Hand

The cards the defender has laid off onto the spread

Source

pub const fn result(&self) -> Option<RoundResult>

The outcome, or None while the round is in play

Source

pub fn pass(&mut self) -> Result<(), RoundError>

Decline the initial upcard

The offer moves from the non-dealer to the dealer; when both pass, the non-dealer must open by drawing from the stock.

§Errors

RoundError::WrongPhase outside the upcard phase.

Source

pub fn take_discard(&mut self) -> Result<Card, RoundError>

Take the top of the discard pile, returning the card

Available as the upcard decision and as the draw of a normal turn.

§Errors

RoundError::WrongPhase outside the upcard and draw phases, and RoundError::MustDrawFromStock on the forced stock draw after both players passed the upcard.

Source

pub fn draw_stock(&mut self) -> Result<Card, RoundError>

Draw the top of the stock, returning the card

§Errors

RoundError::WrongPhase outside the draw phase.

Source

pub fn discard(&mut self, card: Card) -> Result<(), RoundError>

Discard a card, ending the turn

If this leaves two cards in the stock, the round ends as a dead hand: nobody scores and the same dealer redeals.

§Errors

RoundError::WrongPhase outside the discard phase, RoundError::NotInHand, and RoundError::DiscardJustTaken for the card drawn from the discard pile this turn.

Source

pub fn knock(&mut self, card: Card, melds: Melds) -> Result<(), RoundError>

Discard a card and knock, spreading the given arrangement

The knocker chooses the arrangement — it decides what the defender may lay off — so it is passed explicitly; best_melds(hand - card) recovers the automatic choice:

let hand = round.hand(round.turn().unwrap());
round.knock(card, best_melds(hand - card.into()))

An arrangement with zero deadwood is gin: the defender may not lay off, and the round finishes immediately. Otherwise the round enters the layoff phase.

§Errors

RoundError::WrongPhase outside the discard phase, RoundError::NotInHand, RoundError::DiscardJustTaken, RoundError::MeldsMismatch when melds does not arrange exactly the hand minus the discard, and RoundError::TooMuchDeadwood over the knock limit.

Source

pub fn declare_big_gin(&mut self, melds: Melds) -> Result<(), RoundError>

Declare big gin: all 11 cards melded, no discard

The defender may not lay off, and the round finishes immediately. Declaring is never forced — nor ever a trap: an 11-card fully-melded hand always contains a meld of four or more cards, which can shed a card, so plain gin remains available when the rules disable big gin.

§Errors

RoundError::WrongPhase outside the discard phase, RoundError::BigGinDisabled when Rules::big_gin_bonus is None, RoundError::MeldsMismatch when melds does not arrange the full hand, and RoundError::NotBigGin on any deadwood.

Source

pub fn lay_off(&mut self, card: Card, index: usize) -> Result<(), RoundError>

Lay off a card onto the meld at index in the knocker’s spread

Indices are stable across layoffs, so chained extensions — the ♠8 then the ♠9 onto a 5-6-7 of spades — address the same meld.

§Errors

RoundError::WrongPhase outside the layoff phase, RoundError::NotInHand, RoundError::NoSuchMeld, and RoundError::CannotLayOff when the card extends neither end of a run nor completes a set.

Source

pub fn finish_layoffs(&mut self) -> Result<RoundResult, RoundError>

End the layoff phase and settle the round

The defender’s remaining cards are melded optimally. The defender wins an undercut on less deadwood than the knocker kept — or equal deadwood under Rules::undercut_on_tie; otherwise the knocker wins the deadwood difference.

§Errors

RoundError::WrongPhase outside the layoff phase.

Trait Implementations§

Source§

impl Clone for Round

Source§

fn clone(&self) -> Round

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Round

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Round

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for Round

Source§

impl PartialEq for Round

Source§

fn eq(&self, other: &Round) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Round

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Round

Auto Trait Implementations§

§

impl Freeze for Round

§

impl RefUnwindSafe for Round

§

impl Send for Round

§

impl Sync for Round

§

impl Unpin for Round

§

impl UnsafeUnpin for Round

§

impl UnwindSafe for Round

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.