检查两个字符串是否包含相同的字母

时间:2016-02-16 01:11:58

标签: ruby

我正在将一个给定的单词与用户对刽子手游戏的猜测进行比较。 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

6 个答案:

答案 0 :(得分:3)

考虑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

答案 1 :(得分:1)

我想我会这样做:

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:以上假设每次猜测&#34;填写&#34;一次只能写一封信。如果您希望每个猜测都填写所有匹配的字母,它将看起来像这样:

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

答案 2 :(得分:1)

大多数惯用语可能是:

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

答案 3 :(得分:1)

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

(word.chars - guesses).empty?

编辑:在反思中,您似乎可能需要一个方法,该方法采用一个猜测的参数并返回: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

答案 4 :(得分:1)

我认为你的初始解决方案并不像听起来那么糟糕。问题是“删除”和“空”?与手头的问题无明显关系。阅读代码的任何人都需要联系他们相关的原因。

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

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

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

您的necessary_guesses.delete(actual_guesses).empty?解决方案会检查actual_guessesnecessary_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)

简而言之,计算机对您的解决方案感到满意,但专注于名称可以使人类更容易。

答案 5 :(得分:0)

另一个黑客:你可以通过使用位操作使其更简洁。 不太了解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;

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