【问题标题】:Checking if two strings contain the same letters检查两个字符串是否包含相同的字母
【发布时间】:2016-02-16 12:57:17
【问题描述】:

我正在将给定的单词与用户对刽子手游戏的猜测进行比较。 word 是用户想要猜测的字符串,guesses 是与用户猜对的字母连接的字符串。

def initialize(word)
  @word = word 
  @guesses = ''
  @wrong_guesses = ''
end

我正在使用if word.delete(guesses).empty? 来确定获胜条件。每次猜测都会运行此代码,因此我无法找到用户猜测所有正确字母的位置,并且word.delete(guesses) 不会评估为空。

def check_win_or_lose
  if @word.delete(@guesses).empty? 
  #is this a better choice?
  #if @word == self.word_with_guesses 
    return :win
  elsif @wrong_guesses.length >= 7
    return :lose
  else
    return :play
  end
end

它有效,但我觉得这有点 hacky,使用 delete 的副作用。我想知道是否有更好、更简洁的方法来做到这一点。也许使用一些正则表达式?

我已经在程序的另一部分使用了一个函数;不确定它是否比.delete.empty? 方法更快/更好。它返回 word'-' 代替未猜到的字母:

def word_with_guesses
  displayed = @word
  @guesses.length > 0 ? displayed.gsub(/[^#{guesses}]/i, '-') : displayed.gsub(/./, '-')
end

【问题讨论】:

  • 什么是guesses?请发布您的代码 sn-p 以便我们有机会了解。
  • 如果还有什么可以补充的,请告诉我。 guesses 是用户做出的正确猜测,而不是 TOTAL。在适当的条件下(
  • "就像我使用了 .delete() 的副作用" 不,你使用的是 .delete() 的 result . .delete() 没有副作用。我认为使用方法调用的结果没有任何问题(这就是它们的用途)。特别是考虑到根据副本中的答案,这似乎是最快的方式。
  • 如果单词是“foo”并且猜到了“o”,那会暴露一两个“o”吗?

标签: ruby


【解决方案1】:

考虑到guesses 是一个字符列表(至少这是我对刽子手游戏的期望),这样可以:

def won word, guess
    (word.chars & guess) == word.chars.uniq
end

测试一些输入:

word = 'banana'
guess1 = %w(b a m)
guess2 = %w(b a m n)

puts won(word, guess1)
puts won(word, guess2)

#$ ruby words.rb 
#false
#true

【讨论】:

    【解决方案2】:

    最惯用的可能是:

    word.chars.all?{|c| guesses[c]}
    

    【讨论】:

    • 你不是说guesses.include? c吗?
    • 猜测是一个数组吗?我相信这是一个字符串。
    【解决方案3】:

    我认为您最初的解决方案并不像听起来那么糟糕。问题是“删除”和“清空”?显然与手头的问题无关。任何阅读代码的人都需要了解它们的相关性。

    一个简单的解决方法是引入一个解释变量以明确为什么deleteempty?是相关的。


    从概念上讲,我认为您完全符合核心思想:将“实际猜测”集合与“必要猜测”集合进行比较。

    当没有任何东西可以猜测时,玩家获胜——也就是说,当一组实际猜测包含所有必要的猜测时。

    您的necessary_guesses.delete(actual_guesses).empty? 解决方案检查actual_guesses 是否是necessary_guesses 的子集。你可以用几种不同的方式来写它,这取决于你想强调什么:

    unguessed_characters = necessary_guesses.delete(actual_guesses)
    win if unguessed_characters.empty?
    

    或:

    unguessed_characters = necessary_guesses.chars - actual_guesses.chars
    win if unguessed_characters.empty?
    

    如果您愿意使用实际的 Set 对象,您甚至可以编写如下内容:

    win if set_of_necessary_guesses.subset?(set_of_actual_guesses)
    

    简而言之,计算机对您的解决方案很满意,但专注于名称可能会让人类更轻松。

    【讨论】:

      【解决方案4】:

      考虑到一个字母的猜测会暴露该字母在秘密单词中的所有实例,您可以这样写:

      (word.chars - guesses).empty?
      

      编辑:经过反思,您似乎需要一种方法,该方法采用 one 猜测并返回 :win:lose:continue 的参数,考虑到所有先前的猜测。如果是这样,您可以执行以下操作。

      代码

      MAX_INCORRECT_GUESSES = 7
      

      在开头执行:

      def init(word)
        @word = word 
        @nbr_incorrect = 0
      end 
      

      每次猜测后执行,直到返回:win:lose

      def win_lose_or_continue(guess)
        if @word.include?(guess)
          @word.delete!(guess)
          return @word.empty? ? :win : :continue
        end
        @nbr_incorrect += 1
        @nbr_incorrect == MAX_INCORRECT_GUESSES ? :lose : :continue
      end
      

      示例

      首先,一个显示结果的助手:

      def results(guesses)
        puts "@word = #{@word}"
        guesses.each_char.each do |c|
          puts "win_lose_or_continue(#{c}) = #{win_lose_or_continue(c)}, @word now #{@word}"
        end
      end
      
      init('cat')
      guesses = "argptc"
      results(guesses)
      
      @word = cat
      win_lose_or_continue(a) = continue, @word now ct
      win_lose_or_continue(r) = continue, @word now ct
      win_lose_or_continue(g) = continue, @word now ct
      win_lose_or_continue(p) = continue, @word now ct
      win_lose_or_continue(t) = continue, @word now c
      win_lose_or_continue(c) = win, @word now 
      
      init('cat')
      guesses = "argptbfjk"
      results(guesses)
      
      @word = cat
      win_lose_or_continue(a) = continue, @word now ct
      win_lose_or_continue(r) = continue, @word now ct
      win_lose_or_continue(g) = continue, @word now ct
      win_lose_or_continue(p) = continue, @word now ct
      win_lose_or_continue(t) = continue, @word now c
      win_lose_or_continue(b) = continue, @word now c
      win_lose_or_continue(f) = continue, @word now c
      win_lose_or_continue(j) = continue, @word now c
      win_lose_or_continue(k) = lose, @word now c
      

      【讨论】:

        【解决方案5】:

        我想我会这样做:

        word.chars.sort == guesses.sort
        

        编辑:经过进一步考虑,我可能会这样做:

        def initialize(word)
          @word = word
          @letters_remaining = @word.chars
          @correct_guesses = []
          @wrong_guesses = []
        end
        
        def guess(letter)
          if found_idx = @letters_remaining.index(letter)
            @correct_guesses << @letters_remaining.delete_at(found_idx)
            return :win if @letters_remaining.empty?
          else
            @wrong_guesses << letter
            return :lose if @wrong_guesses.size >= MAX_WRONG_GUESSES
          end
          :play
        end
        

        这里发生的是我们保留了一个@letters_remaining 数组,在initialize 中填充了单词的字母。每次猜测时,我们都会在@letters_remaining 中查找猜测的字母。如果找到,我们将其删除并添加到@correct_guesses,然后检查@letters_remaining是否为空。如果是,则用户赢了。

        如果猜到的字母不在@letters_remaining 中,我们将其添加到@wrong_guesses 并检查后者的大小以确定用户是否丢失了。

        如果以上都不成立,则用户继续播放。

        您会注意到我将猜测等存储在数组而不是字符串中。由于我们的大部分逻辑都涉及字母而不是整个字符串,因此这更有意义。

        编辑 2: 上面假设每个猜测一次只“填写”一个字母。如果您希望每个猜测都填写所有匹配的字母,它看起来像这样:

        def guess(letter)
          if @letters_remaining.delete(letter)
            @correct_guesses << letter
            return :win if @letters_remaining.empty?
          else
            @wrong_guesses << letter
            return :lose if @wrong_guesses.size >= MAX_WRONG_GUESSES
          end
          :play
        end
        

        【讨论】:

        • 看来您假设如果单词是“foo”并且猜到了“o”,则只有一个“o”被暴露(比所有“o”都暴露的情况更具挑战性)。您可能希望澄清您的假设。
        【解决方案6】:

        另一个技巧:您可以通过使用位操作来使其更简洁。 对 ruby​​ 不太了解,但这是它在 C++ 中的样子

        long int checker = 0;
        for(int i=0;i<word.length();i++)
        {
            long int t = word[i]-'a';
            t = 1<<t;
            if((t&checker)==0)
            {
                checker |= t;
            }
        }
        for(int i=0;i<guesses.length();i++)
        {
            long int t = guesses[i]-'a';
            t = 1<<t;
            if((t&checker)==0){
                return false;
            }
        }
        return true;
        

        也许内置函数可以在更短的时间内优雅地解决,但如果你想定义自己的函数,你可以试试这个。希望这会有所帮助

        【讨论】:

        • “让它更简洁” 是的,而且完全晦涩难懂。我也看不出这比a.chars.sort == b.sort 更“简洁”。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-16
        • 2015-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多