Rust 练习册 :Poker与扑克牌游戏

扑克牌游戏是世界上最流行的纸牌游戏之一,具有复杂的规则和策略。在 Exercism 的 "poker" 练习中,我们需要实现一个函数来确定给定扑克牌手牌中的获胜者。这不仅能帮助我们掌握复杂规则的实现和比较算法,还能深入学习Rust中的枚举、模式匹配、排序和算法设计。

什么是扑克牌游戏?

扑克牌游戏有许多变种,其中最流行的是德州扑克。在这个练习中,我们需要实现标准扑克牌游戏中各种牌型的比较规则。扑克牌的牌型从低到高依次为:

  1. 高牌(High Card):没有形成任何特定组合的牌
  2. 一对(One Pair):两张相同点数的牌
  3. 两对(Two Pair):两个不同点数的对子
  4. 三条(Three of a Kind):三张相同点数的牌
  5. 顺子(Straight):五张连续点数的牌
  6. 同花(Flush):五张相同花色的牌
  7. 葫芦(Full House):三条加一对
  8. 四条(Four of a Kind):四张相同点数的牌
  9. 同花顺(Straight Flush):五张相同花色的连续牌
  10. 皇家同花顺(Royal Flush):10、J、Q、K、A的同花顺

让我们先看看练习提供的函数签名:

rust 复制代码
/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    unimplemented!("Out of {:?}, which hand wins?", hands)
}

我们需要实现 winning_hands 函数,从给定的扑克牌手牌中找出获胜的手牌。

设计分析

1. 核心要求

  1. 牌面解析:正确解析字符串表示的扑克牌
  2. 牌型识别:识别手牌的牌型并进行分类
  3. 牌型比较:比较不同手牌的牌型和点数
  4. 平局处理:正确处理多个获胜者的情况

2. 技术要点

  1. 枚举设计:设计合适的枚举表示牌型和牌面
  2. 模式匹配:使用模式匹配处理复杂的比较逻辑
  3. 排序算法:实现牌面的排序和比较
  4. 引用处理:正确处理字符串引用,返回原始引用

完整实现

1. 基础实现

rust 复制代码
use std::cmp::Ordering;
use std::collections::HashMap;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    if hands.is_empty() {
        return vec![];
    }
    
    // 将字符串手牌转换为Hand结构体
    let mut parsed_hands: Vec<(Hand, &str)> = hands
        .iter()
        .map(|&hand_str| (Hand::from_str(hand_str), hand_str))
        .collect();
    
    // 按照牌力排序(降序)
    parsed_hands.sort_by(|a, b| b.0.cmp(&a.0));
    
    // 找到所有获胜的手牌(与最高牌力相同的手牌)
    let winning_hand = &parsed_hands[0].0;
    parsed_hands
        .into_iter()
        .take_while(|(hand, _)| hand == winning_hand)
        .map(|(_, hand_str)| hand_str)
        .collect()
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Card {
    rank: Rank,
    suit: Suit,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

impl Card {
    fn from_str(s: &str) -> Card {
        let chars: Vec<char> = s.chars().collect();
        if chars.len() < 2 {
            panic!("Invalid card string: {}", s);
        }
        
        let rank = match chars[0] {
            '2' => Rank::Two,
            '3' => Rank::Three,
            '4' => Rank::Four,
            '5' => Rank::Five,
            '6' => Rank::Six,
            '7' => Rank::Seven,
            '8' => Rank::Eight,
            '9' => Rank::Nine,
            '1' if chars.len() >= 2 && chars[1] == '0' => Rank::Ten,
            'T' | '0' => Rank::Ten,
            'J' => Rank::Jack,
            'Q' => Rank::Queen,
            'K' => Rank::King,
            'A' => Rank::Ace,
            _ => panic!("Invalid rank in card string: {}", s),
        };
        
        let suit_char = if chars[0] == '1' && chars.len() >= 2 && chars[1] == '0' {
            // 处理"10"的情况
            if chars.len() >= 3 {
                chars[2]
            } else {
                panic!("Invalid card string: {}", s);
            }
        } else {
            chars[chars.len() - 1]
        };
        
        let suit = match suit_char {
            'C' => Suit::Clubs,
            'D' => Suit::Diamonds,
            'H' => Suit::Hearts,
            'S' => Suit::Spades,
            _ => panic!("Invalid suit in card string: {}", s),
        };
        
        Card { rank, suit }
    }
}

#[derive(Debug, Clone)]
struct Hand {
    cards: Vec<Card>,
    hand_type: HandType,
    rank_counts: HashMap<Rank, usize>,
    sorted_ranks: Vec<Rank>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum HandType {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl Hand {
    fn from_str(hand_str: &str) -> Hand {
        let card_strs: Vec<&str> = hand_str.split_whitespace().collect();
        let cards: Vec<Card> = card_strs.iter().map(|&s| Card::from_str(s)).collect();
        
        if cards.len() != 5 {
            panic!("Invalid hand: must contain exactly 5 cards");
        }
        
        let mut rank_counts = HashMap::new();
        for card in &cards {
            *rank_counts.entry(card.rank.clone()).or_insert(0) += 1;
        }
        
        let hand_type = Self::determine_hand_type(&cards, &rank_counts);
        
        let mut sorted_ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        sorted_ranks.sort_by(|a, b| b.cmp(a)); // 降序排列
        
        Hand {
            cards,
            hand_type,
            rank_counts,
            sorted_ranks,
        }
    }
    
    fn determine_hand_type(cards: &[Card], rank_counts: &HashMap<Rank, usize>) -> HandType {
        let is_flush = cards.iter().all(|card| card.suit == cards[0].suit);
        
        let mut ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        ranks.sort();
        
        let is_straight = Self::is_straight(&ranks);
        
        // 特殊情况:A,2,3,4,5 是顺子
        let is_low_straight = ranks == vec![Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Ace];
        
        if is_flush && (is_straight || is_low_straight) {
            return HandType::StraightFlush;
        }
        
        if is_flush {
            return HandType::Flush;
        }
        
        if is_straight || is_low_straight {
            return HandType::Straight;
        }
        
        let counts: Vec<usize> = rank_counts.values().cloned().collect();
        let mut count_counts = HashMap::new();
        for &count in &counts {
            *count_counts.entry(count).or_insert(0) += 1;
        }
        
        if count_counts.get(&4).unwrap_or(&0) == &1 {
            HandType::FourOfAKind
        } else if count_counts.get(&3).unwrap_or(&0) == &1 && count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::FullHouse
        } else if count_counts.get(&3).unwrap_or(&0) == &1 {
            HandType::ThreeOfAKind
        } else if count_counts.get(&2).unwrap_or(&0) == &2 {
            HandType::TwoPair
        } else if count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::OnePair
        } else {
            HandType::HighCard
        }
    }
    
    fn is_straight(ranks: &[Rank]) -> bool {
        if ranks.len() != 5 {
            return false;
        }
        
        for i in 0..4 {
            if (ranks[i + 1] as u8) != (ranks[i] as u8) + 1 {
                return false;
            }
        }
        
        true
    }
}

impl PartialEq for Hand {
    fn eq(&self, other: &Self) -> bool {
        self.hand_type == other.hand_type && self.sorted_ranks == other.sorted_ranks
    }
}

impl Eq for Hand {}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        // 首先比较牌型
        let hand_type_order = |hand_type: &HandType| -> u8 {
            match hand_type {
                HandType::HighCard => 0,
                HandType::OnePair => 1,
                HandType::TwoPair => 2,
                HandType::ThreeOfAKind => 3,
                HandType::Straight => 4,
                HandType::Flush => 5,
                HandType::FullHouse => 6,
                HandType::FourOfAKind => 7,
                HandType::StraightFlush => 8,
            }
        };
        
        let self_type_order = hand_type_order(&self.hand_type);
        let other_type_order = hand_type_order(&other.hand_type);
        
        match self_type_order.cmp(&other_type_order) {
            Ordering::Equal => {
                // 牌型相同时,比较具体的牌力
                self.compare_same_type(other)
            }
            other => other,
        }
    }
}

