I'm writing a poker program, and I can't figure out how to handle straights.
我正在写一个扑克计划,我无法弄清楚如何处理直道。
Straight: All cards in a hand of 5 cards are consecutive values. ex. 2..6, 3..7, 4..8, 5..9, 6..T, 7..J, 8..Q, 9..K, T..A
直接:5张牌中的所有牌都是连续值。恩。 2..6,3..7,4..8,5..9,6..T,7..J,8..Q,9..K,T..A
cards = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
How can I check a hand, which is an array, for these combinations? Preferably I can check it to see if it's 5 in a row in the cards array.
如何检查这些组合的手,这是一个数组?我最好能检查它是否在卡阵列中连续5行。
7 个解决方案
#1
4
Edit 2: This is my absolutely final solution:
编辑2:这是我绝对的最终解决方案:
require 'set'
STRAIGHTS = ['A',*2..9,'T','J','Q','K','A'].each_cons(5).map(&:to_set)
#=> [#<Set: {"A", 2, 3, 4, 5}>, #<Set: {2, 3, 4, 5, 6}>,
# ...#<Set: {9, "T", "J", "Q", "K"}>, #<Set: {"T", "J", "Q", "K", "A"}>]
def straight?(hand)
STRAIGHTS.include?(hand.to_set)
end
STRAIGHTS.include?([6,3,4,5,2].to_set)
# STRAIGHTS.include?(#<Set: {6, 3, 4, 5, 2}>)
#=> true
straight?([6,5,4,3,2]) #=> true
straight?(["T","J","Q","K","A"]) #=> true
straight?(["A","K","Q","J","T"]) #=> true
straight?([2,3,4,5,"A"]) #=> true
straight?([6,7,8,9,"J"]) #=> false
straight?(["J",7,8,9,"T"]) #=> false
Edit 1: @mudasobwa upset the apple cart by pointing out that 'A',2,3,4,5
is a valid straight. I believe I've fixed my answer. (I trust he's not going to tell me that 'K','A',2,3,4
is also valid.)
编辑1:@mudasobwa通过指出'A',2,3,4,5是有效的直线来扰乱苹果车。我相信我已经解决了问题。 (我相信他不会告诉我'K','A',2,3,4也是有效的。)
I would suggest the following:
我建议如下:
CARDS = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
STRAIGHTS = CARDS.each_cons(5).to_a
#=>[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8],
# [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"],
# [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"],
# ["T", "J", "Q", "K", "A"]]
def straight?(hand)
(hand.map {|c| CARDS.index(c)}.sort == [0,1,2,3,12]) ||
STRAIGHTS.include?(hand.sort {|a,b| CARDS.index(a) <=> CARDS.index(b)})
end
#2
4
If we map each card to a value (9 is 9, "T" is 10, "J" is 11, etc.), then there are two facts that are true of all straights that we can use to solve our problem:
如果我们将每张牌映射到一个值(9是9,“T”是10,“J”是11等),那么我们可以用来解决问题的所有直道都有两个事实:
- All straights have exactly five unique card values
- 所有直道都有五个独特的卡值
- The difference between the last and first cards' values is always 4
- 最后一张牌和第一张牌的价值之间的差异总是4
And so:
所以:
CARD_VALUES = {
2 => 2, 3 => 3, 4 => 4,
5 => 5, 6 => 6, 7 => 7,
8 => 8, 9 => 9, "T" => 10,
"J" => 11, "Q" => 12, "K" => 13,
"A" => 14
}
def is_straight?(hand)
hand_sorted = hand.map {|card| CARD_VALUES[card] }
.sort.uniq
hand_sorted.size == 5 &&
(hand_sorted.last - hand_sorted.first) == 4
end
This method (1) converts each card to its numeric value with map
, then (2) sort
s them, and then (3) throws out duplicates with uniq
. To illustrate with various hands:
这个方法(1)用map将每张卡转换为数值,然后(2)对它们进行排序,然后(3)用uniq抛出重复。用各种手来说明:
hand | 4 A T A 2 | 2 2 3 3 4 | 5 6 4 8 7 | 3 6 2 8 7
---------+--------------------+--------------------+--------------------+----------------
1. map | 4 14 10 14 2 | 2 2 3 3 4 | 5 6 4 8 7 | 3 6 2 8 7
2. sort | 2 4 10 14 14 | 2 2 3 3 4 | 4 5 6 7 8 | 2 3 6 7 8
3. uniq | 2 4 10 14 | 2 3 4 | 4 5 6 7 8 | 2 3 6 7 8
Alternatively...
I originally posted the following solution, which isn't bad, but is definitely more convoluted:
我最初发布了以下解决方案,这不错,但肯定更复杂:
If the hand is sorted, this is easy. You can use Enumerable#each_cons
to check each possible straight.
如果手被分类,这很容易。您可以使用Enumerable#each_cons来检查每个可能的直线。
CARDS = [ 2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A" ]
hand = [ 4, 5, 6, 7, 8 ]
def is_straight?(hand)
CARDS.each_cons(5).any? do |straight|
hand == straight
end
end
if is_straight?(hand)
puts "Straight!"
else
puts "Not straight!"
end
# => Straight!
each_cons(5)
returns each consecutive set of 5 items, so in the above example hand
is first compared to [ 2, 3, 4, 5, 6 ]
, then [ 3, 4, 5, 6, 7 ]
, and then [ 4, 5, 6, 7, 8 ]
, which is a match, so any?
returns true
.
each_cons(5)返回每组连续的5个项目,因此在上面的示例中,首先将手与[2,3,4,5,6],然后[3,4,5,6,7]进行比较,然后[ 4,5,6,7,8],这是匹配,所以任何?返回true。
Note that this is not the most efficient solution, but unless you need to check many thousands of hands per second, this is more than adequately performant.
请注意,这不是最有效的解决方案,但除非您需要每秒检查数千手,否则这不仅具有足够的性能。
If your hands aren't sorted yet, you'll need to do that first. The simplest way to do that is create a Hash that maps cards to a numeric value (as above) and then use sort_by
:
如果你的手还没有排序,你需要先做。最简单的方法是创建一个Hash,将卡映射到数值(如上所示),然后使用sort_by:
def sort_hand(hand)
hand.sort_by {|card| CARD_VALUES[card] }
end
hand = [ 4, "A", 2, "A", "T" ]
sort_hand(hand)
# => [ 2, 4, "T", "A", "A" ]
#3
1
I did not want to participate, but I can’t keep silence looking at all these oversophisticated solutions around.
我不想参加,但我不能保持沉默,看看所有这些过于复杂的解决方案。
hand = [2, 5, 7, 'A', 'J'].map(&:to_s)
'23456789TJQKA' =~ hand.sort_by{|hc| '23456789TJQKA'.index(hc)}.join ||
'A23456789TJQK' =~ hand.sort_by{|hc| 'A23456789TJQK'.index(hc)}.join
In a not lame hardcoded manner:
以一种不蹩脚的硬编码方式:
suit = '23456789TJQKA'
suit =~ hand.sort_by{|hc| suit.index(hc)}.join ||
suit.rotate(-1) =~ hand.sort_by{|hc| suit.rotate(-1).index(hc)}.join
#4
1
Generate list of valid hands:
生成有效手牌列表:
valid_hands = cards[0..8].each_with_index.map{|b,i| cards[i..i+4]}
#=> [[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"], [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"], ["T", "J", "Q", "K", "A"]]
Once you have the list of all valid hands, you can now check if provided hand is among any? of them (valid ones) or not:
获得所有有效牌的清单后,您现在可以检查提供的牌是否属于任何牌?他们(有效的)或不是:
if valid_hands.any? { |h| (h - hand).empty? }
puts "Valid hand"
else
puts "Not Valid"
end
UPDATE
UPDATE
In-case 2, 3, 4, 5, "A"
, 2, 3, 4, "K", "A"
, 2, 3, "Q", "K", "A"
, 2, "J", "Q", "K", "A"
are also considered as valid hands, calculate them as follows:
在案例2,3,4,5,“A”,2,3,4,“K”,“A”,2,3,“Q”,“K”,“A”,2,“J” ,“Q”,“K”,“A”也被认为是有效的手,计算如下:
valid_hands = cards.each_with_index.map { |b,i| i < 9 ? cards[i..i+4] : cards[0..i-9] + cards[i..-1] }
# => [[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"], [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"], ["T", "J", "Q", "K", "A"], [2, "J", "Q", "K", "A"], [2, 3, "Q", "K", "A"], [2, 3, 4, "K", "A"], [2, 3, 4, 5, "A"]]
#5
1
I recommend writing classes to represent a Card (and maybe Deck and Hand too). Aim for an interface like this:
我建议写一个代表卡片的课程(也可能是Deck和Hand)。瞄准这样的界面:
deck = Deck.new.shuffle!
hand = Hand.new(deck.draw 5)
hand.straight?
#=>false
puts hand
8♣ 8♦ T♠ 2♦ 7♦
The encapsulation of functionality gives you readability and makes it easy to extend (i.e. with suits)
功能的封装为您提供了可读性并使其易于扩展(即适用于套装)
Here's a more simplistic version, implemented as a single Card class. I did add suits though.
这是一个更简单的版本,作为单个Card类实现。我确实加了西装。
class Card
include Enumerable #enables sorting
attr_accessor :value, :suit
@values = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
@suits = ["♣","♦","♥","♠"]
def self.all
@values.product(@suits).map{|c| Card.new c}
end
def self.straight?(cards)
["A", *@values].each_cons(5).include?(cards.map(&:value))
end
def self.flush?(cards)
cards.map(&:suit).uniq.size == 1
end
def initialize(v)
@value, @suit = *v
end
def <=>(other) #for sorting
@values.index(value) <=> @values.index(other.value)
end
def to_s
"#{value}#{suit}"
end
end
This works as follows
其工作原理如下
deck = Card.all
puts deck
#=> 2♣ 2♦ 2♥ 2♠ 3♣ 3♦ 3♥ 3♠ 4♣ 4♦ 4♥ 4♠ 5♣ 5♦ 5♥ 5♠ 6♣ 6♦ 6♥ 6♠ 7♣ 7♦ 7♥ 7♠ 8♣ 8♦ 8♥ 8♠ 9♣ 9♦ 9♥ 9♠ T♣ T♦ T♥ T♠ J♣ J♦ J♥ J♠ Q♣ Q♦ Q♥ Q♠ K♣ K♦ K♥ K♠ A♣ A♦ A♥ A♠
hand = deck.sample 5
puts hand
#=> Q♥ 6♦ 2♣ T♠ Q♦
Card.straight?(hand)
#=>false
#6
0
Step 0: Let's start with an empty class
class CardUtils
end
Step 1: Store values of card in Hash
Hash allows fast referencing of values of a card.
哈希允许快速参考卡的值。
@@card_values = {
'A' => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
6 => 6, 7 => 7, 8 => 8, 9 => 9, 'T' => 10,
'J' => 11, 'Q' => 12, 'K' => 13
}
Thus, you can reference the card value simply as below.
因此,您可以简单地参考卡值,如下所示。
@@card_values['A']
# => 1
@@card_values[8]
# => 8
Step 2: Sort the hand
Apply sort! method to the hand with reference to the card values.
申请排序!参考卡值的手的方法。
def self.sort(hand)
hand.sort {|x,y| @@card_values[x] <=> @@card_values[y]}
end
# => ["A", 2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K"]
Step 3: Function that tells whether two cards are consecutive
def self.is_consecutive(x, y)
val_x = @@card_values[x]
val_y = @@card_values[y]
val_x == val_y - 1 || val_x + 13 == val_y
end
# is_consecutive('A', 2)
# => true
# is_consecutive('K', 'A')
# => true
# is_consecutive('A', 3)
# => false
Step 4: Check for 'straight'
It could be done with simple iteration.
它可以通过简单的迭代完成。
def self.has_straight(hand)
hand = sort(hand)
max_consecutive_count = 0
consecutive_count = 0
hand.each_with_index do |curr, i|
prev = hand[i - 1]
if is_consecutive(prev, curr) then
consecutive_count += 1
else
consecutive_count = 0
end
if consecutive_count > max_consecutive_count then
max_consecutive_count = consecutive_count
end
end
max_consecutive_count >= 5
end
# hand = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
# CardUtils.has_straight(hand)
# => true
Final Result
class CardUtils
@@card_values = {
'A' => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
6 => 6, 7 => 7, 8 => 8, 9 => 9, 'T' => 10,
'J' => 11, 'Q' => 12, 'K' => 13
}
def self.is_consecutive(x, y)
val_x = @@card_values[x]
val_y = @@card_values[y]
val_x == val_y - 1 || val_x + 13 == val_y
end
def self.sort(hand)
hand.sort {|x,y| @@card_values[x] <=> @@card_values[y]}
end
def self.has_straight(hand)
hand = sort(hand)
max_consecutive_count = 0
consecutive_count = 0
hand.each_with_index do |curr, i|
prev = hand[i - 1]
if is_consecutive(prev, curr) then
consecutive_count += 1
else
consecutive_count = 0
end
if consecutive_count > max_consecutive_count then
max_consecutive_count = consecutive_count
end
end
max_consecutive_count >= 5
end
end
#7
0
This is how I would write it:
这是我写它的方式:
hand = [3,4,5,2,'A']
def is_straight(hand)
# No need to check further if we do not have 5 unique cards.
return false unless hand.uniq.size == 5
# Note the A at beginning AND end to count A as 1 or 14.
list_of_straights = 'A23456789TJQKA'.chars.each_cons(5)
sorted_hand = hand.map(&:to_s).sort
list_of_straights.any? do |straight|
straight.sort==sorted_hand
end
end
puts is_straight(hand) #=> true
Alternatively if you do not like all the sorting you could exchange the last part to:
或者,如果您不喜欢所有排序,您可以将最后一部分交换为:
hand_as_stings = hand.map(&:to_s)
list_of_straights.any? do |straight|
(straight-hand_as_stings).empty?
end
#1
4
Edit 2: This is my absolutely final solution:
编辑2:这是我绝对的最终解决方案:
require 'set'
STRAIGHTS = ['A',*2..9,'T','J','Q','K','A'].each_cons(5).map(&:to_set)
#=> [#<Set: {"A", 2, 3, 4, 5}>, #<Set: {2, 3, 4, 5, 6}>,
# ...#<Set: {9, "T", "J", "Q", "K"}>, #<Set: {"T", "J", "Q", "K", "A"}>]
def straight?(hand)
STRAIGHTS.include?(hand.to_set)
end
STRAIGHTS.include?([6,3,4,5,2].to_set)
# STRAIGHTS.include?(#<Set: {6, 3, 4, 5, 2}>)
#=> true
straight?([6,5,4,3,2]) #=> true
straight?(["T","J","Q","K","A"]) #=> true
straight?(["A","K","Q","J","T"]) #=> true
straight?([2,3,4,5,"A"]) #=> true
straight?([6,7,8,9,"J"]) #=> false
straight?(["J",7,8,9,"T"]) #=> false
Edit 1: @mudasobwa upset the apple cart by pointing out that 'A',2,3,4,5
is a valid straight. I believe I've fixed my answer. (I trust he's not going to tell me that 'K','A',2,3,4
is also valid.)
编辑1:@mudasobwa通过指出'A',2,3,4,5是有效的直线来扰乱苹果车。我相信我已经解决了问题。 (我相信他不会告诉我'K','A',2,3,4也是有效的。)
I would suggest the following:
我建议如下:
CARDS = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
STRAIGHTS = CARDS.each_cons(5).to_a
#=>[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8],
# [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"],
# [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"],
# ["T", "J", "Q", "K", "A"]]
def straight?(hand)
(hand.map {|c| CARDS.index(c)}.sort == [0,1,2,3,12]) ||
STRAIGHTS.include?(hand.sort {|a,b| CARDS.index(a) <=> CARDS.index(b)})
end
#2
4
If we map each card to a value (9 is 9, "T" is 10, "J" is 11, etc.), then there are two facts that are true of all straights that we can use to solve our problem:
如果我们将每张牌映射到一个值(9是9,“T”是10,“J”是11等),那么我们可以用来解决问题的所有直道都有两个事实:
- All straights have exactly five unique card values
- 所有直道都有五个独特的卡值
- The difference between the last and first cards' values is always 4
- 最后一张牌和第一张牌的价值之间的差异总是4
And so:
所以:
CARD_VALUES = {
2 => 2, 3 => 3, 4 => 4,
5 => 5, 6 => 6, 7 => 7,
8 => 8, 9 => 9, "T" => 10,
"J" => 11, "Q" => 12, "K" => 13,
"A" => 14
}
def is_straight?(hand)
hand_sorted = hand.map {|card| CARD_VALUES[card] }
.sort.uniq
hand_sorted.size == 5 &&
(hand_sorted.last - hand_sorted.first) == 4
end
This method (1) converts each card to its numeric value with map
, then (2) sort
s them, and then (3) throws out duplicates with uniq
. To illustrate with various hands:
这个方法(1)用map将每张卡转换为数值,然后(2)对它们进行排序,然后(3)用uniq抛出重复。用各种手来说明:
hand | 4 A T A 2 | 2 2 3 3 4 | 5 6 4 8 7 | 3 6 2 8 7
---------+--------------------+--------------------+--------------------+----------------
1. map | 4 14 10 14 2 | 2 2 3 3 4 | 5 6 4 8 7 | 3 6 2 8 7
2. sort | 2 4 10 14 14 | 2 2 3 3 4 | 4 5 6 7 8 | 2 3 6 7 8
3. uniq | 2 4 10 14 | 2 3 4 | 4 5 6 7 8 | 2 3 6 7 8
Alternatively...
I originally posted the following solution, which isn't bad, but is definitely more convoluted:
我最初发布了以下解决方案,这不错,但肯定更复杂:
If the hand is sorted, this is easy. You can use Enumerable#each_cons
to check each possible straight.
如果手被分类,这很容易。您可以使用Enumerable#each_cons来检查每个可能的直线。
CARDS = [ 2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A" ]
hand = [ 4, 5, 6, 7, 8 ]
def is_straight?(hand)
CARDS.each_cons(5).any? do |straight|
hand == straight
end
end
if is_straight?(hand)
puts "Straight!"
else
puts "Not straight!"
end
# => Straight!
each_cons(5)
returns each consecutive set of 5 items, so in the above example hand
is first compared to [ 2, 3, 4, 5, 6 ]
, then [ 3, 4, 5, 6, 7 ]
, and then [ 4, 5, 6, 7, 8 ]
, which is a match, so any?
returns true
.
each_cons(5)返回每组连续的5个项目,因此在上面的示例中,首先将手与[2,3,4,5,6],然后[3,4,5,6,7]进行比较,然后[ 4,5,6,7,8],这是匹配,所以任何?返回true。
Note that this is not the most efficient solution, but unless you need to check many thousands of hands per second, this is more than adequately performant.
请注意,这不是最有效的解决方案,但除非您需要每秒检查数千手,否则这不仅具有足够的性能。
If your hands aren't sorted yet, you'll need to do that first. The simplest way to do that is create a Hash that maps cards to a numeric value (as above) and then use sort_by
:
如果你的手还没有排序,你需要先做。最简单的方法是创建一个Hash,将卡映射到数值(如上所示),然后使用sort_by:
def sort_hand(hand)
hand.sort_by {|card| CARD_VALUES[card] }
end
hand = [ 4, "A", 2, "A", "T" ]
sort_hand(hand)
# => [ 2, 4, "T", "A", "A" ]
#3
1
I did not want to participate, but I can’t keep silence looking at all these oversophisticated solutions around.
我不想参加,但我不能保持沉默,看看所有这些过于复杂的解决方案。
hand = [2, 5, 7, 'A', 'J'].map(&:to_s)
'23456789TJQKA' =~ hand.sort_by{|hc| '23456789TJQKA'.index(hc)}.join ||
'A23456789TJQK' =~ hand.sort_by{|hc| 'A23456789TJQK'.index(hc)}.join
In a not lame hardcoded manner:
以一种不蹩脚的硬编码方式:
suit = '23456789TJQKA'
suit =~ hand.sort_by{|hc| suit.index(hc)}.join ||
suit.rotate(-1) =~ hand.sort_by{|hc| suit.rotate(-1).index(hc)}.join
#4
1
Generate list of valid hands:
生成有效手牌列表:
valid_hands = cards[0..8].each_with_index.map{|b,i| cards[i..i+4]}
#=> [[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"], [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"], ["T", "J", "Q", "K", "A"]]
Once you have the list of all valid hands, you can now check if provided hand is among any? of them (valid ones) or not:
获得所有有效牌的清单后,您现在可以检查提供的牌是否属于任何牌?他们(有效的)或不是:
if valid_hands.any? { |h| (h - hand).empty? }
puts "Valid hand"
else
puts "Not Valid"
end
UPDATE
UPDATE
In-case 2, 3, 4, 5, "A"
, 2, 3, 4, "K", "A"
, 2, 3, "Q", "K", "A"
, 2, "J", "Q", "K", "A"
are also considered as valid hands, calculate them as follows:
在案例2,3,4,5,“A”,2,3,4,“K”,“A”,2,3,“Q”,“K”,“A”,2,“J” ,“Q”,“K”,“A”也被认为是有效的手,计算如下:
valid_hands = cards.each_with_index.map { |b,i| i < 9 ? cards[i..i+4] : cards[0..i-9] + cards[i..-1] }
# => [[2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9], [6, 7, 8, 9, "T"], [7, 8, 9, "T", "J"], [8, 9, "T", "J", "Q"], [9, "T", "J", "Q", "K"], ["T", "J", "Q", "K", "A"], [2, "J", "Q", "K", "A"], [2, 3, "Q", "K", "A"], [2, 3, 4, "K", "A"], [2, 3, 4, 5, "A"]]
#5
1
I recommend writing classes to represent a Card (and maybe Deck and Hand too). Aim for an interface like this:
我建议写一个代表卡片的课程(也可能是Deck和Hand)。瞄准这样的界面:
deck = Deck.new.shuffle!
hand = Hand.new(deck.draw 5)
hand.straight?
#=>false
puts hand
8♣ 8♦ T♠ 2♦ 7♦
The encapsulation of functionality gives you readability and makes it easy to extend (i.e. with suits)
功能的封装为您提供了可读性并使其易于扩展(即适用于套装)
Here's a more simplistic version, implemented as a single Card class. I did add suits though.
这是一个更简单的版本,作为单个Card类实现。我确实加了西装。
class Card
include Enumerable #enables sorting
attr_accessor :value, :suit
@values = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
@suits = ["♣","♦","♥","♠"]
def self.all
@values.product(@suits).map{|c| Card.new c}
end
def self.straight?(cards)
["A", *@values].each_cons(5).include?(cards.map(&:value))
end
def self.flush?(cards)
cards.map(&:suit).uniq.size == 1
end
def initialize(v)
@value, @suit = *v
end
def <=>(other) #for sorting
@values.index(value) <=> @values.index(other.value)
end
def to_s
"#{value}#{suit}"
end
end
This works as follows
其工作原理如下
deck = Card.all
puts deck
#=> 2♣ 2♦ 2♥ 2♠ 3♣ 3♦ 3♥ 3♠ 4♣ 4♦ 4♥ 4♠ 5♣ 5♦ 5♥ 5♠ 6♣ 6♦ 6♥ 6♠ 7♣ 7♦ 7♥ 7♠ 8♣ 8♦ 8♥ 8♠ 9♣ 9♦ 9♥ 9♠ T♣ T♦ T♥ T♠ J♣ J♦ J♥ J♠ Q♣ Q♦ Q♥ Q♠ K♣ K♦ K♥ K♠ A♣ A♦ A♥ A♠
hand = deck.sample 5
puts hand
#=> Q♥ 6♦ 2♣ T♠ Q♦
Card.straight?(hand)
#=>false
#6
0
Step 0: Let's start with an empty class
class CardUtils
end
Step 1: Store values of card in Hash
Hash allows fast referencing of values of a card.
哈希允许快速参考卡的值。
@@card_values = {
'A' => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
6 => 6, 7 => 7, 8 => 8, 9 => 9, 'T' => 10,
'J' => 11, 'Q' => 12, 'K' => 13
}
Thus, you can reference the card value simply as below.
因此,您可以简单地参考卡值,如下所示。
@@card_values['A']
# => 1
@@card_values[8]
# => 8
Step 2: Sort the hand
Apply sort! method to the hand with reference to the card values.
申请排序!参考卡值的手的方法。
def self.sort(hand)
hand.sort {|x,y| @@card_values[x] <=> @@card_values[y]}
end
# => ["A", 2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K"]
Step 3: Function that tells whether two cards are consecutive
def self.is_consecutive(x, y)
val_x = @@card_values[x]
val_y = @@card_values[y]
val_x == val_y - 1 || val_x + 13 == val_y
end
# is_consecutive('A', 2)
# => true
# is_consecutive('K', 'A')
# => true
# is_consecutive('A', 3)
# => false
Step 4: Check for 'straight'
It could be done with simple iteration.
它可以通过简单的迭代完成。
def self.has_straight(hand)
hand = sort(hand)
max_consecutive_count = 0
consecutive_count = 0
hand.each_with_index do |curr, i|
prev = hand[i - 1]
if is_consecutive(prev, curr) then
consecutive_count += 1
else
consecutive_count = 0
end
if consecutive_count > max_consecutive_count then
max_consecutive_count = consecutive_count
end
end
max_consecutive_count >= 5
end
# hand = [2, 3, 4, 5, 6, 7, 8, 9, "T", "J", "Q", "K", "A"]
# CardUtils.has_straight(hand)
# => true
Final Result
class CardUtils
@@card_values = {
'A' => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5,
6 => 6, 7 => 7, 8 => 8, 9 => 9, 'T' => 10,
'J' => 11, 'Q' => 12, 'K' => 13
}
def self.is_consecutive(x, y)
val_x = @@card_values[x]
val_y = @@card_values[y]
val_x == val_y - 1 || val_x + 13 == val_y
end
def self.sort(hand)
hand.sort {|x,y| @@card_values[x] <=> @@card_values[y]}
end
def self.has_straight(hand)
hand = sort(hand)
max_consecutive_count = 0
consecutive_count = 0
hand.each_with_index do |curr, i|
prev = hand[i - 1]
if is_consecutive(prev, curr) then
consecutive_count += 1
else
consecutive_count = 0
end
if consecutive_count > max_consecutive_count then
max_consecutive_count = consecutive_count
end
end
max_consecutive_count >= 5
end
end
#7
0
This is how I would write it:
这是我写它的方式:
hand = [3,4,5,2,'A']
def is_straight(hand)
# No need to check further if we do not have 5 unique cards.
return false unless hand.uniq.size == 5
# Note the A at beginning AND end to count A as 1 or 14.
list_of_straights = 'A23456789TJQKA'.chars.each_cons(5)
sorted_hand = hand.map(&:to_s).sort
list_of_straights.any? do |straight|
straight.sort==sorted_hand
end
end
puts is_straight(hand) #=> true
Alternatively if you do not like all the sorting you could exchange the last part to:
或者,如果您不喜欢所有排序,您可以将最后一部分交换为:
hand_as_stings = hand.map(&:to_s)
list_of_straights.any? do |straight|
(straight-hand_as_stings).empty?
end