function remove_and_drop(self, matches)
    -- Remove matched pieces
    for _, pos in ipairs(matches) do
        self.grid[pos.y][pos.x] = nil
    end

    -- Drop pieces down into empty spaces
    for col = 1, self.cols do
        local empty = 0
        for row = self.rows, 1, -1 do
            if self.grid[row][col] == nil then
                empty = empty + 1
            elseif empty > 0 then
                self.grid[row + empty][col] = self.grid[row][col]
                self.grid[row][col] = nil
            end
        end
        -- Fill top empty spaces with new pieces
        for row = 1, empty do
            self.grid[row][col] = {
                type = self.piece_types[
                    math.random(#self.piece_types)]
            }
        end
    end
end