I'll opt to loop the array instead of using a case
statement, like this:
def lock(a,b,c,d)
combination = [[3,5,7], [2], [5,6], [8,9,0]]
attempt = [a,b,c,d]
combination.each_with_index do |position, i|
return "locked" unless position.include?(attempt[i])
end
"unlocked"
end
Outputs:
lock(3, 2, 5, 8)
#=> "unlocked"
lock(5, 2, 5, 0)
#=> "unlocked"
lock(5, 2, 6, 8)
#=> "unlocked"
lock(7, 2, 5, 8)
#=> "unlocked"
lock(7, 2, 6, 9)
#=> "unlocked"
lock(1, 2, 3, 4)
#=> "locked"
Why your solution fails?
Just as Hamms pointed out in his comment, the when
with [(3||5||7), 2, (5||6), (8||9||0)]
evaluates to [3, 2, 5, 8]
. That is because each expression in parenthesis is evaluated first, so, breaking it down, it would be:
(3 || 5 || 7)
#=> 3
2
#=> 2
(5 || 6)
#=> 5
(8 || 9 || 0)
#=> 8
This is because ||
is evaluating if value is truthy, that is, is neither nil
nor false
. As soon as the expression gets to a truthy value, it will return that value and look no further. So any number will evaluate as truthy, and you will always get the first number of each expression as a result.
Back to your case
statement, it is the exact same thing as writing it like:
case [a,b,c,d]
when [3, 2, 5, 8]
"unlocked"
else
"locked"
end
Now consider that a case
statement will evaluate if the object in case
is equal with the one in each when
. So in, your case will be something like:
[a,b,c,d] === [3, 2, 5, 8]
Which will return true
(and "unlocked"
) only when you call lock(3, 2, 5, 8)
.
Also consider that you could use multiple values with when
, so using something like this will work:
case [a,b,c,d]
when [3, 2, 5, 8], [5, 2, 5, 0] then "unlocked"
else "locked"
end
In which when
will be equivalent to doing:
[a,b,c,d] === [3, 2, 5, 8] || [5, 2, 5, 0]