从一组纸牌中挑选Winner纸牌

在纸牌游戏中,一手包含五张牌并且每一手都有自己的排序,从低到高排序:

此处省略描述,请参考以下链接

[Python版本-纸牌游戏]](https://www.cnblogs.com/metaquant/p/11846933.html)

参考上述文章中的Python实现,用Rust实现此版本。
代码运行

use std::{collections::HashMap, collections::HashSet};
use core::hash::Hash;
use std::cmp::Ordering;
use std::cmp::Ordering::{Less, Greater, Equal};//牌面字母映射为数字,便于比较
const ARRAY_CHAR_CARD_NUM: [(&str, u8);5]  = [("T", 10),("J", 11),("Q", 12),("K", 13),("A", 14),
];//将card数字转为原字符
fn transer_card_num_char(num: u8) -> String {match ARRAY_CHAR_CARD_NUM.iter().find(|item| item.1 == num) {Some(str) => str.0.to_string(),None => num.to_string(),}
}
//将card字符(T J A...)转为数字,便于比较
fn tranfer_card_num(card_value: &str) -> u8 {let card_char_num_map = HashMap::from(ARRAY_CHAR_CARD_NUM);if card_char_num_map.contains_key(card_value) {card_char_num_map.get(card_value).unwrap().to_owned() as u8}else{card_value.parse().unwrap()}
}#[derive(Debug)]
struct Card {value: u8,color: char,}
#[derive(Debug)]
struct Hand {values: Vec<u8>,raw_values: Vec<u8>,colors: Vec<char>,value_counter: Vec<(u8,u8)>,color_kind: usize,first_count: u8,second_count: u8,diff: HashSet<u8>
}impl Card {fn new(value: u8, color: char) -> Self {Self { value: value, color: color }}
}impl From<&str> for Card {fn from(str: &str) -> Self {let value = tranfer_card_num(str.get(..(str.len() - 1)).unwrap());let color = str.get((str.len() - 1)..).unwrap();Card::new(value, color.chars().next().unwrap())}
}impl From<&str> for Hand {fn from(item: &str) -> Self {let hand_vec = item.split(' ').collect::<Vec<_>>();let card_vec = hand_vec.iter().map(|&item| item.into()).collect::<Vec<Card>>();let values = card_vec.iter().map(|item| item.value).collect::<Vec<u8>>();let colors = card_vec.iter().map(|item| item.color).collect::<Vec<char>>();let hand = Hand::new(values, colors);hand}
}
impl PartialEq for Hand{fn eq(&self, other: &Self) -> bool {self.categories() == other.categories() && self.values == other.values}}
impl PartialOrd for Hand{fn partial_cmp(&self, other: &Self) -> Option<Ordering> {if self.eq(&other) {Some(Equal)}else if &self.categories().1 > &other.categories().1 {Some(Greater)}else if &self.categories().1 < &other.categories().1  {Some(Less)}else if [8,7,4,3,2].contains(&self.categories().1){if &self.value_counter > &other.value_counter {Some(Greater)}else {Some(Less)}}else {if &self.values > &other.values {Some(Greater)}else{Some(Less)}}}
}
impl From<&Hand> for String {fn from(_hand: &Hand) -> Self {let mut vec = Vec::new();for i in (0.._hand.colors.len())  {let color1 = _hand.colors[i].to_string();let num1 = transer_card_num_char(_hand.raw_values[i]);let c = num1 + color1.as_ref();vec.push(c);}let hand_string = vec.join(" ");hand_string}
}
impl Hand {fn new(values: Vec<u8>, colors: Vec<char>) -> Self {let set = colors.iter().map(|item| *item).collect::<HashSet<char>>();let counter = Counter::new(&values);let most = counter.most_common();let first_count = most.get(0).unwrap().1;let second_count = most.get(1).unwrap().1;let mut values_sort = values.clone();values_sort.sort_by(|a, b| b.cmp(a));let diff = values_sort.windows(2).map(|item| item[0] - item[1]).collect::<HashSet<u8>>();Self { raw_values:values, values: values_sort, colors: colors, value_counter: most[..].to_vec(), color_kind: set.len(), first_count, second_count, diff}}fn categories(&self) -> (&str, u8) {if self.color_kind.eq(&1) && (self.diff.len() == 1 && self.diff.contains(&1)){("Straight Flush",9)}else if self.color_kind == 1{("Flush",6)}else if (self.diff.len() == 1 && self.diff.contains(&1)){("Straight",5)}else if self.first_count == 4{("Four of a Kind",8)}else if self.first_count == 3 && self.second_count == 2 {("Full House",7)}else if self.first_count == 3 && self.second_count == 1 {("Three of a Kind",4)}else if self.first_count == 2 && self.second_count == 2 {("Two Pairs",3)}else if self.value_counter.len() == 4 && self.first_count == 2 {("One Pair",2)}else {("High Card",1)}}
}// 类比Python Counter数据结构
struct Counter<T>{map: HashMap<T,u8>
}
impl<T> Counter<T>  where T:Hash + Eq + Copy {fn new(vec: &[T]) -> Self{let mut map = HashMap::new();for one in vec  {if let Some(x) = map.get_mut(one){*x = *x + 1;}else{map.insert(*one, 1 as u8);}}Self { map: map }}fn most_common(self) -> Vec<(T,u8)>{let map = self.map;let mut result:Vec<(T,u8)> = Vec::new();let mut value_vec:Vec<u8> = map.iter().map(|(key, val)| *val).collect::<HashSet<u8>>().iter().map(|val| *val).collect();value_vec.sort_by(|a, b| b.cmp(a));// let mut i = 0 ;for item in value_vec  {let mut f = map.iter().map(|(key,value)| (key.to_owned(), *value)).filter(|(key, value)| (value).eq(&item)).collect::<Vec<(T,u8)>>();result.append(&mut f);}result}}//两手牌比较
fn tow_hand_cmp(){let _hand1: Hand = "5D 5S 5S 8D 8C".into();let _hand2: Hand = "2S 3C 4S 5H 6H".into();let c = _hand1.partial_cmp(&_hand2);println!("{:?}", c);
}
//挑选出打牌,可能是多个
fn pickup_winner<'a>(hands: &[&'a str]) -> Vec<String> {let mut hand_vec = hands.iter().map(|item| item.to_owned().into()).collect::<Vec<Hand>>();hand_vec.sort_by(|a,b| b.partial_cmp(a).unwrap());let winners: Vec<&Hand> = hand_vec.iter().filter(|item| item.to_owned().partial_cmp(&(hand_vec[0])).eq(&Some(Equal))).collect();let vec_str = winners.iter().map(|&item| item.into()).collect::<Vec<String>>();println!("{:?}", vec_str);vec_str
}
fn main() {let card_str_vec = [ "3H 4H 5D 6H JH", "4D 5S 5S 8D 3C", "4D 5S 8D 3C 5S","2S 4C JS JH 10H"];pickup_winner(&card_str_vec);//tow_hand_cmp()
}

刚开始写Rust,对于一些方法的作用不太熟悉,导致没有实现的代码比较麻烦,没有实现方法的最优组合。
请参考下一个实现。

use std::cmp::Reverse;
use std::collections::{BinaryHeap, HashMap};pub fn winning_hands<'a>(hands: &[&'a str]) -> Vec<&'a str> {let mut hands: BinaryHeap<_> = hands.iter().map(|&s| (PokerHand::parse(s), s)).collect();let (winning, s) = hands.pop().unwrap();let mut result = vec![s];while let Some((value, s)) = hands.pop() {if value < winning {break;}result.push(s);}result
}
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
struct PokerHand {counts: Vec<usize>,values: Vec<u8>,
}
fn parse_card(s: &str) -> (u8, u8) {let (value, suit) = s.split_at(s.len() - 1);(match value.parse::<u8>() {Ok(v) => v,Err(_) => "JQKA".find(value).unwrap() as u8 + 11,},suit.as_bytes()[0],)
}
impl PokerHand {fn parse(s: &str) -> Self {let (values, suits): (Vec<u8>, Vec<u8>) = s.split_whitespace().map(parse_card).unzip();let mut groups = HashMap::<u8, usize>::new();for &v in values.iter() {*groups.entry(v).or_default() += 1;}let mut groups: Vec<_> = groups.into_iter().map(|(v, c)| (c, v)).collect();groups.sort_unstable_by_key(|&x| Reverse(x));let (mut counts, mut values): (Vec<_>, Vec<_>) = groups.iter().copied().unzip();if counts.len() == 5 {if values == [14, 5, 4, 3, 2] {values = vec![5, 4, 3, 2, 1];}let is_straight = values[0] - values[4] == 4;let is_flush = suits[1..].iter().all(|&x| x == suits[0]);match (is_straight, is_flush) {(true, true) => counts = vec![5],(true, false) => counts = vec![3, 1, 2],(false, true) => counts = vec![3, 1, 3],_ => {}}}Self { counts, values }}
}

