比较字符串数组

时间:2016-07-17 01:38:58

标签: arrays ruby

我正在开发一副纸牌。我的手是一串字符串。例如:

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 ♦"] 

但是对于我的程序来说,配对是一个问题。

4 个答案:

答案 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_HOUSE63插孔(rank=>8)和{ {1}} 22's)。如果两只手有满屋,那么这三种牌的等级就是“踢球者”,或者是打破平局。