impl Hand {
    fn compare_same_type(&self, other: &Self) -> Ordering {
        match self.hand_type {
            HandType::HighCard | HandType::Flush | HandType::Straight | HandType::StraightFlush => {
                // 比较最高牌,然后依次比较
                for (self_rank, other_rank) in self.sorted_ranks.iter().zip(other.sorted_ranks.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                Ordering::Equal
            }
            HandType::OnePair => {
                // 比较对子的点数
                let self_pair_rank = self.get_rank_by_count(2);
                let other_pair_rank = other.get_rank_by_count(2);
                
                match self_pair_rank.cmp(&other_pair_rank) {
                    Ordering::Equal => {
                        // 对子相同,比较剩余牌
                        self.compare_kickers(&[self_pair_rank], &other, &[other_pair_rank])
                    }
                    other => other,
                }
            }
            HandType::TwoPair => {
                // 比较两对的点数(从高到低)
                let mut self_pairs: Vec<Rank> = self.get_ranks_by_count(2);
                let mut other_pairs: Vec<Rank> = other.get_ranks_by_count(2);
                self_pairs.sort_by(|a, b| b.cmp(a));
                other_pairs.sort_by(|a, b| b.cmp(a));
                
                for (self_rank, other_rank) in self_pairs.iter().zip(other_pairs.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                
                // 两对都相同,比较单牌
                self.compare_kickers(&self_pairs, &other, &other_pairs)
            }
            HandType::ThreeOfAKind => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较剩余牌
                        self.compare_kickers(&[self_three_rank], &other, &[other_three_rank])
                    }
                    other => other,
                }
            }
            HandType::FullHouse => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较对子
                        let self_pair_rank = self.get_rank_by_count(2);
                        let other_pair_rank = other.get_rank_by_count(2);
                        self_pair_rank.cmp(&other_pair_rank)
                    }
                    other => other,
                }
            }
            HandType::FourOfAKind => {
                // 比较四条的点数
                let self_four_rank = self.get_rank_by_count(4);
                let other_four_rank = other.get_rank_by_count(4);
                
                match self_four_rank.cmp(&other_four_rank) {
                    Ordering::Equal => {
                        // 四条相同,比较剩余牌
                        self.compare_kickers(&[self_four_rank], &other, &[other_four_rank])
                    }
                    other => other,
                }
            }
        }
    }
    
    fn get_rank_by_count(&self, count: usize) -> Rank {
        self.rank_counts
            .iter()
            .find(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .unwrap()
    }
    
    fn get_ranks_by_count(&self, count: usize) -> Vec<Rank> {
        self.rank_counts
            .iter()
            .filter(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .collect()
    }
    
    fn compare_kickers(&self, exclude_ranks: &[Rank], other: &Self, other_exclude_ranks: &[Rank]) -> Ordering {
        let mut self_ranks: Vec<Rank> = self.sorted_ranks.clone();
        let mut other_ranks: Vec<Rank> = other.sorted_ranks.clone();
        
        // 移除需要排除的点数
        self_ranks.retain(|r| !exclude_ranks.contains(r));
        other_ranks.retain(|r| !other_exclude_ranks.contains(r));
        
        // 比较剩余牌
        for (self_rank, other_rank) in self_ranks.iter().zip(other_ranks.iter()) {
            match self_rank.cmp(other_rank) {
                Ordering::Equal => continue,
                other => return other,
            }
        }
        
        Ordering::Equal
    }
}

2. 优化实现

rust 复制代码
use std::cmp::Ordering;
use std::collections::HashMap;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    if hands.is_empty() {
        return vec![];
    }
    
    // 将字符串手牌转换为Hand结构体
    let mut parsed_hands: Vec<(Hand, &str)> = hands
        .iter()
        .map(|&hand_str| (Hand::from_str(hand_str), hand_str))
        .collect();
    
    // 按照牌力排序(降序)
    parsed_hands.sort_unstable_by(|a, b| b.0.cmp(&a.0));
    
    // 找到所有获胜的手牌(与最高牌力相同的手牌)
    let winning_hand = &parsed_hands[0].0;
    parsed_hands
        .into_iter()
        .take_while(|(hand, _)| hand.cmp(winning_hand) == Ordering::Equal)
        .map(|(_, hand_str)| hand_str)
        .collect()
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Card {
    rank: Rank,
    suit: Suit,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

impl Rank {
    fn from_char(c: char) -> Option<Rank> {
        match c {
            '2' => Some(Rank::Two),
            '3' => Some(Rank::Three),
            '4' => Some(Rank::Four),
            '5' => Some(Rank::Five),
            '6' => Some(Rank::Six),
            '7' => Some(Rank::Seven),
            '8' => Some(Rank::Eight),
            '9' => Some(Rank::Nine),
            'T' | '0' => Some(Rank::Ten),
            'J' => Some(Rank::Jack),
            'Q' => Some(Rank::Queen),
            'K' => Some(Rank::King),
            'A' => Some(Rank::Ace),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

impl Suit {
    fn from_char(c: char) -> Option<Suit> {
        match c {
            'C' => Some(Suit::Clubs),
            'D' => Some(Suit::Diamonds),
            'H' => Some(Suit::Hearts),
            'S' => Some(Suit::Spades),
            _ => None,
        }
    }
}

impl Card {
    fn from_str(s: &str) -> Card {
        let chars: Vec<char> = s.chars().collect();
        
        if chars.is_empty() {
            panic!("Invalid card string: {}", s);
        }
        
        let (rank_char, suit_char) = if chars.len() >= 3 && chars[0] == '1' && chars[1] == '0' {
            // 处理"10"的情况
            if chars.len() >= 3 {
                ('0', chars[2])
            } else {
                panic!("Invalid card string: {}", s);
            }
        } else if chars.len() >= 2 {
            (chars[0], chars[chars.len() - 1])
        } else {
            panic!("Invalid card string: {}", s);
        };
        
        let rank = Rank::from_char(rank_char)
            .unwrap_or_else(|| panic!("Invalid rank in card string: {}", s));
        let suit = Suit::from_char(suit_char)
            .unwrap_or_else(|| panic!("Invalid suit in card string: {}", s));
        
        Card { rank, suit }
    }
}

#[derive(Debug, Clone)]
struct Hand {
    cards: Vec<Card>,
    hand_type: HandType,
    rank_counts: HashMap<Rank, usize>,
    sorted_ranks: Vec<Rank>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum HandType {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl HandType {
    fn rank(&self) -> u8 {
        match self {
            HandType::HighCard => 0,
            HandType::OnePair => 1,
            HandType::TwoPair => 2,
            HandType::ThreeOfAKind => 3,
            HandType::Straight => 4,
            HandType::Flush => 5,
            HandType::FullHouse => 6,
            HandType::FourOfAKind => 7,
            HandType::StraightFlush => 8,
        }
    }
}

impl Hand {
    fn from_str(hand_str: &str) -> Hand {
        let card_strs: Vec<&str> = hand_str.split_whitespace().collect();
        
        if card_strs.len() != 5 {
            panic!("Invalid hand: must contain exactly 5 cards");
        }
        
        let cards: Vec<Card> = card_strs.iter().map(|&s| Card::from_str(s)).collect();
        let mut rank_counts = HashMap::new();
        
        for card in &cards {
            *rank_counts.entry(card.rank.clone()).or_insert(0) += 1;
        }
        
        let hand_type = Self::determine_hand_type(&cards, &rank_counts);
        
        let mut sorted_ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        sorted_ranks.sort_by(|a, b| b.cmp(a)); // 降序排列
        
        Hand {
            cards,
            hand_type,
            rank_counts,
            sorted_ranks,
        }
    }
    
    fn determine_hand_type(cards: &[Card], rank_counts: &HashMap<Rank, usize>) -> HandType {
        let is_flush = cards.iter().all(|card| card.suit == cards[0].suit);
        
        let mut ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        ranks.sort();
        
        let is_straight = Self::is_straight(&ranks);
        
        // 特殊情况:A,2,3,4,5 是顺子
        let is_low_straight = ranks == vec![Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Ace];
        
        if is_flush && (is_straight || is_low_straight) {
            return HandType::StraightFlush;
        }
        
        let counts: Vec<usize> = rank_counts.values().cloned().collect();
        let mut count_counts = HashMap::new();
        for &count in &counts {
            *count_counts.entry(count).or_insert(0) += 1;
        }
        
        if count_counts.get(&4).unwrap_or(&0) == &1 {
            HandType::FourOfAKind
        } else if count_counts.get(&3).unwrap_or(&0) == &1 && count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::FullHouse
        } else if is_flush {
            HandType::Flush
        } else if is_straight || is_low_straight {
            HandType::Straight
        } else if count_counts.get(&3).unwrap_or(&0) == &1 {
            HandType::ThreeOfAKind
        } else if count_counts.get(&2).unwrap_or(&0) == &2 {
            HandType::TwoPair
        } else if count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::OnePair
        } else {
            HandType::HighCard
        }
    }
    
    fn is_straight(ranks: &[Rank]) -> bool {
        if ranks.len() != 5 {
            return false;
        }
        
        for i in 0..4 {
            if (ranks[i + 1] as u8) != (ranks[i] as u8) + 1 {
                return false;
            }
        }
        
        true
    }
}

impl PartialEq for Hand {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for Hand {}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        // 首先比较牌型
        match self.hand_type.rank().cmp(&other.hand_type.rank()) {
            Ordering::Equal => {
                // 牌型相同时,比较具体的牌力
                self.compare_same_type(other)
            }
            other => other,
        }
    }
}

impl Hand {
    fn compare_same_type(&self, other: &Self) -> Ordering {
        match self.hand_type {
            HandType::HighCard | HandType::Flush | HandType::Straight | HandType::StraightFlush => {
                // 比较最高牌,然后依次比较
                for (self_rank, other_rank) in self.sorted_ranks.iter().zip(other.sorted_ranks.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                Ordering::Equal
            }
            HandType::OnePair => {
                // 比较对子的点数
                let self_pair_rank = self.get_rank_by_count(2);
                let other_pair_rank = other.get_rank_by_count(2);
                
                match self_pair_rank.cmp(&other_pair_rank) {
                    Ordering::Equal => {
                        // 对子相同,比较剩余牌
                        self.compare_kickers(&[self_pair_rank], other, &[other_pair_rank])
                    }
                    other => other,
                }
            }
            HandType::TwoPair => {
                // 比较两对的点数(从高到低)
                let mut self_pairs: Vec<Rank> = self.get_ranks_by_count(2);
                let mut other_pairs: Vec<Rank> = other.get_ranks_by_count(2);
                self_pairs.sort_by(|a, b| b.cmp(a));
                other_pairs.sort_by(|a, b| b.cmp(a));
                
                for (self_rank, other_rank) in self_pairs.iter().zip(other_pairs.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                
                // 两对都相同,比较单牌
                self.compare_kickers(&self_pairs, other, &other_pairs)
            }
            HandType::ThreeOfAKind => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较剩余牌
                        self.compare_kickers(&[self_three_rank], other, &[other_three_rank])
                    }
                    other => other,
                }
            }
            HandType::FullHouse => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较对子
                        let self_pair_rank = self.get_rank_by_count(2);
                        let other_pair_rank = other.get_rank_by_count(2);
                        self_pair_rank.cmp(&other_pair_rank)
                    }
                    other => other,
                }
            }
            HandType::FourOfAKind => {
                // 比较四条的点数
                let self_four_rank = self.get_rank_by_count(4);
                let other_four_rank = other.get_rank_by_count(4);
                
                match self_four_rank.cmp(&other_four_rank) {
                    Ordering::Equal => {
                        // 四条相同,比较剩余牌
                        self.compare_kickers(&[self_four_rank], other, &[other_four_rank])
                    }
                    other => other,
                }
            }
        }
    }
    
    fn get_rank_by_count(&self, count: usize) -> Rank {
        self.rank_counts
            .iter()
            .find(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .unwrap()
    }
    
    fn get_ranks_by_count(&self, count: usize) -> Vec<Rank> {
        self.rank_counts
            .iter()
            .filter(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .collect()
    }
    
    fn compare_kickers(&self, exclude_ranks: &[Rank], other: &Self, other_exclude_ranks: &[Rank]) -> Ordering {
        let mut self_ranks: Vec<Rank> = self.sorted_ranks.clone();
        let mut other_ranks: Vec<Rank> = other.sorted_ranks.clone();
        
        // 移除需要排除的点数
        self_ranks.retain(|r| !exclude_ranks.contains(r));
        other_ranks.retain(|r| !other_exclude_ranks.contains(r));
        
        // 比较剩余牌
        for (self_rank, other_rank) in self_ranks.iter().zip(other_ranks.iter()) {
            match self_rank.cmp(other_rank) {
                Ordering::Equal => continue,
                other => return other,
            }
        }
        
        Ordering::Equal
    }
}

测试用例分析

通过查看测试用例,我们可以更好地理解需求:

rust 复制代码
#[test]
fn test_single_hand_always_wins() {
    test(&["4S 5S 7H 8D JC"], &["4S 5S 7H 8D JC"])
}

单个手牌总是获胜。

rust 复制代码
#[test]
fn test_duplicate_hands_always_tie() {
    let input = &["3S 4S 5D 6H JH", "3S 4S 5D 6H JH", "3S 4S 5D 6H JH"];
    assert_eq!(&winning_hands(input), input)
}

重复的手牌总是平局。

rust 复制代码
#[test]
fn test_highest_card_of_all_hands_wins() {
    test(
        &["4D 5S 6S 8D 3C", "2S 4C 7S 9H 10H", "3S 4S 5D 6H JH"],
        &["3S 4S 5D 6H JH"],
    )
}

所有手牌中的最高牌获胜(在这种情况下是J)。

rust 复制代码
#[test]
fn test_a_tie_has_multiple_winners() {
    test(
        &[
            "4D 5S 6S 8D 3C",
            "2S 4C 7S 9H 10H",
            "3S 4S 5D 6H JH",
            "3H 4H 5C 6C JD",
        ],
        &["3S 4S 5D 6H JH", "3H 4H 5C 6C JD"],
    )
}

平局时有多个获胜者。

rust 复制代码
#[test]
fn test_high_card_can_be_low_card_in_an_otherwise_tie() {
    // multiple hands with the same high cards, tie compares next highest ranked,
    // down to last card
    test(&["3S 5H 6S 8D 7H", "2S 5D 6D 8C 7S"], &["3S 5H 6S 8D 7H"])
}

当最高牌相同时,比较次高牌,以此类推。

rust 复制代码
#[test]
fn test_one_pair_beats_high_card() {
    test(&["4S 5H 6C 8D KH", "2S 4H 6S 4D JH"], &["2S 4H 6S 4D JH"])
}

一对牌胜过高牌。

rust 复制代码
#[test]
fn test_highest_pair_wins() {
    test(&["4S 2H 6S 2D JH", "2S 4H 6C 4D JD"], &["2S 4H 6C 4D JD"])
}

比较对子的点数,高对子获胜。

rust 复制代码
#[test]
fn test_two_pairs_beats_one_pair() {
    test(&["2S 8H 6S 8D JH", "4S 5H 4C 8C 5C"], &["4S 5H 4C 8C 5C"])
}

两对胜过一对。

rust 复制代码
#[test]
fn test_two_pair_ranks() {
    // both hands have two pairs, highest ranked pair wins
    test(&["2S 8H 2D 8D 3H", "4S 5H 4C 8S 5D"], &["2S 8H 2D 8D 3H"])
}

两对牌比较时,首先比较最高对子。

rust 复制代码
#[test]
fn test_two_pairs_second_pair_cascade() {
    // both hands have two pairs, with the same highest ranked pair,
    // tie goes to low pair
    test(&["2S QS 2C QD JH", "JD QH JS 8D QC"], &["JD QH JS 8D QC"])
}

最高对子相同时,比较次高对子。

rust 复制代码
#[test]
fn test_two_pairs_last_card_cascade() {
    // both hands have two identically ranked pairs,
    // tie goes to remaining card (kicker)
    test(&["JD QH JS 8D QC", "JS QS JC 2D QD"], &["JD QH JS 8D QC"])
}

两对完全相同时,比较剩余的牌(kicker)。

rust 复制代码
#[test]
fn test_three_of_a_kind_beats_two_pair() {
    test(&["2S 8H 2H 8D JH", "4S 5H 4C 8S 4H"], &["4S 5H 4C 8S 4H"])
}

三条胜过两对。

rust 复制代码
#[test]
fn test_three_of_a_kind_ranks() {
    //both hands have three of a kind, tie goes to highest ranked triplet
    test(&["2S 2H 2C 8D JH", "4S AH AS 8C AD"], &["4S AH AS 8C AD"])
}

三条比较时,点数高的三条获胜。

rust 复制代码
#[test]
fn test_three_of_a_kind_cascade_ranks() {
    // with multiple decks, two players can have same three of a kind,
    // ties go to highest remaining cards
    test(&["4S AH AS 7C AD", "4S AH AS 8C AD"], &["4S AH AS 8C AD"])
}

三条相同时,比较剩余牌的点数。

rust 复制代码
#[test]
fn test_straight_beats_three_of_a_kind() {
    test(&["4S 5H 4C 8D 4H", "3S 4D 2S 6D 5C"], &["3S 4D 2S 6D 5C"])
}

顺子胜过三条。

rust 复制代码
#[test]
fn test_aces_can_end_a_straight_high() {
    // aces can end a straight (10 J Q K A)
    test(&["4S 5H 4C 8D 4H", "10D JH QS KD AC"], &["10D JH QS KD AC"])
}

A可以作为顺子的最高牌(10 J Q K A)。

rust 复制代码
#[test]
fn test_aces_can_end_a_straight_low() {
    // aces can start a straight (A 2 3 4 5)
    test(&["4S 5H 4C 8D 4H", "4D AH 3S 2D 5C"], &["4D AH 3S 2D 5C"])
}

A可以作为顺子的最低牌(A 2 3 4 5)。

rust 复制代码
#[test]
fn test_straight_cascade() {
    // both hands with a straight, tie goes to highest ranked card
    test(&["4S 6C 7S 8D 5H", "5S 7H 8S 9D 6H"], &["5S 7H 8S 9D 6H"])
}

顺子比较时,点数高的顺子获胜。

rust 复制代码
#[test]
fn test_straight_scoring() {
    // even though an ace is usually high, a 5-high straight is the lowest-scoring straight
    test(&["2H 3C 4D 5D 6H", "4S AH 3S 2D 5H"], &["2H 3C 4D 5D 6H"])
}

尽管A通常作为高牌,但5-high顺子(A 2 3 4 5)是最低的顺子。

rust 复制代码
#[test]
fn test_flush_beats_a_straight() {
    test(&["4C 6H 7D 8D 5H", "2S 4S 5S 6S 7S"], &["2S 4S 5S 6S 7S"])
}

同花胜过顺子。

rust 复制代码
#[test]
fn test_flush_cascade() {
    // both hands have a flush, tie goes to high card, down to the last one if necessary
    test(&["4H 7H 8H 9H 6H", "2S 4S 5S 6S 7S"], &["4H 7H 8H 9H 6H"])
}

同花比较时,比较最高牌,然后依次比较。

rust 复制代码
#[test]
fn test_full_house_beats_a_flush() {
    test(&["3H 6H 7H 8H 5H", "4S 5C 4C 5D 4H"], &["4S 5C 4C 5D 4H"])
}

葫芦胜过同花。

rust 复制代码
#[test]
fn test_full_house_ranks() {
    // both hands have a full house, tie goes to highest-ranked triplet
    test(&["4H 4S 4D 9S 9D", "5H 5S 5D 8S 8D"], &["5H 5S 5D 8S 8D"])
}

葫芦比较时,三条点数高的获胜。

rust 复制代码
#[test]
fn test_full_house_cascade() {
    // with multiple decks, both hands have a full house with the same triplet, tie goes to the pair
    test(&["5H 5S 5D 9S 9D", "5H 5S 5D 8S 8D"], &["5H 5S 5D 9S 9D"])
}

三条相同时,比较对子点数。

rust 复制代码
#[test]
fn test_four_of_a_kind_beats_full_house() {
    test(&["4S 5H 4D 5D 4H", "3S 3H 2S 3D 3C"], &["3S 3H 2S 3D 3C"])
}

四条胜过葫芦。

rust 复制代码
#[test]
fn test_four_of_a_kind_ranks() {
    // both hands have four of a kind, tie goes to high quad
    test(&["2S 2H 2C 8D 2D", "4S 5H 5S 5D 5C"], &["4S 5H 5S 5D 5C"])
}

四条比较时,点数高的四条获胜。

rust 复制代码
#[test]
fn test_four_of_a_kind_cascade() {
    // with multiple decks, both hands with identical four of a kind, tie determined by kicker
    test(&["3S 3H 2S 3D 3C", "3S 3H 4S 3D 3C"], &["3S 3H 4S 3D 3C"])
}

四条相同时,比较剩余牌(kicker)。

rust 复制代码
#[test]
fn test_straight_flush_beats_four_of_a_kind() {
    test(&["4S 5H 5S 5D 5C", "7S 8S 9S 6S 10S"], &["7S 8S 9S 6S 10S"])
}

同花顺胜过四条。

rust 复制代码
#[test]
fn test_straight_flush_ranks() {
    // both hands have straight flush, tie goes to highest-ranked card
    test(&["4H 6H 7H 8H 5H", "5S 7S 8S 9S 6S"], &["5S 7S 8S 9S 6S"])
}

同花顺比较时,点数高的获胜。

性能优化版本

考虑性能的优化实现:

rust 复制代码
use std::cmp::Ordering;
use std::collections::HashMap;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    if hands.is_empty() {
        return vec![];
    }
    
    // 预分配结果向量以避免多次重新分配
    let mut parsed_hands: Vec<(Hand, &str)> = Vec::with_capacity(hands.len());
    
    // 将字符串手牌转换为Hand结构体
    for &hand_str in hands {
        parsed_hands.push((Hand::from_str(hand_str), hand_str));
    }
    
    // 按照牌力排序(降序)
    parsed_hands.sort_unstable_by(|a, b| b.0.cmp(&a.0));
    
    // 找到所有获胜的手牌(与最高牌力相同的手牌)
    let winning_hand = &parsed_hands[0].0;
    let mut winners = Vec::with_capacity(parsed_hands.len());
    
    for (hand, hand_str) in parsed_hands {
        if hand.cmp(winning_hand) == Ordering::Equal {
            winners.push(hand_str);
        } else {
            break; // 由于已排序,后续手牌都不可能是获胜者
        }
    }
    
    winners
}

// 使用数组代替HashMap以提高性能
#[derive(Debug, Clone, PartialEq, Eq)]
struct Card {
    rank: Rank,
    suit: Suit,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

impl Rank {
    fn from_char(c: char) -> Option<Rank> {
        match c {
            '2' => Some(Rank::Two),
            '3' => Some(Rank::Three),
            '4' => Some(Rank::Four),
            '5' => Some(Rank::Five),
            '6' => Some(Rank::Six),
            '7' => Some(Rank::Seven),
            '8' => Some(Rank::Eight),
            '9' => Some(Rank::Nine),
            'T' | '0' => Some(Rank::Ten),
            'J' => Some(Rank::Jack),
            'Q' => Some(Rank::Queen),
            'K' => Some(Rank::King),
            'A' => Some(Rank::Ace),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
enum Suit {
    Clubs = 0,
    Diamonds = 1,
    Hearts = 2,
    Spades = 3,
}

impl Suit {
    fn from_char(c: char) -> Option<Suit> {
        match c {
            'C' => Some(Suit::Clubs),
            'D' => Some(Suit::Diamonds),
            'H' => Some(Suit::Hearts),
            'S' => Some(Suit::Spades),
            _ => None,
        }
    }
}

impl Card {
    fn from_str(s: &str) -> Card {
        let chars: Vec<char> = s.chars().collect();
        
        if chars.is_empty() {
            panic!("Invalid card string: {}", s);
        }
        
        let (rank_char, suit_char) = if chars.len() >= 3 && chars[0] == '1' && chars[1] == '0' {
            // 处理"10"的情况
            if chars.len() >= 3 {
                ('0', chars[2])
            } else {
                panic!("Invalid card string: {}", s);
            }
        } else if chars.len() >= 2 {
            (chars[0], chars[chars.len() - 1])
        } else {
            panic!("Invalid card string: {}", s);
        };
        
        let rank = Rank::from_char(rank_char)
            .unwrap_or_else(|| panic!("Invalid rank in card string: {}", s));
        let suit = Suit::from_char(suit_char)
            .unwrap_or_else(|| panic!("Invalid suit in card string: {}", s));
        
        Card { rank, suit }
    }
}

#[derive(Debug, Clone)]
struct Hand {
    cards: [Card; 5],
    hand_type: HandType,
    rank_counts: [u8; 15], // 索引0未使用,索引1未使用,索引2-14对应Rank::Two-Rank::Ace
    sorted_ranks: [Rank; 5],
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum HandType {
    HighCard = 0,
    OnePair = 1,
    TwoPair = 2,
    ThreeOfAKind = 3,
    Straight = 4,
    Flush = 5,
    FullHouse = 6,
    FourOfAKind = 7,
    StraightFlush = 8,
}

impl HandType {
    fn rank(&self) -> u8 {
        *self as u8
    }
}

impl Hand {
    fn from_str(hand_str: &str) -> Hand {
        let card_strs: Vec<&str> = hand_str.split_whitespace().collect();
        
        if card_strs.len() != 5 {
            panic!("Invalid hand: must contain exactly 5 cards");
        }
        
        let cards: [Card; 5] = [
            Card::from_str(card_strs[0]),
            Card::from_str(card_strs[1]),
            Card::from_str(card_strs[2]),
            Card::from_str(card_strs[3]),
            Card::from_str(card_strs[4]),
        ];
        
        let mut rank_counts = [0u8; 15];
        for card in &cards {
            rank_counts[card.rank as usize] += 1;
        }
        
        let hand_type = Self::determine_hand_type(&cards, &rank_counts);
        
        let mut sorted_ranks: [Rank; 5] = [
            cards[0].rank,
            cards[1].rank,
            cards[2].rank,
            cards[3].rank,
            cards[4].rank,
        ];
        sorted_ranks.sort_by(|a, b| b.cmp(a)); // 降序排列
        
        Hand {
            cards,
            hand_type,
            rank_counts,
            sorted_ranks,
        }
    }
    
    fn determine_hand_type(cards: &[Card; 5], rank_counts: &[u8; 15]) -> HandType {
        let is_flush = cards.iter().all(|card| card.suit == cards[0].suit);
        
        let mut ranks: [Rank; 5] = [
            cards[0].rank,
            cards[1].rank,
            cards[2].rank,
            cards[3].rank,
            cards[4].rank,
        ];
        ranks.sort();
        
        let is_straight = Self::is_straight(&ranks);
        
        // 特殊情况:A,2,3,4,5 是顺子
        let is_low_straight = ranks == [Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Ace];
        
        if is_flush && (is_straight || is_low_straight) {
            return HandType::StraightFlush;
        }
        
        // 统计不同点数的牌的数量
        let mut count_counts = [0u8; 5]; // 索引表示相同点数的牌的数量,值表示有几种这样的牌
        for &count in rank_counts.iter() {
            if count > 0 {
                count_counts[count as usize] += 1;
            }
        }
        
        if count_counts[4] == 1 {
            HandType::FourOfAKind
        } else if count_counts[3] == 1 && count_counts[2] == 1 {
            HandType::FullHouse
        } else if is_flush {
            HandType::Flush
        } else if is_straight || is_low_straight {
            HandType::Straight
        } else if count_counts[3] == 1 {
            HandType::ThreeOfAKind
        } else if count_counts[2] == 2 {
            HandType::TwoPair
        } else if count_counts[2] == 1 {
            HandType::OnePair
        } else {
            HandType::HighCard
        }
    }
    
    fn is_straight(ranks: &[Rank; 5]) -> bool {
        for i in 0..4 {
            if (ranks[i + 1] as u8) != (ranks[i] as u8) + 1 {
                return false;
            }
        }
        true
    }
}

impl PartialEq for Hand {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for Hand {}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        // 首先比较牌型
        match self.hand_type.rank().cmp(&other.hand_type.rank()) {
            Ordering::Equal => {
                // 牌型相同时,比较具体的牌力
                self.compare_same_type(other)
            }
            other => other,
        }
    }
}

impl Hand {
    fn compare_same_type(&self, other: &Self) -> Ordering {
        match self.hand_type {
            HandType::HighCard | HandType::Flush | HandType::Straight | HandType::StraightFlush => {
                // 比较最高牌,然后依次比较
                for i in 0..5 {
                    match self.sorted_ranks[i].cmp(&other.sorted_ranks[i]) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                Ordering::Equal
            }
            HandType::OnePair => {
                // 比较对子的点数
                let self_pair_rank = self.get_rank_by_count(2);
                let other_pair_rank = other.get_rank_by_count(2);
                
                match self_pair_rank.cmp(&other_pair_rank) {
                    Ordering::Equal => {
                        // 对子相同,比较剩余牌
                        self.compare_kickers(&[self_pair_rank], other, &[other_pair_rank])
                    }
                    other => other,
                }
            }
            HandType::TwoPair => {
                // 比较两对的点数(从高到低)
                let mut self_pairs: Vec<Rank> = self.get_ranks_by_count(2);
                let mut other_pairs: Vec<Rank> = other.get_ranks_by_count(2);
                self_pairs.sort_by(|a, b| b.cmp(a));
                other_pairs.sort_by(|a, b| b.cmp(a));
                
                for i in 0..2 {
                    match self_pairs[i].cmp(&other_pairs[i]) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                
                // 两对都相同,比较单牌
                self.compare_kickers(&self_pairs, other, &other_pairs)
            }
            HandType::ThreeOfAKind => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较剩余牌
                        self.compare_kickers(&[self_three_rank], other, &[other_three_rank])
                    }
                    other => other,
                }
            }
            HandType::FullHouse => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较对子
                        let self_pair_rank = self.get_rank_by_count(2);
                        let other_pair_rank = other.get_rank_by_count(2);
                        self_pair_rank.cmp(&other_pair_rank)
                    }
                    other => other,
                }
            }
            HandType::FourOfAKind => {
                // 比较四条的点数
                let self_four_rank = self.get_rank_by_count(4);
                let other_four_rank = other.get_rank_by_count(4);
                
                match self_four_rank.cmp(&other_four_rank) {
                    Ordering::Equal => {
                        // 四条相同,比较剩余牌
                        self.compare_kickers(&[self_four_rank], other, &[other_four_rank])
                    }
                    other => other,
                }
            }
        }
    }
    
    fn get_rank_by_count(&self, count: u8) -> Rank {
        for (rank_index, &rank_count) in self.rank_counts.iter().enumerate() {
            if rank_count == count {
                // 安全地将索引转换为Rank
                return unsafe { std::mem::transmute(rank_index as u8) };
            }
        }
        panic!("No rank with count {}", count);
    }
    
    fn get_ranks_by_count(&self, count: u8) -> Vec<Rank> {
        let mut ranks = Vec::new();
        for (rank_index, &rank_count) in self.rank_counts.iter().enumerate() {
            if rank_count == count {
                // 安全地将索引转换为Rank
                ranks.push(unsafe { std::mem::transmute(rank_index as u8) });
            }
        }
        ranks
    }
    
    fn compare_kickers(&self, exclude_ranks: &[Rank], other: &Self, other_exclude_ranks: &[Rank]) -> Ordering {
        let mut self_ranks = self.sorted_ranks;
        let mut other_ranks = other.sorted_ranks;
        
        // 移除需要排除的点数
        self_ranks.retain(|r| !exclude_ranks.contains(r));
        other_ranks.retain(|r| !other_exclude_ranks.contains(r));
        
        // 比较剩余牌
        for i in 0..self_ranks.len() {
            match self_ranks[i].cmp(&other_ranks[i]) {
                Ordering::Equal => continue,
                other => return other,
            }
        }
        
        Ordering::Equal
    }
}

错误处理和边界情况

考虑更多边界情况的实现:

rust 复制代码
use std::cmp::Ordering;
use std::collections::HashMap;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    // 处理空输入
    if hands.is_empty() {
        return vec![];
    }
    
    // 将字符串手牌转换为Hand结构体
    let mut parsed_hands: Vec<Result<(Hand, &str), String>> = hands
        .iter()
        .map(|&hand_str| {
            Hand::from_str(hand_str)
                .map(|hand| (hand, hand_str))
                .map_err(|e| format!("Invalid hand '{}': {}", hand_str, e))
        })
        .collect();
    
    // 检查是否有无效手牌
    if let Some(Err(error)) = parsed_hands.iter().find(|result| result.is_err()) {
        panic!("{}", error);
    }
    
    // 解包有效手牌
    let mut valid_hands: Vec<(Hand, &str)> = parsed_hands
        .into_iter()
        .map(|result| result.unwrap())
        .collect();
    
    // 按照牌力排序(降序)
    valid_hands.sort_unstable_by(|a, b| b.0.cmp(&a.0));
    
    // 找到所有获胜的手牌(与最高牌力相同的手牌)
    let winning_hand = &valid_hands[0].0;
    valid_hands
        .into_iter()
        .take_while(|(hand, _)| hand.cmp(winning_hand) == Ordering::Equal)
        .map(|(_, hand_str)| hand_str)
        .collect()
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Card {
    rank: Rank,
    suit: Suit,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

impl Rank {
    fn from_char(c: char) -> Result<Rank, String> {
        match c {
            '2' => Ok(Rank::Two),
            '3' => Ok(Rank::Three),
            '4' => Ok(Rank::Four),
            '5' => Ok(Rank::Five),
            '6' => Ok(Rank::Six),
            '7' => Ok(Rank::Seven),
            '8' => Ok(Rank::Eight),
            '9' => Ok(Rank::Nine),
            'T' | '0' => Ok(Rank::Ten),
            'J' => Ok(Rank::Jack),
            'Q' => Ok(Rank::Queen),
            'K' => Ok(Rank::King),
            'A' => Ok(Rank::Ace),
            _ => Err(format!("Invalid rank character: {}", c)),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

impl Suit {
    fn from_char(c: char) -> Result<Suit, String> {
        match c {
            'C' => Ok(Suit::Clubs),
            'D' => Ok(Suit::Diamonds),
            'H' => Ok(Suit::Hearts),
            'S' => Ok(Suit::Spades),
            _ => Err(format!("Invalid suit character: {}", c)),
        }
    }
}

impl Card {
    fn from_str(s: &str) -> Result<Card, String> {
        let chars: Vec<char> = s.chars().collect();
        
        if chars.is_empty() {
            return Err("Empty card string".to_string());
        }
        
        let (rank_char, suit_char) = if chars.len() >= 3 && chars[0] == '1' && chars[1] == '0' {
            // 处理"10"的情况
            if chars.len() >= 3 {
                ('0', chars[2])
            } else {
                return Err("Invalid card string for 10".to_string());
            }
        } else if chars.len() >= 2 {
            (chars[0], chars[chars.len() - 1])
        } else {
            return Err("Card string too short".to_string());
        };
        
        let rank = Rank::from_char(rank_char)?;
        let suit = Suit::from_char(suit_char)?;
        
        Ok(Card { rank, suit })
    }
}

#[derive(Debug, Clone)]
pub struct Hand {
    cards: Vec<Card>,
    hand_type: HandType,
    rank_counts: HashMap<Rank, usize>,
    sorted_ranks: Vec<Rank>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HandType {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl HandType {
    fn rank(&self) -> u8 {
        match self {
            HandType::HighCard => 0,
            HandType::OnePair => 1,
            HandType::TwoPair => 2,
            HandType::ThreeOfAKind => 3,
            HandType::Straight => 4,
            HandType::Flush => 5,
            HandType::FullHouse => 6,
            HandType::FourOfAKind => 7,
            HandType::StraightFlush => 8,
        }
    }
}

#[derive(Debug)]
pub enum PokerError {
    InvalidHand(String),
    InvalidCard(String),
}

impl std::fmt::Display for PokerError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            PokerError::InvalidHand(msg) => write!(f, "Invalid hand: {}", msg),
            PokerError::InvalidCard(msg) => write!(f, "Invalid card: {}", msg),
        }
    }
}

impl std::error::Error for PokerError {}

impl Hand {
    fn from_str(hand_str: &str) -> Result<Hand, PokerError> {
        let card_strs: Vec<&str> = hand_str.split_whitespace().collect();
        
        if card_strs.len() != 5 {
            return Err(PokerError::InvalidHand(
                "must contain exactly 5 cards".to_string(),
            ));
        }
        
        let mut cards = Vec::with_capacity(5);
        for card_str in card_strs {
            cards.push(Card::from_str(card_str).map_err(PokerError::InvalidCard)?);
        }
        
        let mut rank_counts = HashMap::new();
        for card in &cards {
            *rank_counts.entry(card.rank.clone()).or_insert(0) += 1;
        }
        
        let hand_type = Self::determine_hand_type(&cards, &rank_counts);
        
        let mut sorted_ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        sorted_ranks.sort_by(|a, b| b.cmp(a)); // 降序排列
        
        Ok(Hand {
            cards,
            hand_type,
            rank_counts,
            sorted_ranks,
        })
    }
    
    fn determine_hand_type(cards: &[Card], rank_counts: &HashMap<Rank, usize>) -> HandType {
        let is_flush = cards.iter().all(|card| card.suit == cards[0].suit);
        
        let mut ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        ranks.sort();
        
        let is_straight = Self::is_straight(&ranks);
        
        // 特殊情况:A,2,3,4,5 是顺子
        let is_low_straight = ranks == vec![Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Ace];
        
        if is_flush && (is_straight || is_low_straight) {
            return HandType::StraightFlush;
        }
        
        let counts: Vec<usize> = rank_counts.values().cloned().collect();
        let mut count_counts = HashMap::new();
        for &count in &counts {
            *count_counts.entry(count).or_insert(0) += 1;
        }
        
        if count_counts.get(&4).unwrap_or(&0) == &1 {
            HandType::FourOfAKind
        } else if count_counts.get(&3).unwrap_or(&0) == &1 && count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::FullHouse
        } else if is_flush {
            HandType::Flush
        } else if is_straight || is_low_straight {
            HandType::Straight
        } else if count_counts.get(&3).unwrap_or(&0) == &1 {
            HandType::ThreeOfAKind
        } else if count_counts.get(&2).unwrap_or(&0) == &2 {
            HandType::TwoPair
        } else if count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::OnePair
        } else {
            HandType::HighCard
        }
    }
    
    fn is_straight(ranks: &[Rank]) -> bool {
        if ranks.len() != 5 {
            return false;
        }
        
        for i in 0..4 {
            if (ranks[i + 1] as u8) != (ranks[i] as u8) + 1 {
                return false;
            }
        }
        
        true
    }
}

impl PartialEq for Hand {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for Hand {}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        // 首先比较牌型
        match self.hand_type.rank().cmp(&other.hand_type.rank()) {
            Ordering::Equal => {
                // 牌型相同时,比较具体的牌力
                self.compare_same_type(other)
            }
            other => other,
        }
    }
}

impl Hand {
    fn compare_same_type(&self, other: &Self) -> Ordering {
        match self.hand_type {
            HandType::HighCard | HandType::Flush | HandType::Straight | HandType::StraightFlush => {
                // 比较最高牌,然后依次比较
                for (self_rank, other_rank) in self.sorted_ranks.iter().zip(other.sorted_ranks.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                Ordering::Equal
            }
            HandType::OnePair => {
                // 比较对子的点数
                let self_pair_rank = self.get_rank_by_count(2);
                let other_pair_rank = other.get_rank_by_count(2);
                
                match self_pair_rank.cmp(&other_pair_rank) {
                    Ordering::Equal => {
                        // 对子相同,比较剩余牌
                        self.compare_kickers(&[self_pair_rank], other, &[other_pair_rank])
                    }
                    other => other,
                }
            }
            HandType::TwoPair => {
                // 比较两对的点数(从高到低)
                let mut self_pairs: Vec<Rank> = self.get_ranks_by_count(2);
                let mut other_pairs: Vec<Rank> = other.get_ranks_by_count(2);
                self_pairs.sort_by(|a, b| b.cmp(a));
                other_pairs.sort_by(|a, b| b.cmp(a));
                
                for (self_rank, other_rank) in self_pairs.iter().zip(other_pairs.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                
                // 两对都相同,比较单牌
                self.compare_kickers(&self_pairs, other, &other_pairs)
            }
            HandType::ThreeOfAKind => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较剩余牌
                        self.compare_kickers(&[self_three_rank], other, &[other_three_rank])
                    }
                    other => other,
                }
            }
            HandType::FullHouse => {
                // 比较三条的点数
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        // 三条相同,比较对子
                        let self_pair_rank = self.get_rank_by_count(2);
                        let other_pair_rank = other.get_rank_by_count(2);
                        self_pair_rank.cmp(&other_pair_rank)
                    }
                    other => other,
                }
            }
            HandType::FourOfAKind => {
                // 比较四条的点数
                let self_four_rank = self.get_rank_by_count(4);
                let other_four_rank = other.get_rank_by_count(4);
                
                match self_four_rank.cmp(&other_four_rank) {
                    Ordering::Equal => {
                        // 四条相同,比较剩余牌
                        self.compare_kickers(&[self_four_rank], other, &[other_four_rank])
                    }
                    other => other,
                }
            }
        }
    }
    
    fn get_rank_by_count(&self, count: usize) -> Rank {
        self.rank_counts
            .iter()
            .find(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .unwrap()
    }
    
    fn get_ranks_by_count(&self, count: usize) -> Vec<Rank> {
        self.rank_counts
            .iter()
            .filter(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .collect()
    }
    
    fn compare_kickers(&self, exclude_ranks: &[Rank], other: &Self, other_exclude_ranks: &[Rank]) -> Ordering {
        let mut self_ranks: Vec<Rank> = self.sorted_ranks.clone();
        let mut other_ranks: Vec<Rank> = other.sorted_ranks.clone();
        
        // 移除需要排除的点数
        self_ranks.retain(|r| !exclude_ranks.contains(r));
        other_ranks.retain(|r| !other_exclude_ranks.contains(r));
        
        // 比较剩余牌
        for (self_rank, other_rank) in self_ranks.iter().zip(other_ranks.iter()) {
            match self_rank.cmp(other_rank) {
                Ordering::Equal => continue,
                other => return other,
            }
        }
        
        Ordering::Equal
    }
}

扩展功能

基于基础实现,我们可以添加更多功能:

rust 复制代码
use std::cmp::Ordering;
use std::collections::HashMap;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    if hands.is_empty() {
        return vec![];
    }
    
    let mut parsed_hands: Vec<(Hand, &str)> = hands
        .iter()
        .map(|&hand_str| (Hand::from_str(hand_str), hand_str))
        .collect();
    
    parsed_hands.sort_unstable_by(|a, b| b.0.cmp(&a.0));
    
    let winning_hand = &parsed_hands[0].0;
    parsed_hands
        .into_iter()
        .take_while(|(hand, _)| hand.cmp(winning_hand) == Ordering::Equal)
        .map(|(_, hand_str)| hand_str)
        .collect()
}

