DealerHand

Struct DealerHand 

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

The dealer’s hand.

Implementations§

Source§

impl DealerHand

Source

pub const fn new() -> Self

Creates a new empty dealer hand.

Source

pub fn add_card(&mut self, card: Card)

Adds a card to the hand.

Source

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

Returns all cards in the hand.

Examples found in repository?
examples/cli_blackjack.rs (line 337)
336fn format_dealer(dealer: &bjrs::DealerHand) -> String {
337    if dealer.cards().is_empty() {
338        return "(no cards)".to_string();
339    }
340
341    if dealer.is_hole_revealed() {
342        dealer
343            .cards()
344            .iter()
345            .map(format_card)
346            .collect::<Vec<_>>()
347            .join(" ")
348    } else {
349        let mut parts = Vec::new();
350        if let Some(card) = dealer.up_card() {
351            parts.push(format_card(card));
352        }
353        if dealer.len() > 1 {
354            parts.push("??".to_string());
355        }
356        parts.join(" ")
357    }
358}
Source

pub fn up_card(&self) -> Option<&Card>

Returns the visible card (first card).

Examples found in repository?
examples/cli_blackjack.rs (line 350)
336fn format_dealer(dealer: &bjrs::DealerHand) -> String {
337    if dealer.cards().is_empty() {
338        return "(no cards)".to_string();
339    }
340
341    if dealer.is_hole_revealed() {
342        dealer
343            .cards()
344            .iter()
345            .map(format_card)
346            .collect::<Vec<_>>()
347            .join(" ")
348    } else {
349        let mut parts = Vec::new();
350        if let Some(card) = dealer.up_card() {
351            parts.push(format_card(card));
352        }
353        if dealer.len() > 1 {
354            parts.push("??".to_string());
355        }
356        parts.join(" ")
357    }
358}
Source

pub const fn is_hole_revealed(&self) -> bool

Returns whether the hole card is revealed.