花了一上午时间,对比了两种实现,越发感觉第一种很“原始”。

首先两种实现思路不同,第二种设想较为简单,直接构造通过排序可以解决问题的PokerHand,

第一种将规则中各类情况考虑较为清楚,分类比较。

将b方案的结构(对比a方案)列举如下:

9 => [5], 8 => [4,1] , 7 => [3,2] ,6 => [3,1,3] , 5 => [3,1,2], 4 => [3,1,1], 3 => [2,2,1], 2 => [2,1,1,1]

可见b方案在设计上就比较简洁。

具体差别:

  • 排序相关trait实现使用派生宏生成

  • Counter结构的实现麻烦

    fn new(vec: &[T]) -> Self{let mut map = HashMap::new();for one in vec  {if let Some(x) = map.get_mut(one){*x = *x + 1;}else{map.insert(*one, 1 as u8);}}Self { map: map }}
    //简单的如下
    fn new(vec: &[T]) -> Self{let mut map = HashMap::new();for one in vec  {*map.entry(*one).or_default() += 1;}Self { map: map }}
    
  • Counter结构,most_common的实现麻烦

fn most_common(self) -> Vec<(T,u8)>{let map = self.map;let mut result:Vec<(T,u8)> = Vec::new();let mut value_vec:Vec<u8> = map.iter().map(|(key, val)| *val).collect::<HashSet<u8>>().iter().map(|val| *val).collect();value_vec.sort_by(|a, b| b.cmp(a));// let mut i = 0 ;for item in value_vec  {let mut f = map.iter().map(|(key,value)| (key.to_owned(), *value)).filter(|(key, value)| (value).eq(&item)).collect::<Vec<(T,u8)>>();f.sort_by(|a, b| (b.0).partial_cmp(&a.0).unwrap());result.append(&mut f);}result}
//简单如下fn most_common(self) -> Vec<(T,u8)>{let map = self.map;let mut groups: Vec<_> = map.into_iter().map(|(v, c)| (c, v)).collect();groups.sort_unstable_by_key(|&x| Reverse(x));groups.into_iter().map(|(v, c)| (c, v)).collect()}
  • &str转为Card
let (value, suit) = s.split_at(s.len() - 1);(match value.parse::<u8>() {Ok(v) => v,Err(_) => "JQKA".find(value).unwrap() as u8 + 11,},suit.as_bytes()[0],)

学习语言,不变的是设计,差异的是一些数据结构,只要我们能够想象到它应该一种什么样子,然后一步一步寻找好的数据结构,构建代码流程,总能实现目标。好的坏的,差异是精巧带来的优雅!

Rust实现:从一组纸牌中挑选Winner纸牌相关推荐

  1. python取出一组数中的奇偶数

    最近学习python,思考了如何取出一组数中的奇数和偶数. 面临这个问题,首先是得对数组进行一个一个的搜素判断.其次,我们知道偶数与2取模之后必为0,故采用模为0的思想来做: 代码如下: #案列1-- ...

  2. matlab产生一组均为一的矩阵,在matlab中如何从一组数中得到随机数组成一个n*n的矩阵...

    导航:网站首页 > 在matlab中如何从一组数中得到随机数组成一个n*n的矩阵 时间:2019-3-15 在matlab中如何从一组数中得到随机数组成一个n*n的矩阵 从1,2,3,4,5,6 ...

  3. //假设有一个能装入总体积为T的背包和n件体积分别为w1,w2....wn.的物品,能否从n件物品中挑选若干件恰好装满背包,即使w1+w2+....+wn=T,要求找出所有满足上述条件的解。例如:当T

    //背包问题 //假设有一个能装入总体积为T的背包和n件体积分别为w1,w2....wn.的物品,能否从n件物品中挑选若干件恰好装满背包,即使w1+w2+....+wn=T,要求找出所有满足上述条件的 ...

  4. 15000个开源项目中挑选Top 12

    15000个开源项目中挑选Top 12,第一就是-- 2018-01-17 

  5. java求最大值_java-求一组整数中的最大值

    /** 作者:朱家磊 版本:Version1.8(java -version可以查出版本) 功能:求一组整数中的最大值 */ public class Demo { public static voi ...

  6. 软件测试作业2:在敏捷宣言遵循的12条原则中挑选1条你感兴趣的原则进行风险评估

    作业2 1.在敏捷宣言遵循的12条原则中挑选1条你感兴趣的原则进行风险评估. "原则"参见Lec 6, slide 8-11; "风险"参见Lec 3, sli ...

  7. python找色_python实现从一组颜色中找出与给定颜色最接近颜色的方法

    本文实例讲述了python实现从一组颜色中找出与给定颜色最接近颜色的方法.分享给大家供大家参考.具体分析如下: 这段代码非常有用,可以找到指定颜色相似的颜色,比如有一组8个颜色,现在给定一个rgb格式 ...

  8. python中特殊变量-python list每三个分成一组python中星号变量的几种特殊用法

    在Python中星号除了用于乘法数值运算和幂运算外,还有一种特殊的用法"在变量前添加单个星号或两个星号",实现多参数的传入或变量的拆解,本文将详细介绍"星号参数" ...

  9. C语言程序设计:编写函数,求一组数中大于平均值的数的个数

    题目内容: 编写函数,求一组整数中大于平均值的个数,数组元素个数任意.例如:给定的一组数为1,3,6,9,4,23,35,67,12,88时,函数值为3. 函数头定义:int aver(int a[] ...

最新文章

  1. Linux 下 进程运行时内部函数耗时的统计 工具:pstack,strace,perf trace,systemtap
  2. 小猿圈html5教程之canvas绘制线段方法
  3. CSS HACK 区别 IE6、IE7、IE8、Firefox兼容性
  4. JLBH示例1 –为什么应在上下文中对代码进行基准测试
  5. Delphi IDE扩展工具,在IDE中增加Google翻译器
  6. tomcat和java安装,JavaWeb-Tomcat下载和安装
  7. 酷狗笔试题:补齐左括号(栈)
  8. CCF201312--模拟练习试题参考答案(Java)
  9. mybatis if where标签怎么使用?
  10. ElasticSearch学习(四):可视化管理之Kibana
  11. mov格式怎么在线转换成mp4格式
  12. lpad与rpad函数
  13. 初创公司需要哪些部门_哪些初创公司在安全方面犯了错误
  14. Charles 访问 HTTPS 链接不是私密连接 (完美解决)
  15. java计算机毕业设计vue健康餐饮管理系统设计与实现MyBatis+系统+LW文档+源码+调试部署
  16. 经典:统计字符串中汉字,英文,数字,特殊符号个数
  17. 实用办公必学技巧:Excel打印标题设置方法
  18. 安装nvcc CUDNN
  19. webRTC服务器搭建(基于Janus)与Demo运行
  20. 犹太裔大陆籍华人的故事-值得一读

热门文章

  1. vs警告 当前源代码跟内置的版本不一致解决办法
  2. p73 应急响应-WEB 分析 phpjavaweb自动化工具
  3. 稍微挖掘一下思维导图XMind潜力以及那个使用XMind的你
  4. ASCII码对照表(转载)
  5. 槛外人观察 :语义和语用
  6. RabbitMQ消息监听(多种模式-fanout/topic)
  7. 三友硅业的化工厂人员定位系统——新导智能
  8. 虚拟偶像 “造星” 指南,二次元、超写实、智能驱动,你会粉上谁?
  9. Android蓝牙开发之一:打开、关闭蓝牙
  10. PPT忘记加密密码的处理方式