poker/
lib.rs

1//! # Poker
2//!
3//! `poker` is a crate for efficient poker hand evaluation supporting both
4//! 5-card and 3-card poker hands. It is ported into Rust from the [`treys`]
5//! Python package, utilizing fast lookup algorithms for speedy evaluation,
6//! which have been adapted and made more idiomatic for Rust where appropriate.
7//!
8//! ## 5-Card Poker Example
9//!
10//! ```
11//! # fn main() {
12//! #     if run().is_err() { std::process::exit(1); }
13//! # }
14//! #
15//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
16//! use poker::{Card, Evaluator, Rank, cards, evaluate::FiveCardHandClass};
17//!
18//! // Create a reusable evaluator
19//! let eval = Evaluator::new();
20//!
21//! // Parse a `Vec` of cards from a str
22//! let royal_flush_cards: Vec<Card> = cards!("Ks Js Ts Qs As").try_collect()?;
23//!
24//! // Evaluate the hand
25//! let royal_flush_eval = eval.evaluate_five(royal_flush_cards)?;
26//!
27//! assert!(matches!(
28//!     royal_flush_eval.classify(),
29//!     FiveCardHandClass::StraightFlush { rank: Rank::Ace }
30//! ));
31//! assert!(royal_flush_eval.is_royal_flush());
32//!
33//! // Compare hands
34//! let pair_cards: Vec<Card> = cards!("3c 4h Td 3h Kd").try_collect()?;
35//! let pair_eval = eval.evaluate_five(pair_cards)?;
36//! assert!(royal_flush_eval.is_better_than(pair_eval));
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! ## 3-Card Poker Example
42//!
43//! ```
44//! # fn main() {
45//! #     if run().is_err() { std::process::exit(1); }
46//! # }
47//! #
48//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
49//! use poker::{Card, Evaluator, Rank, cards};
50//!
51//! // Create a reusable evaluator
52//! let eval = Evaluator::new();
53//!
54//! // Three-card straight flush
55//! let straight_flush: Vec<Card> = cards!("Ah Kh Qh").try_collect()?;
56//! let sf_eval = eval.evaluate_three(straight_flush)?;
57//!
58//! assert!(sf_eval.is_straight_flush());
59//! assert_eq!(sf_eval.straight_flush(), Some(Rank::Ace));
60//!
61//! // Compare with three of a kind (straight flush beats three of a kind)
62//! let trips: Vec<Card> = cards!("As Ad Ac").try_collect()?;
63//! let trips_eval = eval.evaluate_three(trips)?;
64//! assert!(sf_eval.is_better_than(trips_eval));
65//! # Ok(())
66//! # }
67//! ```
68//!
69//!
70//! The [`Evaluator`] does not expose any mutable methods, so it's perfectly
71//! safe to wrap it into an [`Arc`](std::sync::Arc) and share it between
72//! multiple threads.
73//!
74//! ```
75//! # fn main() {
76//! #     if run().is_err() { std::process::exit(1); }
77//! # }
78//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
79//! use std::{cmp, sync::Arc, thread};
80//!
81//! use poker::{Eval, Evaluator, FiveCard, deck};
82//!
83//! let shared_evaluator = Arc::new(Evaluator::new());
84//! let mut handles = vec![];
85//! for _ in 0..10 {
86//!     let evaluator = Arc::clone(&shared_evaluator);
87//!     handles.push(thread::spawn(move || {
88//!         let deck = deck::shuffled();
89//!         let hand = &deck[..5];
90//!         evaluator
91//!             .evaluate_five(hand)
92//!             .unwrap_or(Eval::<FiveCard>::WORST_FIVE)
93//!     }));
94//! }
95//!
96//! let max = handles
97//!     .into_iter()
98//!     .filter_map(|handle| handle.join().ok())
99//!     .fold(Eval::<FiveCard>::WORST_FIVE, cmp::max);
100//!
101//! println!("{}", max);
102//! # Ok(())
103//! # }
104//! ```
105//! [`treys`]: https://github.com/ihendley/treys
106
107#![forbid(unsafe_code)]
108#![warn(missing_docs, missing_debug_implementations)]
109#![doc(html_root_url = "https://docs.rs/poker/0.7")]
110
111#[cfg(doctest)]
112doc_comment::doctest!("../README.md");
113
114pub mod card;
115mod constants;
116pub mod deck;
117pub mod error;
118pub mod evaluate;
119
120#[doc(inline)]
121pub use card::{Card, Rank, Suit};
122#[doc(inline)]
123pub use error::{EvalError, EvalResult, ParseCardError};
124#[doc(inline)]
125pub use evaluate::{
126    eval::Eval,
127    evaluator::Evaluator,
128    poker_type::{FiveCard, ThreeCard},
129};