How can I check if 2 ranges intersect in any way in ruby?
You can check if one range includes begin or end of another one:
r1 = (1..5)
r2 = (4..8)
r1.include?(r2.begin) || r1.include?(r2.end) || r2.include?(r1.begin) || r2.include?(r1.end)
In your case:
r1 = (sprite1[1]..sprite1[1] + sprite1[0].width)
r2 = (sprite2[1]..sprite2[1] + sprite2[0].width)
r1.include?(sprite2[1]) || r1.include?(sprite2[1] + sprite2[0].width) ||
r2.include(sprite1[1]) || r2.include(sprite1[1] + sprite1[0].width)
assuming that the ranges are not endless.
There are a number of cases to consider, as pointed out by @muistooshort in a comment.
I assume that the elements of the ranges are integers, as in the example.
Code
The easiest way to determine if two ranges intersect is to negate an expression that determines if they don't intersect.
def overlap?(r1, r2)
return false if r1.size.zero? || r2.size.zero?
!(range_last(r1) < r2.begin || range_last(r2) < r1.begin)
end
def range_last(r)
return Float::INFINITY if r.end==Float::INFINITY || r.end.nil?
r.include?(r.end) ? r.end : r.end-1
end
Examples
overlap? 1..3, 2..5 #=> true
overlap? 1..3, 4..5 #=> false
overlap? 3..1, 0..5 #=> false
overlap? 1..4, 4..8 #=> true
overlap? 1...4, 4..8 #=> false
overlap? 4.., 1..4 #=> true
overlap? 4.., 1...4 #=> false
overlap? -Float::INFINITY..Float::INFINITY, 1..1 #=> true
overlap? -Float::INFINITY..7, 7..8 #=> true
overlap? -Float::INFINITY...7, 7..8 #=> false
overlap? -4..Float::INFINITY, -6..-4 #=> true
overlap? -4..Float::INFINITY, 6...-4 #=> false
Observe that the range 3..1
in the 3rd example is empty.
Note also:
range_last(1..) #=> Infinity
range_last(1..Float::INFINITY) #=> Infinity
range_last(1..3) #=> 3
range_last(1...3) #=> 2
If the two ranges, r1
and r2
, are finite and of the two-dot variety one can replace range_last(r)
with r.last
.