You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
exportfunctionhandRank(cardStrings: [string,string,string,string,string]): Hand{constcards: Card[]=cardStrings.map((str: string)=>({rank: rankToNumber(str.substring(0,str.length-1)asRank),suit: suitToNumber(str.at(-1)asSuit)}));// We won't use the [0] place in the following arraysconstcountBySuit=newArray(5).fill(0);constcountByRank=newArray(15).fill(0);constcountBySet=newArray(5).fill(0);cards.forEach((card: Card)=>{countByRank[card.rank]++;countBySuit[card.suit]++;});countByRank.forEach((count: number)=>count&&countBySet[count]++);// count the A also as a 14, for straightscountByRank[14]=countByRank[1];if(countBySet[4]===1&&countBySet[1]===1)returnHand.FourOfAKind;elseif(countBySet[3]&&countBySet[2]===1)returnHand.FullHouse;elseif(countBySet[3]&&countBySet[1]===2)returnHand.ThreeOfAKind;elseif(countBySet[2]===2&&countBySet[1]===1)returnHand.TwoPairs;elseif(countBySet[2]===1&&countBySet[1]===3)returnHand.OnePair;elseif(countBySet[1]===5){if(countByRank.join('').includes('11111'))return!countBySuit.includes(5)
? Hand.Straight
: countByRank.slice(10).join('')==='11111'
? Hand.RoyalFlush
: Hand.StraightFlush;else{/* !countByRank.join("").includes("11111") */returncountBySuit.includes(5)
? Hand.Flush
: Hand.HighCard;}}else{thrownewError('Unknown hand! This cannot happen! Bad logic!');}}
TS实战之扑克牌排序
在线运行
我们用
ts实现扑克牌排序问题
,首先,我们将定义所需的数据类型,然后专注于模式查找算法,该算法有几个有趣的要点。类型和转换
定义一些我们需要的类型。
Rank
和Suit
是明显的联合类型。我们将使用
Card
对象进行处理,将rank和suit转换为数字。卡片将用从1(Ace)到13(King)的值表示,花色从1(红心)到4(梅花)。rankToNumber()
和suitToNumber()
函数处理从Rank
和Suit
值到数字的转换。这些类型用于内部工作;我们还必须定义手牌检测算法的结果类型。我们需要一个枚举类型来表示手牌的可能值。这些值按照从最低("高牌")到最高("皇家同花顺")的顺序排列。
我们有什么手牌?
让我们首先定义我们将要构建的
handRank()
函数。我们的函数将接收一个包含五张牌的元组
,并返回一个Hand
结果。由于处理字符串比我们需要的要困难,我们将把牌字符串转换为具有数字
rank
和suit
值的Card
对象,以便更容易编写。确定玩家手牌的价值的关键在于知道每个等级的牌有多少张,以及我们有多少计数。例如,如果我们有三张J和两张K,J的计数为3,K的计数为2。然后,知道我们有一个计数为三和一个计数为两的计数,我们可以确定我们有一个葫芦。另一个例子:如果我们有两个Q,两个A和一个5,我们会得到两个计数为两和一个计数为一;我们有两对。
生成计数很简单。我们希望A的计数在
countByRank[1]
处,因此我们不会使用countByRank
数组的初始位置。类似地,花色的计数将位于countBySuit[1]
到countBySuit[4]
之间,因此我们也不会使用该数组的初始位置。我们不要忘记A可能位于顺子的开头(A-2-3-4-5)或结尾(10-J-Q-K-A)。我们可以通过在K之后复制Aces计数来处理这个问题。
现在我们可以开始识别手牌了。我们只需要查看按等级计数即可识别几种手牌:
例如,如果有四张相同等级的牌,我们知道玩家将获得“四条”。可能会问:如果
countBySet[4] === 1
,为什么还要测试countBySet[1] === 1
?如果四张牌的等级相同,应该只有一张其他牌,对吗?答案是“防御性编程”——在开发代码时,有时会出现错误,通过在测试中更加具体,有助于排查错误。上面的情况包括了所有某个等级出现多次的可能性。我们必须处理其他情况,包括顺子、同花和“高牌”。
这里我们再次进行防御性编程;即使我们知道我们有五个不同的等级,我们也确保逻辑工作良好,甚至在出现问题时抛出一个
throw
。我们如何测试顺子?我们应该有五个连续的等级。如果我们查看
countByRank
数组,它应该有五个连续的1,所以通过执行countByRank.join()
并检查生成的字符串是否包含11111
,我们可以确定是顺子。我们必须区分几种情况:
如果我们没有顺子,只有两种可能性:
完整的函数如下所示:
测试代码
在线运行
The text was updated successfully, but these errors were encountered: