<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _draw_surfaces(self, surface, offset, surfaces):
 """ Draw surfaces onto buffer, then redraw tiles that cover them :param surface: destination :param offset: offset to compensate for buffer alignment :param surfaces: sequence of surfaces to blit """

        surface_blit = surface.blit
        ox, oy = offset
        left, top = self._tile_view.topleft
        hit = self._layer_quadtree.hit
        get_tile = self.data.get_tile_image
        tile_layers = tuple(self.data.visible_tile_layers)
        dirty = list()
        dirty_append = dirty.append

        # TODO: check to avoid sorting overhead
        # sort layers, then the y value
        def sprite_sort(i):
            return i[2], i[1][1] + i[0].get_height()

        surfaces.sort(key=sprite_sort)

        layer_getter = itemgetter(2)
        for layer, group in groupby(surfaces, layer_getter):
            del dirty[:]

            for i in group:
                try:
                    flags = i[3]
                except IndexError:
                    dirty_append(surface_blit(i[0], i[1]))
                else:
                    dirty_append(surface_blit(i[0], i[1], None, flags))

            # TODO: make set of covered tiles, in the case where a cluster
            # of sprite surfaces causes excessive over tile overdrawing
            for dirty_rect in dirty:
                for r in hit(dirty_rect.move(ox, oy)):
                    x, y, tw, th = r
                    for l in [i for i in tile_layers if gt(i, layer)]:

                        if self.tall_sprites and l == layer + 1:
                            if y - oy + th <= dirty_rect.bottom - self.tall_sprites:
                                continue

                        tile = get_tile(x // tw + left, y // th + top, l)
                        tile and surface_blit(tile, (x - ox, y - oy))