我正在开发一副纸牌。我的手是一串字符串。例如:
hand1 = ["10 of ♣", "5 of ♣", "5 of ♠", "A of ♦", "3 of ♦"]
我想评估和比较双手。如何识别和比较此对象?我的例子有一对,但如果我做了像
这样的事情hand1.select{ |value| hand1.count(value) > 1 }
这会返回一个空数组。如果我做
hand1.detect{ |value| hand1.count(value) > 1 }
它会返回nil
,因为两个部分都不相同。
如果我使用像
这样的手,它会起作用hand1 = ["10 of ♣", "10 of ♣", "J of ♠", "A of ♦", "3 of ♦"]
但是对于我的程序来说,配对是一个问题。
答案 0 :(得分:4)
对字符串执行正则表达式检查,以查看数字是否相等。类似的东西:
hand1 = ["10 of ♣", "5 of ♣", "5 of ♠", "A of ♦", "3 of ♦"]
hand1.select do |card|
value = card[/^\w+/] # This will equal 10, 5, A or 3
hand1.count { |other_card| other_card.match(value) } > 1
end
这将返回手中所有牌的Array
,手中有一张匹配的价值牌。我不清楚这是否是你想要的数据,但你明白了。
不要这样做。在String
中执行所有操作不更简单;您的代码最终会使读/写/测试/调试更加混乱。
使用原始的card
对象,并在Card
类(或者你称之为的任何类)上定义合适的方法。例如,实现可能类似于:
class Card
attr_reader :value, :suit
def initialize(value, suit)
@value = value
@suit = suit
end
# I'm not actually using these two methods here, but read
# them for inspiration!...
def to_s
"#{value} of #{suit}"
end
def ==(other)
value == other.value && suit == other.suit
end
end
hand1 = [Card.new('10', '♣'), ....]
hand1.select do |card|
hand1.count { |other_card| card.value == other_card.value) } > 1
end
让我们更进一步。而不是定义Array
卡,然后在Array
上定义一堆全局方法,为什么不定义一个Hand
类,它包含Card
个对象的列表?
您的最终结果很容易扩展,可能是一个额外的类,如:
class Hand
attr_accessor :cards
def initialize(cards = [])
@cards = cards
end
def matching_values
cards.select do |card|
cards.count { |other_card| card.value == other_card.value) } > 1
end
end
end
然后,您可以处理hand
个对象,并调用hand.matching_values
等方法。没有更多可疑的数组,字符串,正则表达式和全局方法。最好的面向对象编程:)
答案 1 :(得分:0)
如上所述,您可能想要创建一个Card
类。从您的问题中不清楚您要如何评价手牌,但是在这里您可以检查一对:
def pair_for hand
values = hand.map{|c| c.scan(/\w+/).first }
values.detect{|v| values.count(v) == 2 }
end
此方法不处理有两对或三种情况的情况。
如果没有配对,此方法会返回nil
,因此不太好。但是,如果您评估从最高值到最低值的牌,那么nil
可能是一个不错的选择。
答案 2 :(得分:0)
这是一种方法:
def rank(hand)
cards = hand.map(&:split)
ranks = cards.group_by(&:first)
suits = cards.group_by(&:last)
case
when ranks.one? { |k, v| v.count == 2 }
"pair"
when suits.count == 1
"flush"
end
end
player1 = rank ["10 of ♣", "5 of ♣", "5 of ♠", "A of ♦", "3 of ♦"]
=> "pair"
player2 = rank ["10 of ♣", "4 of ♣", "5 of ♣", "A of ♣", "3 of ♣"]
=> "flush"
我做了很简单的事情,还有很多逻辑要做。正如其他人所说的那样,你最好不要和你的班级一起工作。
答案 3 :(得分:0)
关于在五张牌扑克中确定获胜手牌的一些规则我可能是错的(抽牌?螺柱?其他?),但是下面的代码可以很容易地修改以纠正我的假设中的任何错误。< / p>
“踢球者”是决胜局。例如,如果两只手都包含直道,则“踢球者”是具有最高等级的牌(对于3,4,5,6和7,7是“踢球者”)。如果双手都有相同的踢球者,那就是平局。对于一个拥有两个5和两个皇后的牌,第一个踢球者是等级中的较高者(女王),如果另一个有两对的牌的等级相同,则5
成为踢球者。如果双手都有一对女王和一对5,那就是平局。注意多个“赢家”的可能性。
通过关联数组比较指针,我将其称为“手值”。数组的第一个元素是一个非负整数,表示手的类型,0
表示“高牌”(所有牌都有不同的等级而且并非所有套牌都相同),1
表示一对,依此类推,最多8
为同花顺。数组的第二个元素是踢球者(如果有的话),在一个案例中(两对),第三个元素是第二个踢球者,如果第一个没有决定胜利者。数组在Ruby中以字典顺序排序(参见Array#<=>),因此我们可以通过查找哪个数组最大来确定获胜者(或者在平局情况下获胜者)。
我假设一只手就像这样表示:
[['J', :clubs], ['2', :spades], ['J', :diamonds], ['2', :hearts], ['J', :spades]]
这可能需要从其他格式转换(我没有讨论过)。
<强>代码强>
RANK_STR_TO_RANK = %w| 2 3 4 5 6 7 8 9 J Q K A |.
each_with_index.with_object({}) { |(s,i),h| h[s] = i }
#=> {"2"=>0, "3"=>1, "4"=>2, "5"=>3, "6"=>4, "7"=>5,
# "8"=>6, "9"=>7, "J"=>8, "Q"=>9, "K"=>10, "A"=>11}
HIGH_CARD = 0
TWO_OF_KIND = 1
TWO_PAIR = 2
THREE_OF_KIND = 3
STRAIGHT = 4
FLUSH = 5
FULL_HOUSE = 6
FOUR_OF_KIND = 7
STRAIGHT_FlUSH = 8
def winners(hands)
hands_and_values = hands.map { |hand| [hand, hand_value(hand)] }
winning_value = hands_and_values.map(&:last).max
hands_and_values.select { |_, value| value == winning_value }.map(&:first)
end
def hand_value(hand)
ranks, suits = convert(hand).transpose
case
when straight_flush?(ranks, suits) then [STRAIGHT_FlUSH, ranks.max]
when (kicker = four_of_kind?(ranks)) then [FOUR_OF_KIND, kicker]
when (kicker = full_house?(ranks)) then [FULL_HOUSE, kicker]
when flush?(suits) then [FLUSH]
when straight?(ranks) then [STRAIGHT, ranks.max]
when (kicker = three_of_kind?(ranks)) then [THREE_OF_KIND, kicker]
when (kickers = two_pair?(ranks)) then [TWO_PAIR, *kickers]
else [HIGH_CARD, ranks.max]
end
end
def convert(hand)
hand.map { |rank_str, suit| [RANK_STR_TO_RANK[rank_str], suit] }
end
def straight_flush?(ranks, suits)
straight?(ranks) && flush?(suits)
end
def four_of_kind?(ranks)
h = group_by_rank(ranks)
h.key?(4) ? h[4].first : false
end
def full_house?(ranks)
h = group_by_rank(ranks)
(h.key?(3) && h.key?(2)) ? h[3].first : false
end
def flush?(suits)
suits.uniq.size == 1
end
def straight?(ranks)
smallest, largest = ranks.minmax
largest - smallest == 4 && ranks.uniq.size == 5
end
def three_of_kind?(ranks)
h = group_by_rank(ranks)
h.key?(3) ? h[3].first : false
end
def two_pair?(ranks)
h = group_by_rank(ranks)
h.key?(2) && h[2].size==2 ? h[2].sort.reverse : false
end
def one_pair?(ranks)
h = group_by_rank(ranks)
h.key?(2) ? h[2].first : false
end
def group_by_rank(ranks)
ranks.group_by(&:itself).each_with_object({}) { |(k,v),h| (h[v.size] ||= []) << k }
end
示例强>
hands = [[['J', :clubs], ['2', :spades], ['J', :diamonds], ['2', :hearts], ['J', :spades]],
[['Q', :hearts], ['3', :clubs], ['Q', :clubs], ['A', :hearts], ['3', :spades]],
[['4', :hearts], ['5', :spades], ['6', :hearts], ['7', :hearts], ['8', :spades]],
[['5', :clubs], ['9', :clubs], ['K', :clubs], ['A', :clubs], ['8', :clubs]]]
winners(hands)
#=> [
# [["J", :clubs], ["2", :spades], ["J", :diamonds], ["2", :hearts], ["J", :spades]]
# ]
备注强>
在winners
中,中间值如下。
hands_and_values
#=> [[[["J", :clubs], ["2", :spades], ["J", :diamonds], ["2", :hearts], ["J", :spades]],
# [6, 8]],
# [[["Q", :hearts], ["3", :clubs], ["Q", :clubs], ["A", :hearts], ["3", :spades]],
# [2, 9, 1]],
# [[["4", :hearts], ["5", :spades], ["6", :hearts], ["7", :hearts], ["8", :spades]],
# [4, 6]],
# [[["5", :clubs], ["9", :clubs], ["K", :clubs], ["A", :clubs], ["8", :clubs]],
# [5]]
# ]
winning_value
#=> [6, 8]
第一只手的价值是6, 8, 0
,这意味着它是FULL_HOUSE
(6
)3
插孔(rank=>8
)和{ {1}} 2
(2's
)。如果两只手有满屋,那么这三种牌的等级就是“踢球者”,或者是打破平局。