pub struct PokerGame {
    hands: Vec<Hand>,
    original_strings: Vec<String>,
}

impl PokerGame {
    pub fn new() -> Self {
        PokerGame {
            hands: Vec::new(),
            original_strings: Vec::new(),
        }
    }
    
    pub fn add_hand(&mut self, hand_str: &str) -> Result<(), String> {
        let hand = Hand::from_str(hand_str)?;
        self.hands.push(hand);
        self.original_strings.push(hand_str.to_string());
        Ok(())
    }
    
    pub fn get_winning_hands(&self) -> Vec<&str> {
        if self.hands.is_empty() {
            return vec![];
        }
        
        let mut indices: Vec<usize> = (0..self.hands.len()).collect();
        indices.sort_by(|&a, &b| self.hands[b].cmp(&self.hands[a]));
        
        let winning_hand = &self.hands[indices[0]];
        indices
            .into_iter()
            .take_while(|&i| self.hands[i].cmp(winning_hand) == Ordering::Equal)
            .map(|i| self.original_strings[i].as_str())
            .collect()
    }
    
    pub fn get_hand_type(&self, index: usize) -> Option<&HandType> {
        self.hands.get(index).map(|hand| &hand.hand_type)
    }
    
    pub fn get_hand_ranking(&self, hand_str: &str) -> Option<usize> {
        let mut indices: Vec<usize> = (0..self.hands.len()).collect();
        indices.sort_by(|&a, &b| self.hands[b].cmp(&self.hands[a]));
        
        indices.iter().position(|&i| self.original_strings[i] == hand_str)
    }
    