Examples found in repository?
examples/cli_blackjack.rs (line 175)
169fn print_table(game: &Game, player_id: u8) {
170    let remaining = game.cards_remaining();
171    println!("\nShoe: {remaining} cards remaining");
172
173    let dealer = game.get_dealer_hand();
174    let dealer_view = format_dealer(&dealer);
175    let dealer_value = if dealer.is_hole_revealed() {
176        dealer.value()
177    } else {
178        dealer.visible_value()
179    };
180    println!("\nDealer: {dealer_view} (value {dealer_value})");
181
182    let hands = game.get_hands(player_id).unwrap_or_default();
183    let turn = game.current_turn();
184    for (index, hand) in hands.iter().enumerate() {
185        let marker = if index == turn.hand_index { "*" } else { " " };
186        println!(
187            "{} Hand {}: {} | value {} | bet {} | {:?}",
188            marker,
189            index,
190            format_hand(hand),
191            hand.value(),
192            hand.bet(),
193            hand.status()
194        );
195    }
196    println!();
197}
198
199fn print_table_final(game: &Game, player_id: u8) {
200    let remaining = game.cards_remaining();
201    println!("\nShoe: {remaining} cards remaining");
202
203    let dealer = game.get_dealer_hand();
204    println!(
205        "\nDealer: {} (value {})",
206        format_dealer(&dealer),
207        dealer.value()
208    );
209
210    let hands = game.get_hands(player_id).unwrap_or_default();
211    for (index, hand) in hands.iter().enumerate() {
212        println!(
213            "Hand {}: {} | value {} | bet {} | {:?}",
214            index,
215            format_hand(hand),
216            hand.value(),
217            hand.bet(),
218            hand.status()
219        );
220    }
221    println!();
222}
223
224fn format_actions(game: &Game, player_id: u8) -> String {
225    let availability = available_actions(game, player_id);
226    let mut parts = Vec::new();
227    parts.push(format_action("hit", "h", availability.hit));
228    parts.push(format_action("stand", "s", availability.stand));
229    parts.push(format_action("double", "d", availability.double));
230    parts.push(format_action("split", "p", availability.split));
231    parts.push(format_action("surrender", "u", availability.surrender));
232    format!("Actions: {}", parts.join(" "))
233}
234
235fn format_action(label: &str, key: &str, allowed: bool) -> String {
236    let text = format!("[{key}]{label}");
237    if allowed {
238        colorize(&text, "32")
239    } else {
240        colorize(&text, "90")
241    }
242}
243
244fn colorize(text: &str, code: &str) -> String {
245    format!("\u{1b}[{code}m{text}\u{1b}[0m")
246}
247
248struct ActionAvailability {
249    hit: bool,
250    stand: bool,
251    double: bool,
252    split: bool,
253    surrender: bool,
254}
255
256fn available_actions(game: &Game, player_id: u8) -> ActionAvailability {
257    if *game.state.lock() != GameState::PlayerTurn {
258        return ActionAvailability {
259            hit: false,
260            stand: false,
261            double: false,
262            split: false,
263            surrender: false,
264        };
265    }
266
267    if game.current_player() != Some(player_id) {
268        return ActionAvailability {
269            hit: false,
270            stand: false,
271            double: false,
272            split: false,
273            surrender: false,
274        };
275    }
276
277    let hands = game.get_hands(player_id).unwrap_or_default();
278    let turn = game.current_turn();
279    let Some(hand) = hands.get(turn.hand_index) else {
280        return ActionAvailability {
281            hit: false,
282            stand: false,
283            double: false,
284            split: false,
285            surrender: false,
286        };
287    };
288
289    if hand.status() != HandStatus::Active {
290        return ActionAvailability {
291            hit: false,
292            stand: false,
293            double: false,
294            split: false,
295            surrender: false,
296        };
297    }
298
299    let money = game.get_money(player_id).unwrap_or(0);
300    let bet = hand.bet();
301    let has_funds_for_double = money >= bet;
302    let has_funds_for_split = money >= bet;
303
304    let can_double_value = match game.options.double {
305        DoubleOption::Any => true,
306        DoubleOption::NineOrTen => hand.value() == 9 || hand.value() == 10,
307        DoubleOption::NineThrough11 => (9..=11).contains(&hand.value()),
308        DoubleOption::NineThrough15 => (9..=15).contains(&hand.value()),
309        DoubleOption::None => false,
310        _ => panic!("unhandled double option"),
311    };
312
313    let can_double = hand.len() == 2
314        && (!hand.is_from_split() || game.options.double_after_split)
315        && can_double_value
316        && has_funds_for_double;
317
318    let is_ace = hand.cards().first().is_some_and(|c| c.rank == 1);
319    let max_splits_reached = hands.len() > game.options.split as usize;
320    let can_split = hand.can_split()
321        && !max_splits_reached
322        && has_funds_for_split
323        && !(is_ace && hand.is_from_split() && game.options.split_aces_only_once);
324
325    let can_surrender = game.options.surrender && hand.len() == 2 && !hand.is_from_split();
326
327    ActionAvailability {
328        hit: true,
329        stand: true,
330        double: can_double,
331        split: can_split,
332        surrender: can_surrender,
333    }
334}
335
336fn format_dealer(dealer: &bjrs::DealerHand) -> String {
337    if dealer.cards().is_empty() {
338        return "(no cards)".to_string();
339    }
340
341    if dealer.is_hole_revealed() {
342        dealer
343            .cards()
344            .iter()
345            .map(format_card)
346            .collect::<Vec<_>>()
347            .join(" ")
348    } else {
349        let mut parts = Vec::new();
350        if let Some(card) = dealer.up_card() {
351            parts.push(format_card(card));
352        }
353        if dealer.len() > 1 {
354            parts.push("??".to_string());
355        }
356        parts.join(" ")
357    }
358}
Source

pub const fn reveal_hole(&mut self)

Reveals the hole card.

Source

pub fn visible_value(&self) -> u8

Calculates the visible value (only up card if hole not revealed).

