条件概率 扑克_建立没有条件分支的扑克手牌评估器

条件概率 扑克

Building a team of developers requires a way to measure the talent and skill of candidates. During the early stages of a company, building out a core senior team requires a way to weed out imposters versus impressors. Using a technical coding challenge is one path to accomplish this.

建立开发人员团队需要一种衡量候选人才能和技能的方法。 在公司的早期阶段,建立核心的高级团队需要一种方法来消除冒名顶替者和印象深刻者。 使用技术编码挑战是完成此任务的一种途径。

My go-to test involves one of my favorite pastimes, poker. To be specific, incorporating a poker hand evaluation mechanism. Without leading candidates to a particular implementation, the challenge is open-ended to allow them to showcase their foundational programming knowledge and experience level.

我的参加考试涉及我最喜欢的消遣之一,扑克。 具体来说,结合了扑克手评估机制。 如果没有带领候选人实现特定的实施方案,那么挑战就是无限的,以使他们能够展示自己的基础编程知识和经验水平。

I’ve witnessed the gamut of solutions, from elegant to terribly redundant copy/paste code spanning multiple hundreds of lines. Some were outright plagiarism without attribution to the original authors. But the common thread across these submissions always contained conditional branches that caused confusion or extraneous code.

我目睹了各种解决方案,从优雅的代码到跨越数百行的极其冗余的复制/粘贴代码。 有些是完全窃,没有注明原始作者。 但是,这些提交中的通用线程始终包含导致混乱或无关代码的条件分支。

A challenge to myself was to write an evaluator that did not use large lookup matrixes or any conditional branches, like if/else or switch blocks. Code with chained ternary operators is also discouraged.

我自己面临的一个挑战是编写一个不使用大型查找矩阵或任何条件分支(如if / elseswitch块)的评估程序。 不建议使用链式三元运算符进行编码。

Here is my journey into that challenge.

这是我应对挑战的旅程。

背景 (Background)

During my early years of programming, on the Timex Sinclair ZX-81, with extremely constrained resources, jumping into machine language was the ultimate in optimization of code. Using the bitwise operators to perform math was magical to me. The result of those bitwise operations or logical operators could be used as an inline decision tree, assigning the registers one value or another.

在我编写程序的最初几年中,在资源极为有限的Timex Sinclair ZX-81上,进入机器语言是代码优化的终极目标。 使用按位运算符执行数学运算对我来说是神奇的。 这些按位运算或逻辑运算符的结果可以用作内联决策树,为寄存器分配一个值或另一个值。

I continued onto the Commodore 64 and then the Apple II, coding in machine language on the 6502 chip. As computers grew more powerful and faster, with inexpensive memory and storage, programmers moved up to higher-level languages and started slacking off, being more verbose and sloppy with their code.

我继续使用Commodore 64,然后使用Apple II,在6502芯片上使用机器语言进行编码。 随着计算机功能越来越强大,速度越来越快,内存和存储空间越来越便宜,程序员开始使用高级语言并开始懈怠,他们的代码变得更加冗长和草率。

With every move to another computing platform, I held the mantra of using less code to perform the same operation. I tried to squeeze the most out of every line of code, sometimes to the detriment of readability through obfuscation.

每次迁移到另一个计算平台时,我都坚持使用更少的代码来执行相同的操作。 我试图从代码的每一行中挤出最多,有时会由于混淆而损害可读性。

In this exercise, I will be using logical operators throughout and will explain how the code does the work of multiple branching mechanisms. In addition to logical operators, using object maps helps with this effort. I prefer code that reads and operates top-down without creating deep branching trees.

在本练习中,我将在整个过程中使用逻辑运算符,并将说明代码如何完成多个分支机制的工作。 除逻辑运算符外,使用对象映射也有助于此工作。 我更喜欢从上到下读取和操作而不创建深分支树的代码。

Let’s get to work.

让我们开始工作。

规划 (Planning)

