A sticker designer builds pictures out of a few simple shapes. A shape answers three questions: contains(x, y) (is the point inside or on the edge?), bbox() (the bounding box (xmin, ymin, xmax, ymax)) and count() (how many basic shapes it is made of).
Write these classes:
Box(x, y, w, h): the rectangle with lower-left corner(x, y), widthwand heighth.Disc(cx, cy, r): the disc with centre(cx, cy)and radiusr.Moved(shape, dx, dy):shapeshifted bydxto the right anddyup.Scaled(shape, k):shapestretched by the factork > 0about the origin(0, 0)(every point(x, y)of the shape goes to(k*x, k*y)).Cut(shape, hole): the points ofshapethat are not inhole; its bounding box isshape's.Group(shapes): all the points of any shape in the non-empty listshapes.
Box and Disc count as 1; the other classes count the basic shapes inside them. Any of these can be put inside any other: a group of moved, scaled groups is still a shape. The tests also wrap a shape of their own, Point(x, y) from the setup, which has the same three methods.
The setup's helper render(shape, x0, y0, x1, y1) draws a shape on the whole-number points of a window: one string per row from y1 down to y0, with # for points inside.
Examples
Input: render(Group([Box(0, 0, 4, 1), Moved(Disc(0, 0, 1), 2, 3)]), 0, 0, 4, 4)
Output: ['..#..',
'.###.',
'..#..',
'#####',
'#####']
Input: s = Scaled(Cut(Box(0, 0, 4, 4), Disc(2, 2, 1)), 2)
s.bbox(), s.count(), s.contains(4, 4), s.contains(1, 7)
Output: ((0, 0, 8, 8), 2, False, True)
Constraints
- Coordinates, sizes and shifts are whole numbers or halves; scale factors are
0.5,2or4. - Shapes are nested at most 30 deep;
renderwindows have at most41 x 41points.
Goals
- Build new shapes out of existing ones instead of writing a subclass for every combination
- Delegate a question to the wrapped object and adjust the answer
- Make wrappers and groups work with any object that has the right methods