Mic*_*ael 22 java algorithm poker r data-structures
我在考虑扑克牌(5张牌)的评价Java.现在我正在寻求简单和清晰,而不是性能和效率.我可能会写一个"天真"的算法,但它需要大量的代码.
我还看到了一些扑克评估库,它们使用散列和按位操作,但它们看起来相当复杂.
什么是扑克手评估的"最干净,最简单"的算法?
dan*_*lmo 31
这是一个非常简短但完整的基于直方图的5卡扑克评分函数(2.x).如果转换为Java,它将会变得更长.
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
Run Code Online (Sandbox Code Playgroud)
小智 11
查找表是解决问题的最直接,最简单的解决方案,也是最快的解决方案.诀窍在于管理表的大小并保持使用模式足够简单以便快速处理(时空权衡).显然,从理论上讲,你可以只编码每个可以持有的手并进行一系列评估,然后--poof--一个表查找,你就完成了.不幸的是,这样的表对于大多数机器来说都是巨大的并且难以管理,并且无论如何都会让你颠倒磁盘,因为内存被换掉了.
所谓的两加二解决方案是一个大型的10M表,但字面上涉及一张桌面查找手中的每张卡.您不太可能找到更快速,更简单的算法.
其他解决方案涉及更多压缩表和更复杂的索引,但它们易于理解且速度非常快(尽管比2 + 2慢得多).在这里您可以看到有关散列的语言等等 - 将表格大小缩小到更易于管理的大小的技巧.
在任何情况下,查找解决方案都比直方图排序快几个数量级 - 跳过你头上的比较 - 特殊情况和逐个冲洗的解决方案,几乎没有其中值得一看.
你实际上不需要任何高级功能,它可以按位完成:(来源:http://www.codeproject.com/Articles/569271/A-Poker-hand-analyzer-in-JavaScript-using-bit-数学)
(这个实际上是用JavaScript编写的,但如果需要的话,你可以用Java来评估JavaScript,所以它不应该是一个问题.而且,这也是它的简短,所以即使是为了说明方法......) :
首先,您将卡分成两个阵列:排名(cs)和套装(ss)并代表套装,您将使用1,2,4或8(即0b0001,0b0010,...):
var J=11, Q=12, K=13, A=14, C=1, D=2, H=4, S=8;
Run Code Online (Sandbox Code Playgroud)
现在这里是魔术:
function evaluateHand(cs, ss) {
var pokerHands = ["4 of a Kind", "Straight Flush","Straight","Flush","High Card","1 Pair","2 Pair","Royal Flush", "3 of a Kind","Full House"];
var v,i,o,s = 1 << cs[0] | 1 << cs[1] | 1 << cs[2] | 1 << cs[3] | 1 << cs[4];
for (i = -1, v = o = 0; i < 5; i++, o = Math.pow(2, cs[i] * 4)) {v += o * ((v / o & 15) + 1);}
v = v % 15 - ((s / (s & -s) == 31) || (s == 0x403c) ? 3 : 1);
v -= (ss[0] == (ss[1] | ss[2] | ss[3] | ss[4])) * ((s == 0x7c00) ? -5 : 1);
return pokerHands[v];
}
Run Code Online (Sandbox Code Playgroud)
用法:
evaluateHand([A,10,J,K,Q],[C,C,C,C,C]); // Royal Flush
Run Code Online (Sandbox Code Playgroud)
现在它的作用(非常简单)就是当它存在2时将1放入s的第3位,而当存在3 时将其放入第4位等等,所以对于上面的例子,s看起来像这样:
0b111110000000000
对于[A,2,3,4,5],它看起来像这样
0b100 0000 0011 1100
等等
v使用四位来记录同一张卡的多个出现,所以它是52位长,如果你有三个A和两个国王,它的8个MSB位看起来像:
0111 0011 ...
最后一行然后检查刷新或同花顺或皇家同花顺(0x7c00).
public record Hand(Category category, Rank... ranks) implements Comparable<Hand> {
public static Hand evaluate(Set<Card> cards) {
if (cards.size() != 5) { throw new IllegalArgumentException(); }
var flush = cards.stream().map(Card::suit).distinct().count() == 1;
var counts = cards.stream().collect(groupingBy(Card::rank, counting()));
var ranks = counts.entrySet().stream().sorted(
comparing(Entry<Rank,Long>::getValue).thenComparing(Entry::getKey).reversed()
).map(Entry::getKey).toArray(Rank[]::new);
if (ranks.length == 4) {
return new Hand(PAIR, ranks);
} else if (ranks.length == 3) {
return new Hand(counts.get(ranks[0]) == 2 ? TWO_PAIR : TRIPS, ranks);
} else if (ranks.length == 2) {
return new Hand(counts.get(ranks[0]) == 3 ? FULL_HOUSE : QUADS, ranks);
} else if (ranks[0].ordinal() - ranks[4].ordinal() == 4) {
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, ranks[0]);
} else if (ranks[0] == ACE && ranks[1] == FIVE) { // wheel
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, FIVE);
} else {
return new Hand(flush ? FLUSH : HIGH_CARD, ranks);
}
}
@Override
public int compareTo(Hand that) { // compare categories, then ranks lexicographically
return comparing(Hand::category).thenComparing(Hand::ranks, Arrays::compare)
.compare(this, that);
}
}
Run Code Online (Sandbox Code Playgroud)
进口和其余类型:
import java.util.Arrays;
import java.util.Set;
import java.util.Map.Entry;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
record Card(Rank rank, Suit suit) {}
enum Rank {
TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
}
enum Suit {
DIAMONDS, CLUBS, HEARTS, SPADES
}
enum Category {
HIGH_CARD, PAIR, TWO_PAIR, TRIPS, STRAIGHT, FLUSH, FULL_HOUSE, QUADS, STRAIGHT_FLUSH
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
49785 次 |
| 最近记录: |