A small amount of planning is always required before pumping out code. I often return to the tried-and-true analog of graph paper and pencil to sketch out my thoughts quickly. You can never have too much graph paper; it’s the ultimate medium to draw out plans. I wanted to embed the evaluation of a poker hand into a binary-map matrix, with each value of the next card being a binary magnitude higher than the previous.

在抽出代码之前,总是需要进行少量计划。 我经常回到试纸和铅笔的久经考验的相似之处,以快速勾勒出我的想法。 您永远不会有太多的方格纸; 这是制定计划的最终媒介。 我想将扑克手的评估值嵌入到二进制地图矩阵中,下一张纸牌的每个值都比前一张纸牌高一个二进制值。

Using a binary-map representation results in unique values for every combination of cards when summed together. The winner is determined by the hand with the highest-ranked “score.”

使用二元映射表示法,将每个卡组合组合在一起时,得出唯一的值。 获胜者由“得分”最高的牌决定。

A: 8192
K: 4096
Q: 2048
J: 1024
T: 512
9: 256
8: 128
7: 64
6: 32
5: 16
4: 8
3: 4
2: 2
A: 1

Why is the Ace repeated? In a poker hand, the Ace is usually treated as the highest card value, but during a Low-Ace Straight, the Ace is the lowest value; therefore, it has dual positions on the map.

为什么重复王牌? 在扑克牌中,通常将A视为最高纸牌值,但在低A直牌中,A是最低纸牌值。 因此,它在地图上具有双重位置。

There are nine ranks in poker, with a Royal Flush the highest of a 9th ranked hand (we’ll give it a 10 in this instance to make it clear). Let’s list them out now, assigning a ranking number.

扑克有9个等级,皇家同花顺排名第9位的手最高(在这种情况下,我们将其设为10)。 让我们现在列出它们,并分配一个排名编号。

10: Royal Flush
9: Straight Flush
8: Quads (4 of a kind)
7: Full House
6: Flush
5: Straight
4: Trips (3 of a kind)
3: Two Pairs
2: Pair
1: High Card

An object map of the ranks will be used to hold flags, with the highest rank first in the map. The high_card rank is set to “true” as a default. During the evaluation of the hand, the corresponding matching rank will be flipped to “true.” Traversing the object map and stopping on the first “true” value will determine the hand’s rank.

等级的对象图将用于保留标志,最高的等级在地图中居首。 默认情况下, high_card等级设置为“ true”。 在评估手牌期间,相应的匹配等级将翻转为“ true”。 遍历对象图并停止在第一个“ true”值上将确定手的等级。

const ranks = {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: false,
high_card: true,
};

Before we get down to coding, I’d like to preface it with the notion that this is NOT production-ready code. It does not include error handling or validation and makes assumptions that you are familiar with poker, ranked hands, and have a basic understanding of JavaScript syntax.

在开始编码之前,我想以不属于生产就绪代码的概念作为开头。 它不包括错误处理或验证,并且假设您熟悉扑克,手牌排名并且对JavaScript语法有基本的了解。

常数 (Constants)

Now that the planning is complete, let’s assign some constants that will be used throughout this exercise. Some of them are self-explanatory, with comments on those that may require additional detail.

现在计划已经完成,让我们分配一些将在整个练习中使用的常量。 其中一些是不言自明的,对可能需要更多详细信息的内容进行评论。

ACE_VALUE equates to 8192, but let's use the Math.pow function to calcualte that for us, which is 2^13, the 13th position from our map above (using a zero index).A way to visualize a hand in the binary matrix, is how the STRAIGHT_LOW_ACE_INDICATOR is constructed as a binary number. It represents a low-ace-straight with the Ace in the high position. The ace will effectively be moved to a lower position during the conversion, which we will see later in the exercise.Without counting the low Ace position, using a zero-index, the "Ten" card is in the 8th position, hence the TEN_CARD_POSITION constant. This will be used later to detect a Royal Flush.A high value is desired for a RANK_BASE_VALUE which will be added to the total score of the hand. It should be higher than the highest sum that can be caculated, which equates to a hand with quad Aces and a King: AAAAK. This value is 268,439,552. I chose 10^9 (1 billion) since it gives a visual clue to its rank by looking at the most significant digit of the final total score.10,000,000,000 < Royal Flush
9,000,000,000 < Straight Flush < 10,000,000
8,000,000,000 < Quads < 7,000,000,000
...
1,000,000,000 < High Card < 2,000,000,000