    pub fn compare_hands(&self, index1: usize, index2: usize) -> Option<Ordering> {
        match (self.hands.get(index1), self.hands.get(index2)) {
            (Some(hand1), Some(hand2)) => Some(hand1.cmp(hand2)),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Card {
    rank: Rank,
    suit: Suit,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14,
}

impl Rank {
    fn from_char(c: char) -> Result<Rank, String> {
        match c {
            '2' => Ok(Rank::Two),
            '3' => Ok(Rank::Three),
            '4' => Ok(Rank::Four),
            '5' => Ok(Rank::Five),
            '6' => Ok(Rank::Six),
            '7' => Ok(Rank::Seven),
            '8' => Ok(Rank::Eight),
            '9' => Ok(Rank::Nine),
            'T' | '0' => Ok(Rank::Ten),
            'J' => Ok(Rank::Jack),
            'Q' => Ok(Rank::Queen),
            'K' => Ok(Rank::King),
            'A' => Ok(Rank::Ace),
            _ => Err(format!("Invalid rank character: {}", c)),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

impl Suit {
    fn from_char(c: char) -> Result<Suit, String> {
        match c {
            'C' => Ok(Suit::Clubs),
            'D' => Ok(Suit::Diamonds),
            'H' => Ok(Suit::Hearts),
            'S' => Ok(Suit::Spades),
            _ => Err(format!("Invalid suit character: {}", c)),
        }
    }
}

impl Card {
    fn from_str(s: &str) -> Result<Card, String> {
        let chars: Vec<char> = s.chars().collect();
        
        if chars.is_empty() {
            return Err("Empty card string".to_string());
        }
        
        let (rank_char, suit_char) = if chars.len() >= 3 && chars[0] == '1' && chars[1] == '0' {
            // 处理"10"的情况
            if chars.len() >= 3 {
                ('0', chars[2])
            } else {
                return Err("Invalid card string for 10".to_string());
            }
        } else if chars.len() >= 2 {
            (chars[0], chars[chars.len() - 1])
        } else {
            return Err("Card string too short".to_string());
        };
        
        let rank = Rank::from_char(rank_char)?;
        let suit = Suit::from_char(suit_char)?;
        
        Ok(Card { rank, suit })
    }
}

#[derive(Debug, Clone)]
pub struct Hand {
    cards: Vec<Card>,
    pub hand_type: HandType,
    rank_counts: HashMap<Rank, usize>,
    sorted_ranks: Vec<Rank>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HandType {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl HandType {
    pub fn name(&self) -> &'static str {
        match self {
            HandType::HighCard => "High Card",
            HandType::OnePair => "One Pair",
            HandType::TwoPair => "Two Pair",
            HandType::ThreeOfAKind => "Three of a Kind",
            HandType::Straight => "Straight",
            HandType::Flush => "Flush",
            HandType::FullHouse => "Full House",
            HandType::FourOfAKind => "Four of a Kind",
            HandType::StraightFlush => "Straight Flush",
        }
    }
    
    fn rank(&self) -> u8 {
        match self {
            HandType::HighCard => 0,
            HandType::OnePair => 1,
            HandType::TwoPair => 2,
            HandType::ThreeOfAKind => 3,
            HandType::Straight => 4,
            HandType::Flush => 5,
            HandType::FullHouse => 6,
            HandType::FourOfAKind => 7,
            HandType::StraightFlush => 8,
        }
    }
}

impl Hand {
    fn from_str(hand_str: &str) -> Result<Hand, String> {
        let card_strs: Vec<&str> = hand_str.split_whitespace().collect();
        
        if card_strs.len() != 5 {
            return Err("must contain exactly 5 cards".to_string());
        }
        
        let mut cards = Vec::with_capacity(5);
        for card_str in card_strs {
            cards.push(Card::from_str(card_str)?);
        }
        
        let mut rank_counts = HashMap::new();
        for card in &cards {
            *rank_counts.entry(card.rank.clone()).or_insert(0) += 1;
        }
        
        let hand_type = Self::determine_hand_type(&cards, &rank_counts);
        
        let mut sorted_ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        sorted_ranks.sort_by(|a, b| b.cmp(a)); // 降序排列
        
        Ok(Hand {
            cards,
            hand_type,
            rank_counts,
            sorted_ranks,
        })
    }
    
    fn determine_hand_type(cards: &[Card], rank_counts: &HashMap<Rank, usize>) -> HandType {
        let is_flush = cards.iter().all(|card| card.suit == cards[0].suit);
        
        let mut ranks: Vec<Rank> = cards.iter().map(|c| c.rank.clone()).collect();
        ranks.sort();
        
        let is_straight = Self::is_straight(&ranks);
        
        // 特殊情况:A,2,3,4,5 是顺子
        let is_low_straight = ranks == vec![Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Ace];
        
        if is_flush && (is_straight || is_low_straight) {
            return HandType::StraightFlush;
        }
        
        let counts: Vec<usize> = rank_counts.values().cloned().collect();
        let mut count_counts = HashMap::new();
        for &count in &counts {
            *count_counts.entry(count).or_insert(0) += 1;
        }
        
        if count_counts.get(&4).unwrap_or(&0) == &1 {
            HandType::FourOfAKind
        } else if count_counts.get(&3).unwrap_or(&0) == &1 && count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::FullHouse
        } else if is_flush {
            HandType::Flush
        } else if is_straight || is_low_straight {
            HandType::Straight
        } else if count_counts.get(&3).unwrap_or(&0) == &1 {
            HandType::ThreeOfAKind
        } else if count_counts.get(&2).unwrap_or(&0) == &2 {
            HandType::TwoPair
        } else if count_counts.get(&2).unwrap_or(&0) == &1 {
            HandType::OnePair
        } else {
            HandType::HighCard
        }
    }
    
    fn is_straight(ranks: &[Rank]) -> bool {
        if ranks.len() != 5 {
            return false;
        }
        
        for i in 0..4 {
            if (ranks[i + 1] as u8) != (ranks[i] as u8) + 1 {
                return false;
            }
        }
        
        true
    }
}

impl PartialEq for Hand {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl Eq for Hand {}

impl PartialOrd for Hand {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Hand {
    fn cmp(&self, other: &Self) -> Ordering {
        match self.hand_type.rank().cmp(&other.hand_type.rank()) {
            Ordering::Equal => {
                self.compare_same_type(other)
            }
            other => other,
        }
    }
}

impl Hand {
    fn compare_same_type(&self, other: &Self) -> Ordering {
        match self.hand_type {
            HandType::HighCard | HandType::Flush | HandType::Straight | HandType::StraightFlush => {
                for (self_rank, other_rank) in self.sorted_ranks.iter().zip(other.sorted_ranks.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                Ordering::Equal
            }
            HandType::OnePair => {
                let self_pair_rank = self.get_rank_by_count(2);
                let other_pair_rank = other.get_rank_by_count(2);
                
                match self_pair_rank.cmp(&other_pair_rank) {
                    Ordering::Equal => {
                        self.compare_kickers(&[self_pair_rank], other, &[other_pair_rank])
                    }
                    other => other,
                }
            }
            HandType::TwoPair => {
                let mut self_pairs: Vec<Rank> = self.get_ranks_by_count(2);
                let mut other_pairs: Vec<Rank> = other.get_ranks_by_count(2);
                self_pairs.sort_by(|a, b| b.cmp(a));
                other_pairs.sort_by(|a, b| b.cmp(a));
                
                for (self_rank, other_rank) in self_pairs.iter().zip(other_pairs.iter()) {
                    match self_rank.cmp(other_rank) {
                        Ordering::Equal => continue,
                        other => return other,
                    }
                }
                
                self.compare_kickers(&self_pairs, other, &other_pairs)
            }
            HandType::ThreeOfAKind => {
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        self.compare_kickers(&[self_three_rank], other, &[other_three_rank])
                    }
                    other => other,
                }
            }
            HandType::FullHouse => {
                let self_three_rank = self.get_rank_by_count(3);
                let other_three_rank = other.get_rank_by_count(3);
                
                match self_three_rank.cmp(&other_three_rank) {
                    Ordering::Equal => {
                        let self_pair_rank = self.get_rank_by_count(2);
                        let other_pair_rank = other.get_rank_by_count(2);
                        self_pair_rank.cmp(&other_pair_rank)
                    }
                    other => other,
                }
            }
            HandType::FourOfAKind => {
                let self_four_rank = self.get_rank_by_count(4);
                let other_four_rank = other.get_rank_by_count(4);
                
                match self_four_rank.cmp(&other_four_rank) {
                    Ordering::Equal => {
                        self.compare_kickers(&[self_four_rank], other, &[other_four_rank])
                    }
                    other => other,
                }
            }
        }
    }
    
    fn get_rank_by_count(&self, count: usize) -> Rank {
        self.rank_counts
            .iter()
            .find(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .unwrap()
    }
    
    fn get_ranks_by_count(&self, count: usize) -> Vec<Rank> {
        self.rank_counts
            .iter()
            .filter(|(_, &c)| c == count)
            .map(|(rank, _)| rank.clone())
            .collect()
    }
    
    fn compare_kickers(&self, exclude_ranks: &[Rank], other: &Self, other_exclude_ranks: &[Rank]) -> Ordering {
        let mut self_ranks: Vec<Rank> = self.sorted_ranks.clone();
        let mut other_ranks: Vec<Rank> = other.sorted_ranks.clone();
        
        self_ranks.retain(|r| !exclude_ranks.contains(r));
        other_ranks.retain(|r| !other_exclude_ranks.contains(r));
        
        for (self_rank, other_rank) in self_ranks.iter().zip(other_ranks.iter()) {
            match self_rank.cmp(other_rank) {
                Ordering::Equal => continue,
                other => return other,
            }
        }
        
        Ordering::Equal
    }
}

// 便利函数
pub fn analyze_hand(hand_str: &str) -> Result<String, String> {
    let hand = Hand::from_str(hand_str)?;
    Ok(format!("Hand: {} - Type: {}", hand_str, hand.hand_type.name()))
}

pub fn compare_two_hands(hand1_str: &str, hand2_str: &str) -> Result<String, String> {
    let hand1 = Hand::from_str(hand1_str)?;
    let hand2 = Hand::from_str(hand2_str)?;
    
    match hand1.cmp(&hand2) {
        Ordering::Greater => Ok(format!("{} wins over {}", hand1_str, hand2_str)),
        Ordering::Less => Ok(format!("{} wins over {}", hand2_str, hand1_str)),
        Ordering::Equal => Ok(format!("{} ties with {}", hand1_str, hand2_str)),
    }
}

实际应用场景

扑克牌游戏在实际开发中有以下应用:

  1. 在线扑克平台:在线扑克游戏和锦标赛平台
  2. 手机游戏:移动端扑克游戏应用
  3. 社交应用:社交平台中的扑克游戏功能
  4. 教育软件:扑克规则教学和练习工具
  5. AI研究:扑克AI和游戏理论研究
  6. 赌场系统:数字赌场和博彩系统
  7. 数据分析:扑克策略分析和统计工具
  8. 娱乐应用:休闲娱乐类扑克应用

算法复杂度分析

  1. 时间复杂度

    • 单手牌分析:O(1)(固定5张牌)
    • 多手牌比较:O(n log n),其中n是手牌数量(主要是排序开销)
  2. 空间复杂度:O(n)

    • 其中n是手牌数量,需要存储所有手牌的解析结果

与其他实现方式的比较

rust 复制代码
// 使用第三方库的实现
// [dependencies]
// cardgame = "0.1"

pub fn winning_hands_with_library<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    // 使用第三方扑克牌库实现
    // 这里只是一个示例,实际实现会更复杂
    unimplemented!()
}

// 使用宏的实现
macro_rules! poker_hand {
    ($($card:tt),*) => {
        // 宏实现的扑克手牌
    };
}

// 使用trait的实现
pub trait PokerHand {
    fn hand_type(&self) -> HandType;
    fn compare(&self, other: &Self) -> Ordering;
}

// 函数式实现
pub fn winning_hands_functional<'a>(hands: &[&'a str]) -> Vec<&'a str> {
    hands
        .iter()
        .map(|&hand_str| (Hand::from_str(hand_str), hand_str))
        .collect::<Vec<_>>()
        .as_mut_slice()
        .sort_by(|a, b| b.0.cmp(&a.0));
    
    let winning_hand = &parsed_hands[0].0;
    hands
        .iter()
        .filter(|&&hand_str| Hand::from_str(hand_str).cmp(winning_hand) == Ordering::Equal)
        .copied()
        .collect()
}

总结

通过 poker 练习,我们学到了:

  1. 复杂规则实现:掌握了如何实现复杂的扑克牌规则和比较逻辑
  2. 枚举设计:学会了使用枚举表示复杂的分类和状态
  3. 模式匹配:深入理解了Rust中模式匹配的强大功能
  4. 排序算法:理解了自定义排序规则的实现方法
  5. 错误处理:学会了处理各种输入错误和边界情况
  6. 性能优化:了解了如何优化数据结构和算法以提高性能

这些技能在实际开发中非常有用,特别是在游戏开发、规则引擎、复杂业务逻辑处理等场景中。扑克牌游戏虽然是一个具体的应用问题,但它涉及到了枚举设计、模式匹配、排序算法、错误处理、性能优化等许多核心概念,是学习Rust高级编程的良好起点。

通过这个练习,我们也看到了Rust在实现复杂业务规则和处理复杂数据结构方面的强大能力,以及如何用安全且高效的方式实现复杂的比较逻辑。这种结合了安全性和性能的语言特性正是Rust的魅力所在。

相关推荐
晨非辰2 小时前
【数据结构初阶】--从排序算法原理分析到代码实现操作,参透插入排序的奥秘!
c语言·开发语言·数据结构·c++·算法·面试·排序算法
Jonathan Star2 小时前
Next.js、NestJS、Nuxt.js 是 **Node.js 生态中针对不同场景的框架**
开发语言·javascript·node.js
zhangyao9403305 小时前
关于js导入Excel时,Excel的(年/月/日)日期是五位数字的问题。以及对Excel日期存在的错误的分析和处理。
开发语言·javascript·excel
骑驴看星星a5 小时前
【Three.js--manual script】4.光照
android·开发语言·javascript
2301_795167206 小时前
玩转Rust高级应用 如何避免对空指针做“解引用”操作,在C/C++ 里面就是未定义行为
c语言·c++·rust
星释6 小时前
Rust 练习册 :Leap与日期计算
开发语言·后端·rust
悟能不能悟8 小时前
java的java.sql.Date和java.util.Date的区别,应该怎么使用
java·开发语言
循环过三天8 小时前
3.4、Python-集合
开发语言·笔记·python·学习·算法
_院长大人_10 小时前
设计模式-工厂模式
java·开发语言·设计模式