我构建了一个mastermind版本,用于检查用户的输入,并根据用户对获胜序列的猜测程度提供反馈。如果您不熟悉游戏,则会得到反馈,表明在同一索引中有多少字符被正确猜测,并且序列中猜到了多少个字符,但索引错误。如果猜测中有重复项,那么除非它们对应于密码中相同数量的重复项,否则您不会计算额外值。
示例:如果序列是[" G"," G"," G"," Y"]并且用户猜测[" G"," Y"," G"," G"]然后您想要返回2秘密序列中包含的不同索引的项目使用相同的索引和2。
另一个例子:如果顺序是[" X"," R"," Y"," T"]和用户猜测[" T"," T"," Y"," Y"]然后你返回1为猜测的字符在序列中但索引错误时的索引1相同。
无论如何,对我而言,这不是一个简单的问题需要解决。这是我用来使它工作的代码,但它并不优雅。肯定有更好的办法。我希望有人能告诉我我在这里失踪了什么? Ruby的新手......
def index_checker(input_array, sequence_array)
count = 0
leftover_input = []
leftover_sequence = []
input.each_with_index do |char, idx|
if char == sequence[idx]
count += 1
else
leftover_input << char
leftover_sequence << sequence[idx]
end
end
diff_index_checker(leftover_input, leftover_sequence, count)
end
def diff_index_checker(input, sequence, count)
count2 = 0
already_counted = []
input.each do |char|
if sequence.include?(char) && !already_counted.include?(char)
count2 += 1
already_counted << char
end
end
[count, count2]
end
答案 0 :(得分:2)
这是一个干净的Ruby解决方案,用惯用的Ruby面向对象风格编写:
class Mastermind
def initialize(input_array, sequence_array)
@input_array = input_array
@sequence_array = sequence_array
end
def matches
[index_matches, other_matches]
end
def results
[index_matches.size, other_matches.size]
end
private
attr_reader :input_array, :sequence_array
def index_matches
input_array.select.with_index { |e, i| e == sequence_array[i] }
end
def other_matches
non_exact_input & non_exact_sequence
end
def non_exact_input
array_difference(input_array, index_matches)
end
def non_exact_sequence
array_difference(sequence_array, index_matches)
end
# This method is based on https://stackoverflow.com/a/3852809/5961578
def array_difference(array_1, array_2)
counts = array_2.inject(Hash.new(0)) { |h, v| h[v] += 1; h }
array_1.reject { |e| counts[e] -= 1 unless counts[e].zero? }
end
end
您可以按如下方式使用此课程:
>> input_array = ["G","G","G","Y"]
>> sequence_array = ["G", "Y","G","G"]
>> guess = Mastermind.new(input_array, sequence_array)
>> guess.results
#> [2, 2]
>> guess.matches
#> [["G", "G"], ["G", "Y"]]
以下是它的工作原理。首先,一切都进入了一个名为Mastermind的课程。我们为类创建一个构造函数(在Ruby中是一个名为initialize
的方法),我们接受两个参数:输入数组(用户猜测)和序列数组(答案)。
我们将每个参数设置为一个实例变量,该变量以@
开头表示。然后我们使用attr_reader
为@input_array
和@sequence_array
创建getter方法,这样我们就可以通过从任何实例方法中调用input_array
和sequence_array
来获取值上课。
然后我们定义了两个公共方法:matches
(返回精确匹配的数组和其他匹配的数组(匹配但索引错误的匹配)和results
(返回这两个数组的计数。)
现在,在我们班的private
部分,我们可以定义逻辑的内容。每个方法都有一个特定的工作,每个方法都被命名为(希望)帮助读者了解它正在做什么。
index_matches
返回input_array的一个子集,其元素与sequence_array完全匹配。
other_matches
返回input_array的一个子集,其元素与sequence_array完全匹配,但在错误的索引处匹配。
other_matches
依赖于non_exact_input
和non_exact_sequence
,每个都是使用array_difference
方法计算的,我从另一个SO答案中复制了该方法。 (没有方便的Ruby方法允许我们从一个数组中减去一个数组而不删除重复项。)
答案 1 :(得分:1)
<强>代码强>
def matches(hidden, guess)
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
guess_counts = counting_hash(guess.values_at *indices_wo_match)
[hidden.size - indices_wo_match.size, guess_counts.reduce(0) { |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min }]
end
def counting_hash(arr)
arr.each_with_object(Hash.new(0)) { |s, h| h[s] += 1 }
end
<强>实施例强>
matches ["G","G","G","Y"], ["G", "Y","G","G"]
#=> [2, 2]
matches ["X","R","Y","T"] , ["T","T","Y","Y"]
#=> [1, 1]
<强>解释强>
步骤如下。
hidden = ["G","G","G","Y"]
guess = ["G", "Y","G","G"]
保存i
的索引hidden[i] != guess[i]
。
indices_wo_match = hidden.each_index.reject { |i| hidden[i] == guess[i] }
#=> [1, 3]
请注意,值相等的索引数如下:
hidden.size - indices_wo_match.size
#=> 2
现在计算guess
的剩余元素的数量,这些元素与hidden
的其余值之一配对,具有相同的值。首先计算hidden
的每个唯一元素的实例数,然后对guess
执行相同操作。
hidden_counts = counting_hash(hidden.values_at *indices_wo_match)
#=> {"G"=>1, "Y"=>1}
guess_counts = counting_hash(guess.values_at *indices_wo_match)
#=> {"Y"=>1, "G"=>1}
要了解counting_hash
的工作原理,请参阅Hash::new,尤其是提供默认值作为new
参数的效果说明。简而言之,如果定义了哈希h = Hash.new(3)
,那么如果h
没有密钥k
,则h[k]
会返回默认值,此处为3
(哈希没有改变。)
现在计算guess
元素在同一索引处不等于hidden
的值的匹配数以及具有相同元素的hidden
元素对的匹配数值。
val_matches = guess_counts.reduce(0) do |tot, (k, cnt)|
tot + [hidden_counts[k], cnt].min
end
#=> 2
最后,返回感兴趣的值。
[hidden.size - indices_wo_match.size, val_matches]
#=> [2, 2]
在上面的代码中,我已经替换了变量val_matches
。
使用Ruby 2.4+,可以使用Enumerable#sum替换
guess_counts.reduce(0) { |tot, (k, cnt)| tot + [hidden_counts[k], cnt].min }
与
guess_counts.sum { |k, cnt| [hidden_counts[k], cnt].min }
答案 2 :(得分:1)
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
semi = secret.uniq.sum { |s| [secret.count(s), guess.count(s)].min } - full
[full, semi]
end
演示:
> judge(["G","G","G","Y"], ["G","Y","G","G"])
=> [2, 2]
> judge(["X","R","Y","T"], ["T","T","Y","Y"])
=> [1, 1]
一个较短的选择,虽然我发现不太清楚:
full = secret.zip(guess).count(&:uniq!)
答案 3 :(得分:1)
我更喜欢我的另一个答案,因为它的简单性,但是如果有人想将它用于比Mastermind更大的数组,那么这个会更快。
// Example: Promote PKPaymentAuthorizationViewController to optional so that we can verify
// that our paymentRequest is valid. Otherwise, an invalid paymentRequest would crash our app.
if let vca = PKPaymentAuthorizationViewController(paymentRequest: paymentRequest) as PKPaymentAuthorizationViewController?
{
...logic...
} else {
->this is what i get when using pounds or anything else<-
}
演示:
def judge(secret, guess)
full = secret.zip(guess).count { |s, g| s == g }
pool = secret.group_by(&:itself)
[full, guess.count { |g| pool[g]&.pop } - full]
end