甲板和洗牌 (The Deck and Shuffling)

We need to build a deck of cards and then to shuffle that deck. Referencing the article I wrote previously about JavaScript shuffling, we can use the Stack Shuffle method described within.

我们需要构建一副纸牌,然后将其洗牌。 参考我之前写的有关JavaScript改组的文章,我们可以使用其中描述的Stack Shuffle方法。

The deck is an array of numbers from 0–51. The matrix shown below splits the cards into four suits: Clubs, Diamonds, Hearts, and Spades. Using a modified Fisher-Yates shuffling algorithm, it should be sufficient enough for this exercise. Line #5 from buildDeck.js chooses a random card in the pool of unshuffled cards and pulls it out of the deck and pushes it back on the top of the deck, then continues with the rest of the cards.

甲板是从0到51的数字数组。 下面显示的矩阵将纸牌分为四组:棍棒,钻石,红心和黑桃。 使用改进的Fisher-Yates混排算法,对于本练习来说应该足够了。 buildDeck.js的第5行代码从未洗牌的卡池中选择一张随机卡,然后将其从卡组中拉出,然后推回卡组的顶部,然后继续处理其余的卡。

Card Matrix
. 2 3 4 5 6 7 8 9 T J Q K A
C 00 01 02 03 04 05 06 07 08 09 10 11 12D 13 14 15 16 17 18 19 20 21 22 23 24 25H 26 27 28 29 30 31 32 33 34 35 36 37 38S 39 40 41 42 43 44 45 46 47 48 49 50 51

显示卡 (Display Cards)

It would be difficult for a human to determine which cards are in hand using numbers only. Let’s write a function that will display the cards in poker terminology; a more human-readable format.

对于人类而言,仅使用数字来确定手中的卡将是困难的。 让我们写一个函数来显示扑克术语中的牌; 更易于阅读的格式。

My favorite JavaScript Array function is .reduce. When iterating across a set of items to return a single value or build a list, using .reduce literally reduces the amount of code that is required. In this instance, it will build out an array of readable poker card faces based on the matrix of numeric card values. In the end, the .join will concatenate it into a single string.

我最喜欢JavaScript Array函数是.reduce 。 遍历一组项目以返回单个值或构建列表时,使用.reduce可以从字面上减少所需的代码量。 在这种情况下,它将基于数字卡值矩阵构建一系列可读的扑克牌面。 最后, .join将把它连接成一个字符串。

It takes an array like this [ 12, 16, 33, 7, 49 ] and displays it like A♣︎ 5♦︎ 9♥︎ 9♣︎ Q♠︎

排名手 (Rank the Hand)

This code is the meat of the exercise and the most complicated and fun to write. This function assumes that an array of 5 cards, based on the card matrix defined above, is the input to the function. As mentioned previously, there is no error handling or input validation. Assume that the consumer of this function is passing valid information.

这段代码是练习的内容,也是编写过程中最复杂,最有趣的部分。 该函数假定基于上述卡片矩阵的5张卡片组成的数组是该函数的输入。 如前所述,没有错误处理或输入验证。 假定此函数的使用者正在传递有效信息。

Outline of the rankHand function:
• Build and count occurences of suits and values
• Calculate the total value of the cards
• Determine the rank of the hand
• Handle a Low-Ace Straight
• Build the description and human readable version
• Return an object with all properties

First, this function builds an array map of suits and values to count the occurrences present in the hand.

首先,此函数构建一个西服和值的数组映射,以计算手中出现的次数。

A Straight Flush would have the resulting array maps:
suits: [ 0, 5, 0, 0 ]
values: [ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 ]A Full House would look like this:
suits: [ 1, 2, 2, 0 ]
values: [ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0 ]

