Reputation: 57
I am struggling with my code to write a simple code-breaking game. There is a hidden code:
code = ["a","b","b","c"]
My program asks for user input, then stores it in a variable. I want to compare user input against the secret code variable and give the user feedback: 1 for a good letter in good place, 0 for good letter in wrong place, "-" for wrong letter.
I came up with something like this:
feedback = []
input.each_with_index do |v,i|
if v == code.fetch(i)
feedback << "1"
else
feedback << "-"
end
end
It works OK when it compares elements at the same index. I have no idea how I can find elements that are in the code array, but not in the same index and give feedback to the user.
For example:
code = ["a","b","b","c"]
input = ["b","b","a","z"]
feedback = ["0","1","0","-"]
Upvotes: 1
Views: 93
Reputation: 54223
This code works with the 3 examples you mentioned.
2 passes are used because the 1
s must be returned before the 0
s :
def give_feedback(input, code)
feedback = Array.new(input.size) { '-' }
code2 = code.dup
input.each_with_index do |letter, index|
if letter == code[index]
feedback[index] = '1'
code2[index] = nil
end
end
input.each_with_index do |letter, index|
next if feedback[index] == '1'
found = code2.index(letter)
if found
feedback[index] = '0'
code2[found] = nil
end
end
feedback
end
p give_feedback(%w(b b a z), %w(a b b c))
# ["0", "1", "0", "-"]
p give_feedback(%w(a a a a), %w(a b b c))
# ["1", "-", "-", "-"]
p give_feedback(%w(c c b a), %w(a b b c))
# ["0", "-", "1", "0"]
Upvotes: 1
Reputation: 121000
Just out of curiosity:
[code, input].map { |a| (0...a.size).zip(a).to_h }
.reduce do |e, acc|
c = acc.values.dup
acc.merge(e) do |_, v1, v2|
case (c.delete_at(c.index(v2)) rescue nil)
when v1 then "1"
when nil then "-"
else "0"
end
end
end.values
Upvotes: 0
Reputation: 4801
You can use the include?
method to see if that character is in the list at a different index. Something like this:
input.each_with_index do |v,i|
if v == code.fetch(i)
feedback << "1"
elsif code.include?(v)
# right character, wrong spot
feedback << "0"
else
feedback << "-"
end
end
Upvotes: 0
Reputation: 1733
You can use zip
and map
to make it a little more functional. include?
will check to see if the input is in code
code = %w(a b b c)
input = %w(b b a z)
result = code.zip(input).map do |c, i|
if c == i
'1'
elsif code.include?(i)
'0'
else
'-'
end
end
puts result.to_s
Upvotes: 0
Reputation: 4440
One more solution
code = ["a","b","b","c"]
input = ["b","b","a","z"]
feedback = input.map.with_index do |num, ind|
if code.include? num
code[ind] == num ? '1' : '0'
else
'-'
end
end
=> ['0', '1', '0', '-']
if you want define feedback
before, just edit 1st variant to:
code = ["a","b","b","c"]
input = ["b","b","a","z"]
feedback = []
input.each_with_index do |num, ind|
if code.include? num
feedback << (code[ind] == num ? '1' : '0')
else
feedback << '-'
end
end
result would be the same
Upvotes: 0