【问题标题】:Recognizing poker hands from a 2D matrix of values从二维值矩阵中识别扑克手
【发布时间】:2019-09-29 23:15:10
【问题描述】:

我有一个 1000 x 5 的排序矩阵,其数字为 1-13。每个数字表示扑克牌的数值。 Ace 的值为 1,然后是数字 2 到 10,然后是 Jack 的值为 11,Queen 的值为 12,King 的值为 13。因此,该矩阵的每一行构成一手牌。我正在尝试创建一个程序,使用以这种方式枚举的这些牌来识别扑克手。

例如:

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

因此,在这个矩阵A 中,第一行有一对 (1,1)。第二行有高牌 (7),第三行有两对 ((3,3) 和 (5,5)),最后一个是满屋 (9s 对子和同类 3 (8)。

在 MATLAB 中有没有好的方法来做到这一点?

【问题讨论】:

  • 欧拉计划练习?
  • bsxfun 对此不起作用。
  • 现在我们知道你想要什么,知道你做了什么会很有趣。
  • 你不是需要全部 52 张牌来做同花之类的事情吗?

标签: matlab matrix


【解决方案1】:

bsxfun 不适用于这种情况。这是一个计数问题。这完全是计算你拥有什么的问题。具体来说,扑克牌涉及计算您拥有的每张牌的数量,并找出正确的计数组合以获得有效手牌。这是一张漂亮的图片,向我们展示了人类已知的所有可能的扑克牌:

来源:http://www.bestonlinecasino.tips

因为我们的矩阵中没有花色,所以我将忽略皇家同花顺、同花顺和同花顺场景。您想识别的每只手都可以归结为使用从 1 到 13 的箱的每一行的直方图,并确定是否(按排名顺序):

  • 情况 #1:高手 - 所有 bin 的 bin 计数正好为 1
  • 情况 #2:一对 - 您正好有 1 个计数为 2 的箱子
  • 情况 #3:两对 - 您正好有 2 个计数为 2 的箱子
  • 情况 #4:三种类型 - 您恰好有 1 个计数为 3 的箱子
  • 情况 #5:直线 - 您无需在此处计算直方图。只需对您的手进行排序,并取相邻的差异,并确保连续值之间的差异为 1。
  • 情况 #6:满屋 - 您正好有 1 个计数为 2 的箱子并且您正好有 1 个计数为 3 的箱子。
  • 情况 #7:四种类型 - 您恰好有 1 个计数为 4 的箱子。

因此,根据您的 MATLAB 版本,使用 histchistcounts 找到您手的直方图。我还会在每一行上预先对你的手进行排序,以便在找到顺子时让事情变得更简单。您在帖子中提到矩阵是预先排序的,但我将假设它可能未排序的一般情况。

因此,这里有一些预处理代码,假设您的矩阵位于A

Asort = sort(A,2); %// Sort rowwise
diffSort = diff(Asort, 1, 2); %// Take row-wise differences
counts = histc(Asort, 1:13, 2); %// Count each row up

diffSort 包含每行的列差异,counts 为您提供N x 13 矩阵,其中N 是您正在考虑的手牌总数......所以在您的情况下,这是 1000。对于每一行,它会告诉您遇到了多少张特定卡片。所以你现在要做的就是经历每一种情况,看看你有什么。

让我们创建一个 ID 数组,它是一个与您的手数相同大小的向量,ID 告诉您我们玩过哪一手牌。具体来说:

* ID = 1 --> High Hand
* ID = 2 --> One Pair
* ID = 3 --> Two Pairs
* ID = 4 --> Three of a Kind
* ID = 5 --> Straight
* ID = 6 --> Full House
* ID = 7 --> Four of a Kind

因此,您需要执行以下操作来检查每种情况,并分配 out 以包含我们的 ID:

%// To store IDs
out = zeros(size(A,1),1);

%// Variables for later
counts1 = sum(counts == 1, 2);
counts2 = sum(counts == 2, 2);
counts3 = sum(counts == 3, 2);
counts4 = sum(counts == 4, 2);

%// Situation 1 - High Hand
check = counts1 == 5;
out(check) = 1;

%// Situation 2 - One Pair
check = counts2 == 1;
out(check) = 2;

%// Situation 3 - Two Pair
check = counts2 == 2;
out(check) = 3;

%// Situation 4 - Three of a Kind
check = counts3 == 1;
out(check) = 4;

%// Situation 5 - Straight
check = all(diffSort == 1, 2);
out(check) = 5;

%// Situation 6 - Full House
check = counts2 == 1 & counts3 == 1;
out(check) = 6;

%// Situation 7 - Four of a Kind
check = counts4 == 1;
out(check) = 7; 

情况 #1 基本上检查是否所有遇到的垃圾箱都只包含 1 张卡片。如果我们检查所有只有 1 个计数的箱子并将它们加在一起,我们应该得到 5 张卡片。

情况 #2 检查我们是否只有 1 个有 2 张卡片的箱子,并且只有 一个这样的箱子

情况 #3 检查我们是否有 2 个包含 2 张卡片的箱子。

情况 #4 检查我们是否只有 1 个包含 3 张卡片的箱子。

Situation #5 检查排序结果的每一行的相邻差值是否都等于 1。这意味着在查找相邻距离时,整行由 1 组成。如果是这种情况,那么我们就有顺子。我们使用all 并独立检查每一行以查看是否所有值都等于1。

情况 #6 检查我们是否有一个包含 2 张卡片的垃圾箱一个包含 3 张卡片的垃圾箱。

最后,情况 #7 检查我们是否有 1 个包含 4 张卡片的箱。


有几点需要注意:

  • 根据我们的定义,顺子在技术上也是强牌,但由于顺子过牌发生在管道的后期,任何最初被分配为强手的牌都被分配为顺子......所以这就是对我们来说没问题。

  • 此外,满屋也可以是一类三,因为我们只考虑满屋包含的一类三。但是,后面的满堂检查也将包括检查一对牌,因此任何分配到三张的牌最终都会成为满堂。


我还要注意的另一件事是,如果您的手牌无效,它将自动被分配一个值 0。


通过你的例子,这就是我得到的:

>> out

out =

     2
     1
     3
     6

这表示第一手是一对,下一手是高牌,下一对是两对,最后一手是满屋。作为奖励,我们实际上可以输出每手牌的字符串:

str = {'Invalid Hand', 'High Card', 'One Pair', 'Two Pair', 'Three of a Kind', 'Straight', 'Full House', 'Four of a Kind'};
hands = str(out+1);

我为无效的手做了一个占位符,如果我们的向量中有合法的手,您只需将每个索引加 1 即可访问右手。如果我们没有一手好牌,它会显示一个Invalid Hand 字符串。

我们得到这个字符串:

hands = 

    'One Pair'    'High Card'    'Two Pair'    'Full House'

【讨论】:

  • @Benoit_11 - 哈哈,我知道是吗?
  • 我知道不鼓励这种类型的 cmets,但是 wow。非常好的答案伙计。
  • @jucestain - 非常感谢 :)。我通常也会留下 cmets 以获得非常好的答案,而且您的许多图像处理帖子都非常值得赞叹!
  • 只有我一个人还是很有趣,这已经快 2 岁了,没有人注意到图像中的“一对”示例描绘了两个梅花 A。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 1970-01-01
相关资源
最近更新 更多