While iterating through the values array, a summation is performed. This code is an example where conditional branches are eliminated by using logical operators within a reducer method. Two calculations are summed together.

在遍历values数组时,执行求和。 此代码是通过在reducer方法中使用逻辑运算符消除条件分支的示例。 将两个计算结果相加。

Line 11:
((val === 1 && Math.pow(2, index + 1)) || 0)

This first calculation will add the value of the card based on the binary expansion of its position + 1, using Math.pow(2, index + 1). The expression val === 1 is required to be true to continue with the math expression; otherwise, it will be zero due to the logical OR (||) operator.

第一次计算将使用Math.pow(2,index + 1)根据卡位置+ 1的二进制扩展来添加卡的值。 表达式val === 1必须为true才能继续数学表达式; 否则,由于逻辑OR(||)运算符,它将为零。

Line 12:
((val > 1 && Math.pow(2, index + 1) * ACE_VALUE * val) || 0))

The second calculation has the same structure, but only for occurrences that are greater than one. This time the binary expansion is multiplied by the ACE_VALUE value and then multiplied again by the number of occurrences of that value. It will adjust for pairs, trips, full houses, and quads by increasing the rank value accordingly.

第二种计算具有相同的结构,但仅适用于大于一个的出现。 这次,将二进制扩展乘以ACE_VALUE值,然后再乘以该值的出现次数。 它将通过相应地增加等级值来调整成对,旅行,满座和四边形。

Line 15:
const firstCardIndex = values.findIndex((index) => index === 1);

The constant firstCardIndex serves a dual purpose. It is used to find the position of the first non-zero count and then used to determine if the hand is ranked as a Straight.

常量firstCardIndex具有双重用途。 它用于查找第一个非零计数的位置,然后用于确定手是否被定为顺子。

Lines 16–34 sets the flag for each rank determined by the conditions and logic set forth on each rank property. The logic for the ranks of Straight Flush and Royal Flush is performed last to leverage the flags already set for a Straight and a Flush. Each expression will equate to a boolean. This block of code eliminates the use of conditional branches altogether by using an object map and boolean expressions.

第16–34行为每个等级设置标志,该标志由每个等级属性上规定的条件和逻辑确定。 最后使用Straight Flush和Royal Flush的等级逻辑来利用已经为Straight和Flush设置的标志。 每个表达式都等于一个布尔值。 此代码块通过使用对象映射和布尔表达式完全消除了条件分支的使用。

