indicate that the player was bought at the specified cost

        :param Player player: player to buy
        :param int cost: cost to pay

        :raises InsufficientFundsError: if owner doesn't have the money
        :raises NoValidRosterSlotError: if owner doesn't have a slot this player could fill
        :raises AlreadyPurchasedError: if owner already bought this player

def buy(self, player, cost):
        """
        indicate that the player was bought at the specified cost

        :param Player player: player to buy
        :param int cost: cost to pay

        :raises InsufficientFundsError: if owner doesn't have the money
        :raises NoValidRosterSlotError: if owner doesn't have a slot this player could fill
        :raises AlreadyPurchasedError: if owner already bought this player
        """
        if cost > self.max_bid():
            raise InsufficientFundsError()
        elif not any(roster_slot.accepts(player) and roster_slot.occupant is None for roster_slot in self.roster):
            raise NoValidRosterSlotError()
        elif self.owns(player):
            raise AlreadyPurchasedError()

        self.money -= cost
        self._remaining_picks -= 1
        self._owned_player_ids.add(player.player_id)
        self._slot_in(player, cost)