import unittest ################################################################################ # Solution ################################################################################ # bottom :: Rectangle -> Int def bottom(x): return x.get('bottom_y') # top :: Rectangle -> Int def top(x): return bottom(x) + x.get('height') # left :: Rectangle -> Int def left(x): return x.get('left_x') # right :: Rectangle -> Int def right(x): return left(x) + x.get('width') # sort_highest :: Rectangle -> Rectangle -> (Rectangle, Rectangle) def sort_highest(x, y): if top(x) >= top(y): return x, y else: return y, x # sort_leftmost :: Rectangle -> Rectangle -> (Rectangle, Rectangle) def sort_leftmost(x, y): if left(x) <= left(y): return x, y else: return y, x # rectify :: Int -> Int -> Int -> Int -> Rectify def rectify(top=None, bottom=None, left=None, right=None): assert top >= bottom assert left <= right return { 'left_x': left, 'bottom_y': bottom, 'width': right - left, 'height': top - bottom, } # empty_rect :: Rectangle def empty_rect(): return { 'left_x': None, 'bottom_y': None, 'width': None, 'height': None, } # find_rectangular_overlap :: Rectangle -> Rectangle -> Maybe(Rectangle) def find_rectangular_overlap(x, y): ha, hb = sort_highest(x, y) la, lb = sort_leftmost(x, y) if bottom(hb) <= top(hb) <= bottom(ha) <= top(ha): return empty_rect() if left(la) <= right(la) <= left(lb) <= right(lb): return empty_rect() # We should have an intersection here. verts = [bottom(ha), top(ha), bottom(hb), top(hb)] verts.sort() horzs = [left(la), right(la), left(lb), right(lb)] horzs.sort() return rectify(top=verts[2], bottom=verts[1], left=horzs[1], right=horzs[2]) ################################################################################ # Tests ################################################################################ class Test(unittest.TestCase): def test_overlap_along_both_axes(self): rect1 = { 'left_x': 1, 'bottom_y': 1, 'width': 6, 'height': 3, } rect2 = { 'left_x': 5, 'bottom_y': 2, 'width': 3, 'height': 6, } expected = { 'left_x': 5, 'bottom_y': 2, 'width': 2, 'height': 2, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_one_rectangle_inside_another(self): rect1 = { 'left_x': 1, 'bottom_y': 1, 'width': 6, 'height': 6, } rect2 = { 'left_x': 3, 'bottom_y': 3, 'width': 2, 'height': 2, } expected = { 'left_x': 3, 'bottom_y': 3, 'width': 2, 'height': 2, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_both_rectangles_the_same(self): rect1 = { 'left_x': 2, 'bottom_y': 2, 'width': 4, 'height': 4, } rect2 = { 'left_x': 2, 'bottom_y': 2, 'width': 4, 'height': 4, } expected = { 'left_x': 2, 'bottom_y': 2, 'width': 4, 'height': 4, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_touch_on_horizontal_edge(self): rect1 = { 'left_x': 1, 'bottom_y': 2, 'width': 3, 'height': 4, } rect2 = { 'left_x': 2, 'bottom_y': 6, 'width': 2, 'height': 2, } expected = { 'left_x': None, 'bottom_y': None, 'width': None, 'height': None, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_touch_on_vertical_edge(self): rect1 = { 'left_x': 1, 'bottom_y': 2, 'width': 3, 'height': 4, } rect2 = { 'left_x': 4, 'bottom_y': 3, 'width': 2, 'height': 2, } expected = { 'left_x': None, 'bottom_y': None, 'width': None, 'height': None, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_touch_at_a_corner(self): rect1 = { 'left_x': 1, 'bottom_y': 1, 'width': 2, 'height': 2, } rect2 = { 'left_x': 3, 'bottom_y': 3, 'width': 2, 'height': 2, } expected = { 'left_x': None, 'bottom_y': None, 'width': None, 'height': None, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) def test_no_overlap(self): rect1 = { 'left_x': 1, 'bottom_y': 1, 'width': 2, 'height': 2, } rect2 = { 'left_x': 4, 'bottom_y': 6, 'width': 3, 'height': 6, } expected = { 'left_x': None, 'bottom_y': None, 'width': None, 'height': None, } actual = find_rectangular_overlap(rect1, rect2) self.assertEqual(actual, expected) unittest.main(verbosity=2)