Line 37:
Object.keys(ranks).every((key, index) => {

I used Array.every to short-circuit the loop once the first true flag is found, which is when the !ranks[key] is false. This eliminates having to build out a loop and initializing additional variables for tracking. I use this method to reduce the amount of code, which also reduces the number of bugs that could be introduced.

一旦发现第一个true标志,即!ranks [key]为false时,我就使用Array.every来使循环短路。 这样就不必建立循环并初始化用于跟踪的其他变量。 我使用这种方法来减少代码量,这也减少了可能引入的错误的数量。

Lines 42–44 adds the RANK_BASE_VALUE multiplied by the magnitude of the rankIndex, that was found in the previous block, and then subtracts the ACE_VALUE if it’s a Low-Ace Straight. Here again, instead of using any branching logic, conditional logic operators are used.

行42-44添加RANK_BASE_VALUE乘以rankIndex的幅度这是在以前的块中,然后减去ACE_VALUE如果它是一个低王牌直。 同样,这里不使用任何分支逻辑,而是使用条件逻辑运算符。

扑克派对 (Poker Party)

Now that we’ve completed the hard parts, let’s have some fun. We first need to have a way to compare hands to find the winner.

既然我们已经完成了困难的部分,那就让我们玩得开心。 我们首先需要有一种比较手以找到获胜者的方法。

This function will return the hands sorted in ranking order, with the first hand being the “winner.” If writing a full-fledged poker game, determine the equality of multiple hands in the case for split pots.

该函数将返回按排名顺序排列的手牌,第一手牌为“获胜者”。 如果要编写成熟的扑克游戏,则在分派底池的情况下,确定多手牌是否相等。

德州扑克 (Texas Hold ‘Em)

There are many ways to play poker, and some variations can be somewhat complicated, but the most popular would have to be Texas Hold ’Em style. The World Series of Poker (WSOP) circuit is based on No-Limit Texas Hold ’Em rules. Let’s write a function to deal the cards assuming this style of poker game is being played.

玩扑克的方式有很多,有些变化可能有些复杂,但是最受欢迎的应该是德州扑克风格。 世界扑克系列(WSOP)巡回赛基于无限额德州扑克规则。 让我们编写一个函数来假设正在玩这种风格的扑克游戏来发牌。

Instead of wrapping the dealing of the board within a loop, I unrolled it to make it abundantly clear what is happening. After dealing the cards out to the players, the first deck.pop() is a burn card, then three board.push(deck.pop()) consecutively is the flop. The next deck.pop() is another burn card, then comes the turn card, and finally, the same pattern is repeated for the river card.

我没有将电路板的交易包装成一个循环,而是展开了它,以使其清楚地说明正在发生的事情。 在将牌分发给玩家之后,第一个deck.pop()是一张烧牌,然后连续三个board.push(deck.pop())是翻牌。 下一个deck.pop()是另一个烧录卡,然后是转牌,最后,河牌重复相同的模式。

This function can also handle dealing cards for a poker variety called Omaha, in which players received four hole cards instead of two. They are required to use two of those hole cards to combine with three board cards to complete their hand.

此功能还可以处理称为Omaha的扑克品种的发牌,在该品种中,玩家收到的是四张底牌,而不是两张。 他们需要使用其中的两个洞Kong卡与三个板卡结合才能完成操作。

寻找最好的手 (Finding the Best Hand)

With five community cards on the board and two hole cards, we need a routine that will find the best hand across the combination of hands. With Texas Hold ’Em, you can use 1, 2, or none of your hole cards to make a hand.

在板上有五张社区卡和两张Kong卡的情况下,我们需要一个常规程序,以便在多手牌组合中找到最佳手牌。 使用德州扑克(Texas Hold'Em),您可以使用1张,2张或完全不使用底牌来做牌。

Cards are replaced on a clone of the board and then pushed into an array of hands. Including the board as a possible hand, this function produces 21 possible combinations. I believe there may be a more elegant way to accomplish this, but at this time it escapes me. So for now, brute force for loops will suffice.

卡片在板的副本上被替换,然后推入一排手中。 包括板作为可能的手,此功能产生21种可能的组合。 我相信可能会有一种更优雅的方式来完成此操作,但是这一次让我无所适从。 因此,现在for循环蛮力就足够了。

For Texas Hold 'Em rules:The board is 1 possible handThe first set of loops iterates through each index and replaces it with each hole card, producing 10 handsThe second set of loops replaces the board with 2 hole cards, resulting in another 10 hands

Here is the way to find the best hand for Omaha rules.

这是为奥马哈规则找到最佳选择的方法。

With Omaha, the loops iterates through the 4 hole cards and replaces 2 of the board cards, resulting in 60 different hands. This increases the difficulty of identifying combinations of hands, causing Omaha players to adopt a different betting strategy.

These functions will be used later as we deal out a round of play and determine the winner.

这些功能将在稍后进行比赛并确定获胜者时使用。

进行回合 (Dealing a Round)

Now that we have a way to deal out the cards and determine the best hand, let’s put it all together to deal out a round of poker. This function should be able to handle variations in the number of players, hole cards, and evaluating the best hand combination.

现在我们有了一种方法来分发纸牌并确定最佳手牌,让我们将所有这些组合在一起以分发一轮扑克。 此功能应能够处理玩家数量,底牌和评估最佳手牌组合的变化。

The findBestHand parameter is assuming that a function will be passed in based on the required evaluation for the game being played. With this strategy, the dealRound function can support various rules for different variations of poker.

Let’s put it all together now with a function to deal a round of poker for a specific type of game. First Texas Hold ’Em. Notice the holeCards property is set to 2 and the findBestHand property is set to findBestHandTexasHoldEm.

现在让我们将所有功能结合在一起,为特定类型的游戏处理一轮扑克。 第一德州扑克。 请注意, holeCards属性设置为2 ,而findBestHand属性设置为findBestHandTexasHoldEm

Here is how it’s dealt for a round of Omaha. Notice the holeCards property is set to 4 and the findBestHand property is switched to findBestHandOmaha.

这是奥马哈回合的处理方式。 请注意, holeCards属性设置为4 ,并且findBestHand属性切换为findBestHandOmaha

If you copy all of the gists code into a single file and then add either:dealTexasHoldEm(9)ordealOmaha(9)Passing in 9 equates to 9 players. If you execute the file, you should see something like this for Texas Hold 'Em:[
{
name: "Player 5",
hole: "8♣︎ 3♣︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 6, 19],
suits: [2, 1, 0, 2],
values: [0, 0, 0, 0, 0, 0, 3, 0, 1, 1, 0, 0, 0],
rankValue: 4003147264,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: true,
two_pairs: false,
pair: false,
high_card: true,
},
rankDescription: "Trips",
display: "J♠︎ T♣︎ 8♠︎ 8♣︎ 8♦︎",
},
},
{
name: "Player 1",
hole: "J♥︎ 3♠︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 35, 19],
suits: [1, 1, 1, 2],
values: [0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0],
rankValue: 3018874880,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: true,
pair: false,
high_card: true,
},
rankDescription: "Two Pairs",
display: "J♠︎ T♣︎ 8♠︎ J♥︎ 8♦︎",
},
},
{
name: "Player 8",
hole: "5♠︎ 7♣︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 42, 45, 3, 19],
suits: [1, 1, 0, 3],
values: [0, 0, 0, 2, 0, 0, 2, 0, 0, 1, 0, 0, 0],
rankValue: 3002360320,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: true,
pair: false,
high_card: true,
},
rankDescription: "Two Pairs",
display: "J♠︎ 5♠︎ 8♠︎ 5♣︎ 8♦︎",
},
},
{
name: "Player 2",
hole: "A♣︎ 6♥︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 12, 19],
suits: [2, 1, 0, 2],
values: [0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 1],
rankValue: 2002106880,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ A♣︎ 8♦︎",
},
},
{
name: "Player 3",
hole: "9♥︎ A♦︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 25, 19],
suits: [1, 2, 0, 2],
values: [0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 1],
rankValue: 2002106880,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ A♦︎ 8♦︎",
},
},
{
name: "Player 7",
hole: "2♥︎ Q♣︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 10, 19],
suits: [2, 1, 0, 2],
values: [0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 1, 0, 0],
rankValue: 2002100736,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ Q♣︎ 8♦︎",
},
},
{
name: "Player 9",
hole: "Q♦︎ 7♠︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 23, 19],
suits: [1, 2, 0, 2],
values: [0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 1, 0, 0],
rankValue: 2002100736,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ Q♦︎ 8♦︎",
},
},
{
name: "Player 4",
hole: "2♦︎ 6♠︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 43, 19],
suits: [1, 1, 0, 3],
values: [0, 0, 0, 0, 1, 0, 2, 0, 1, 1, 0, 0, 0],
rankValue: 2002098720,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ 6♠︎ 8♦︎",
},
},
{
name: "Player 6",
hole: "3♦︎ 2♠︎",
board: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
bestHand: {
hand: [48, 8, 45, 3, 19],
suits: [2, 1, 0, 2],
values: [0, 0, 0, 1, 0, 0, 2, 0, 1, 1, 0, 0, 0],
rankValue: 2002098704,
ranks: {
royal_flush: false,
straight_flush: false,
quads: false,
full_house: false,
flush: false,
straight: false,
trips: false,
two_pairs: false,
pair: true,
high_card: true,
},
rankDescription: "Pair",
display: "J♠︎ T♣︎ 8♠︎ 5♣︎ 8♦︎",
},
},
]