Examples found in repository?
examples/cli_blackjack.rs (line 178)
169fn print_table(game: &Game, player_id: u8) {
170    let remaining = game.cards_remaining();
171    println!("\nShoe: {remaining} cards remaining");
172
173    let dealer = game.get_dealer_hand();
174    let dealer_view = format_dealer(&dealer);
175    let dealer_value = if dealer.is_hole_revealed() {
176        dealer.value()
177    } else {
178        dealer.visible_value()
179    };
180    println!("\nDealer: {dealer_view} (value {dealer_value})");
181
182    let hands = game.get_hands(player_id).unwrap_or_default();
183    let turn = game.current_turn();
184    for (index, hand) in hands.iter().enumerate() {
185        let marker = if index == turn.hand_index { "*" } else { " " };
186        println!(
187            "{} Hand {}: {} | value {} | bet {} | {:?}",
188            marker,
189            index,
190            format_hand(hand),
191            hand.value(),
192            hand.bet(),
193            hand.status()
194        );
195    }
196    println!();
197}
Source

pub fn value(&self) -> u8

Calculates the full value of the hand.

Examples found in repository?
examples/cli_blackjack.rs (line 176)
169fn print_table(game: &Game, player_id: u8) {
170    let remaining = game.cards_remaining();
171    println!("\nShoe: {remaining} cards remaining");
172
173    let dealer = game.get_dealer_hand();
174    let dealer_view = format_dealer(&dealer);
175    let dealer_value = if dealer.is_hole_revealed() {
176        dealer.value()
177    } else {
178        dealer.visible_value()
179    };
180    println!("\nDealer: {dealer_view} (value {dealer_value})");
181
182    let hands = game.get_hands(player_id).unwrap_or_default();
183    let turn = game.current_turn();
184    for (index, hand) in hands.iter().enumerate() {
185        let marker = if index == turn.hand_index { "*" } else { " " };
186        println!(
187            "{} Hand {}: {} | value {} | bet {} | {:?}",
188            marker,
189            index,
190            format_hand(hand),
191            hand.value(),
192            hand.bet(),
193            hand.status()
194        );
195    }
196    println!();
197}
198
199fn print_table_final(game: &Game, player_id: u8) {
200    let remaining = game.cards_remaining();
201    println!("\nShoe: {remaining} cards remaining");
202
203    let dealer = game.get_dealer_hand();
204    println!(
205        "\nDealer: {} (value {})",
206        format_dealer(&dealer),
207        dealer.value()
208    );
209
210    let hands = game.get_hands(player_id).unwrap_or_default();
211    for (index, hand) in hands.iter().enumerate() {
212        println!(
213            "Hand {}: {} | value {} | bet {} | {:?}",
214            index,
215            format_hand(hand),
216            hand.value(),
217            hand.bet(),
218            hand.status()
219        );
220    }
221    println!();
222}
Source

pub fn is_blackjack(&self) -> bool

Returns whether the hand is a blackjack.

Source

pub fn is_bust(&self) -> bool

Returns whether the hand is bust.

Source

pub fn is_soft(&self) -> bool

Returns whether the hand is soft (contains an ace counted as 11).

Source

pub fn len(&self) -> usize

Returns the number of cards.

Examples found in repository?
examples/cli_blackjack.rs (line 353)
336fn format_dealer(dealer: &bjrs::DealerHand) -> String {
337    if dealer.cards().is_empty() {
338        return "(no cards)".to_string();
339    }
340
341    if dealer.is_hole_revealed() {
342        dealer
343            .cards()
344            .iter()
345            .map(format_card)
346            .collect::<Vec<_>>()
347            .join(" ")
348    } else {
349        let mut parts = Vec::new();
350        if let Some(card) = dealer.up_card() {
351            parts.push(format_card(card));
352        }
353        if dealer.len() > 1 {
354            parts.push("??".to_string());
355        }
356        parts.join(" ")
357    }
358}
Source

pub fn is_empty(&self) -> bool

Returns whether the hand is empty.

Source

pub fn clear(&mut self)

Clears the hand for a new round.

Trait Implementations§

Source§

impl Clone for DealerHand

Source§

fn clone(&self) -> DealerHand

Returns a duplicate of the value. Read more
1.0.0 · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for DealerHand

Source§

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

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

impl Default for DealerHand

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

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> 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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V