【问题标题】:Deck#shuffle and Deck#shuffle! doing the same thing甲板#shuffle 和甲板#shuffle!做同样的事情
【发布时间】:2014-05-16 22:24:43
【问题描述】:

我正在用 Ruby 编写一个纸牌游戏框架,但我发现了一个问题。我做了一个洗牌方法,可以混合卡片,效果很好。但是我叫 Deck#shuffle 而不是 Deck#shuffle!它让牌组一直洗牌,这是我不想要的。

我还觉得奇怪的是,当我添加 :riffle 作为参数时,然后 shuffle 不会让牌组保持我想要的洗牌。

对于如何防止 Deck#shuffle 修改牌组的任何帮助,我将不胜感激。谢谢!

这是我的代码(其中的一部分,如果有人也需要我,我可以发布其余部分):

class Deck

    def initialize
        @cards = []
        (1..4).each { |suit|
            (1..13).each { |rank|
                @cards << Card.new(rank, suit)
            }
        }
    end

    def size
        @deck.length
    end

    def shuffle!(type = :random, precision = 100)
        case type
        when :random
            @cards.shuffle!
        when :riffle, :farro
            i = 0
            first, second = cut
            @cards = []
            while size != 52
                pile = (i.even? ? first : second)
                if pile.empty?
                        pile = (pile == first ? second : first)
                end
                add_card(pile.pop)
                i += 1  if (1..precision) === rand(1..100)
            end
        else
            warn "Invalid shuffle method."
        end
    end

    def shuffle(type = :random, precision = 100)
        dup.shuffle!(type, precision)
    end

    def add_card(card)
        @cards << card
    end

end

deck = Deck.new
deck.shuffle

p deck.cards.map(&:to_a)

【问题讨论】:

    标签: ruby shuffle


    【解决方案1】:

    您的 Deck 类有一个实例变量 - @cards - 它保存卡片。 @cards 实际上是对卡片数组的引用。

    你没有实现Deck#dup,当你使用它时你使用Object#dup,它做一个浅拷贝——它将所有实例变量作为引用拷贝。 它不会复制实例变量!

    这意味着duped Deck 拥有一个不同的 @cards 变量,该变量引用相同 数组作为原始Deck 的@ 987654330@。当您 shuffle 它时,相同的数组将被打乱。它通过不同的引用变量访问,但它仍然是同一个数组。

    如果您尝试使用:riffle:farro 洗牌,它不会影响原始对象,因为这些洗牌类型中的那些您会执行@cards = [],这会将@cards 设置为一个新数组。

    不过,我想说,即使你没有 :random 类型,实现仍然是错误的 - 因为新的 @cards 与旧的分离不应该在 shuffle! 中 -它应该在dup

    因此,您需要覆盖dup 方法并使其重复@cards。您可能还想更改 initialize 以支持此功能:

    def initialize(cards = nil)
        if cards
            @cards = cards
        else
            @cards = []
            (1..4).each { |suit|
                (1..13).each { |rank|
                    @cards << Card.new(rank, suit)
                }
            }
        end
    end
    
    def dup
        Deck.new(@cards.dup)
    end       
    

    【讨论】:

      【解决方案2】:

      当你对一个对象执行dup 时,you are only creating a shallow copy of that object。这意味着当您获得一个新的 Deck 实例时,您的原始实例和这个新的 Deck 都将引用相同的 @cards 实例变量。

      【讨论】:

        【解决方案3】:

        这一行...

        dup.shuffle!(type, precision)
        

        ... 正在创建 Deck 对象的浅表副本。

        虽然它有自己的实例变量@cards,但该实例变量实际上引用的对象与原始对象中的实例变量相同。

        【讨论】:

          猜你喜欢
          • 2019-07-17
          • 1970-01-01
          • 2014-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多