下一步 (Next Steps)

If you were able to read through the entirety of the code posted, you will notice not a single “if,” “switch,” or ternary statement was used. Changing the design to utilize an object map and logical operators removed the messiness of nested conditional branches and in return reduced the line count, forming a clean top-down execution structure.

如果您能够阅读所发布的全部代码,则将注意到未使用任何一个“ if”,“ switch”或三元语句。 更改设计以利用对象映射和逻辑运算符可以消除嵌套的条件分支的混乱情况,从而减少行数,从而形成干净的自上而下的执行结构。

The functions written here can be used as a springboard to get a good start and establish a core of handling cards and ranks. To build a fully functional poker game, additional functionality and mechanisms are needed: betting rounds, pot management, chip management, player management, and a user interface. If operating over the internet, then networking, API, and state management code are required for a full-fledged poker application.

此处编写的功能可以用作入门的跳板,并建立起处理卡片和等级的核心。 要构建功能齐全的扑克游戏,需要其他功能和机制:下注回合,底池管理,筹码管理,玩家管理和用户界面。 如果通过Internet进行操作,则成熟的扑克应用程序需要联网,API和状态管理代码。

There are always multiple ways to solve a problem in programming, some unconventional. Take some time to plan out an approach before laying down a single line of code. Dare yourself to go past your first inclinations.

