I’m always looking for side projects that are the right mix of feasible, fun, relevant to my career, and interesting. Recently I joined Excella’s Ruby Book Club, and started a side project that is just the right mix: A silly retro game in Ruby!
The game is built on the gem gosu
. Gosu does the actual C++ calls to deal with I/O and graphics, and gives you nice, pretty Ruby abstractions so you can draw rectangles and ask whether the spacebar is down. I’m having a blast so far.
Recently I was writing some code that checks whether the y-coordinates for two rectangles overlap. It’s a pretty simple method: Given two integer ranges, do the ranges overlap?
When I first started thinking about this method, I thought of several cases:
- Left overlap, e.g.: [1,4] overlaps [2,5]
- Right overlap, e.g., [1,4] overlaps [0, 3]
- Total overlap, e.g., [1,4] overlaps [2,3]
- Middle overlap, e.g., [1,4] overlaps [0, 5]
- Non-overlap
This seems like a lot for such a little method, so I feel like I’m missing something. I remember a TED talk by Linus Torvalds. The main lesson, I thought, was that special cases are a bad sign. If you’re method checks whether 4 different special cases are true, there may be some underlying condition you could check once. For the overlaps?
method, it was definitely the case. A StackOverflow answer suggested this simple Python snippet:
def is_overlapping(x1,x2,y1,y2):
return max(x1,y1) <= min(x2,y2)
I was thinking of the arguments to my method as the two ranges, but I should have been thinking of them as the two pairs: lows and highs. Here’s the Ruby implementation I eventually settled on:
def overlaps?(lows, highs)
lows.max <= highs.min
end
This has only one case to it: Two ranges overlap if and only if the highest low number is lower than the lowest high number. I am much happier with this implementation. Also, Gosu is a fun gem to work with. I hope to finish up a simple 2-D game sometime this summer. Please feel free to check it out or open a PR.
Till next time, happy learning!
-Will