#### rectangles.py

 ```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68``` ```from itertools import combinations from operator import attrgetter class Rectangle: CORNER = '+' HORIZONTAL = '-' VERTICAL = '|' # Valid characters for horizontal and vertical sides # These are allowed to include corners VALID_HORIZONTAL_CHARS = frozenset(CORNER + HORIZONTAL) VALID_VERTICAL_CHARS = frozenset(CORNER + VERTICAL) def __init__(self, chars): self._chars = chars @property def has_sides(self): """Make sure rectangle has all its sides""" horizontals = set(self._chars[0] + self._chars[-1]) verticals = set( ''.join(line[0] + line[-1] for line in self._chars) ) return ( horizontals <= self.VALID_HORIZONTAL_CHARS and verticals <= self.VALID_VERTICAL_CHARS ) @classmethod def get(cls, tl, tr, bl, br, lines): """ Try to make a rectangle from 4 coordinates If tl, tr, bl, br line up as a non-zero rectangle, return a corresponding Rectangle object Otherwise, return None """ corners_line_up = ( tl[0] == tr[0] and bl[0] == br[0] and tl[1] == bl[1] and tr[1] == br[1] ) if corners_line_up: top, left = tl bottom, right = br if top < bottom and left < right: return Rectangle( [row[left:right+1] for row in lines[top:bottom+1]] ) def count(lines=''): # Find all corner positions corners = ( (row_num, col_num) for row_num, line in enumerate(lines) for col_num, char in enumerate(line) if char == Rectangle.CORNER ) # Search combinations of corners to find rectangles rects = ( Rectangle.get(*points, lines) for points in combinations(corners, 4) ) # Get the number this which have complete sides return sum(r.has_sides for r in rects if r) ```