解决编程问题的方法总有多种,有些是非常规的。 在放置一行代码之前,需要花一些时间来规划一种方法。 敢于超越自己的初衷。

My ongoing challenge is to write the least amount of code, leveraging strategies learned through examples, articles, and a lot of experimentation. Step out of your comfort zone, and you may discover a shortcut or new technique and, along the way, become a better software developer.

我目前面临的挑战是编写最少的代码,利用通过示例,文章和大量实验中学到的策略。 走出舒适区,您可能会发现捷径或新技术,并一路成为更好的软件开发人员。

翻译自: https://medium.com/javascript-in-plain-english/building-a-poker-hand-evaluator-without-conditional-branches-556c39c8e33e

条件概率 扑克

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算德州扑克6人游戏中不同手牌的获胜概率需要考虑所有可能的手牌组合与公共牌的组合情况。以下是一个R代码示例,用于计算不同手牌的获胜概率: ```R # 定义扑克牌 suits <- c("hearts", "diamonds", "clubs", "spades") values <- c("A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3", "2") cards <- expand.grid(value=values, suit=suits) # 定义一副牌 deck <- paste(cards$value, "of", cards$suit) # 定义所有可能的手牌组合 all_hands <- combn(deck, 2) # 定义公共牌 board <- c("2h", "5h", "9c", "10d", "Qh") # 定义计算每种手牌组合胜率的函数 calculate_win_rate <- function(hand, board, deck) { # 生成所有可能的手牌组合 hand_combinations <- combn(setdiff(deck, c(hand, board)), 2) # 计算每种手牌组合的胜率 wins <- 0 total <- ncol(hand_combinations) for (i in 1:total) { opponent_hand <- hand_combinations[,i] all_cards <- c(hand, board, opponent_hand) player_score <- PokerHand::score_hand(all_cards[1:2], all_cards[3:7]) opponent_score <- PokerHand::score_hand(opponent_hand, all_cards[3:7]) if (player_score > opponent_score) { wins <- wins + 1 } } # 返回胜率 return(wins / total) } # 计算不同手牌获胜概率 win_rates <- matrix(NA, nrow=nrow(all_hands), ncol=1) for (i in 1:nrow(all_hands)) { hand <- all_hands[,i] win_rates[i] <- calculate_win_rate(hand, board, deck) } # 输出结果 result <- data.frame(hand1=all_hands[1,], hand2=all_hands[2,], win_rate=win_rates) result <- result[order(result$win_rate, decreasing=TRUE),] head(result) ``` 这段代码用到了PokerHand包来计算牌型得分。输出结果将显示不同手牌的获胜概率,并按照获胜概率从高到低排序。注意,这只是一个简单的示例代码,实际应用中需要考虑更多因素,如对手的行为模式和策略等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值