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]