Пример #1
0
def make_bid(player, current_gameboard, asset, current_bid):
    """
    Decide the amount you wish to bid for asset in auction, given the current_bid that is currently going. If you don't
    return a bid that is strictly higher than current_bid you will be removed from the auction and won't be able to
    bid anymore. Note that it is not necessary that you are actually on the location on the board representing asset, since
    you will be invited to the auction automatically once a player who lands on a bank-owned asset rejects buying that asset
    (this could be you or anyone else).
    :param player: A Player instance. You should expect this to be the player that is 'making' the decision (i.e. the player
    instantiated with the functions specified by this decision agent).
    :param current_gameboard: A dict. The global data structure representing the current game board.
    :param asset: An purchaseable instance of Location (i.e. real estate, utility or railroad)
    :param current_bid: The current bid that is going in the auction. If you don't bid higher than this amount, the bank
    will remove you from the auction proceedings. You could also always return 0 to voluntarily exit the auction.
    :return: An integer that indicates what you wish to bid for asset
    """

    if current_bid < asset.price:
        new_bid = current_bid + (asset.price - current_bid) / 2
        if new_bid < player.current_cash:
            return new_bid
        else:  # We are aware that this can be simplified with a simple return 0 statement at the end. However in the final baseline agent
            # the return 0's would be replaced with more sophisticated rules. Think of them as placeholders.
            return 0  # this will lead to a rejection of the bid downstream automatically
    elif current_bid < player.current_cash and agent_helper_functions.will_property_complete_set(
            player, asset, current_gameboard):
        # We are prepared to bid more than the price of the asset only if it doesn't result in insolvency, and
        # if we can get a monopoly this way
        return current_bid + (player.current_cash - current_bid) / 4
    else:
        return 0  # no reason to bid
Пример #2
0
def make_buy_property_decision(player, current_gameboard, asset):
    """
    The agent decides to buy the property if:
    (i) it can 'afford' it. Our definition of afford is that we must have at least go_increment cash balance after
    the purchase.
    (ii) we can obtain a full color set through the purchase, and still have positive cash balance afterwards (though
    it may be less than go_increment).

    :param player: A Player instance. You should expect this to be the player that is 'making' the decision (i.e. the player
    instantiated with the functions specified by this decision agent).
    :param current_gameboard: A dict. The global data structure representing the current game board.
    :return: A Boolean. If True, then you decided to purchase asset from the bank, otherwise False. We allow you to
    purchase the asset even if you don't have enough cash; however, if you do you will end up with a negative
    cash balance and will have to handle that if you don't want to lose the game at the end of your move (see notes
    in handle_negative_cash_balance)
    """
    decision = False
    if player.current_cash - asset.price >= current_gameboard[
            'go_increment']:  # case 1: can we afford it?
        print player.player_name, ': I will attempt to buy ', asset.name, ' from the bank.'
        decision = True
    elif asset.price <= player.current_cash and \
            agent_helper_functions.will_property_complete_set(player,asset,current_gameboard):
        print player.player_name, ': I will attempt to buy ', asset.name, ' from the bank.'
        decision = True

    return decision
Пример #3
0
def make_out_of_turn_move(player, current_gameboard, allowable_moves, code):
    """
    The agent is in the out-of-turn phase and must decide what to do (next). This simple dummy agent skips the turn, and
     doesn't do anything.
    :param player: A Player instance. You should expect this to be the player that is 'making' the decision (i.e. the player
    instantiated with the functions specified by this decision agent).
    :param current_gameboard: A dict. The global data structure representing the current game board.
    :param allowable_moves: A set of functions, each of which is defined in action_choices (imported in this file), and that
    will always be a subset of the action choices for out_of_turn in the game schema. Your returned action choice must be from
    allowable_moves; we will check for this when you return.
    :param code: See the preamble of this file for an explanation of this code
    :return: A 2-element tuple, the first of which is the action you want to take, and the second is a dictionary of
    parameters that will be passed into the function representing that action when it is executed.
    The dictionary must exactly contain the keys and expected value types expected by that action in
    action_choices
    """
    if action_choices.accept_sell_property_offer in allowable_moves:
        param = dict()
        param['player'] = player
        param['current_gameboard'] = current_gameboard
        # we accept an offer under one of two conditions:
        print player.player_name, ': Should I accept the offer by ',player.outstanding_property_offer['from_player'].player_name,' to buy ',\
            player.outstanding_property_offer['asset'].name,' for ',str(player.outstanding_property_offer['price']),'?'
        print '(', player.player_name, ' currently has cash balance of ', str(
            player.current_cash), ')'
        if player.outstanding_property_offer[
                'asset'].is_mortgaged or player.outstanding_property_offer[
                    'price'] > player.current_cash:
            pass  # ignore the offer if the property is mortgaged or will result in insolvency. This pass doesn't require 'filling' in.
        elif player.current_cash-player.outstanding_property_offer['price'] >= current_gameboard['go_increment'] and \
            player.outstanding_property_offer['price']<=player.outstanding_property_offer['asset'].price:
            # 1. we can afford it, and it's at or below market rate so let's buy it
            print player.player_name, ': I am accepting the offer to buy ',player.outstanding_property_offer['asset'].name,' since I can afford' \
                                                    'it and it is being offered at or below market rate.'
            player._agent_memory[
                'previous_action'] = action_choices.accept_sell_property_offer
            return (action_choices.accept_sell_property_offer, param)
        elif agent_helper_functions.will_property_complete_set(
                player, player.outstanding_property_offer['asset'],
                current_gameboard):
            # 2. less affordable, but we stand to gain by monopoly
            if player.current_cash - player.outstanding_property_offer[
                    'price'] >= current_gameboard[
                        'go_increment'] / 2:  # risky, but worth it
                print player.player_name, ': I am accepting the offer to buy ', player.outstanding_property_offer[
                    'asset'].name, ' since I can afford ' \
                                   'it (albeit barely so) and it will let me complete my color set.'
                player._agent_memory[
                    'previous_action'] = action_choices.accept_sell_property_offer
                return (action_choices.accept_sell_property_offer, param)

    if player.status != 'current_move':  # these actions are considered only if it's NOT our turn to roll the dice.
        if action_choices.improve_property in allowable_moves:  # beef up full color sets to maximize rent potential.
            param = agent_helper_functions.identify_improvement_opportunity(
                player, current_gameboard)
            if param:
                if player._agent_memory[
                        'previous_action'] == action_choices.improve_property and code == -1:
                    print player.player_name, ': I want to improve property ', param[
                        'asset'].name, ' but I cannot, due to reasons I do not understand. Aborting improvement attempt...'
                else:
                    print player.player_name, ': I am going to improve property ', param[
                        'asset'].name
                    player._agent_memory[
                        'previous_action'] = action_choices.improve_property
                    return (action_choices.improve_property, param)

        for m in player.mortgaged_assets:
            if player.current_cash - (m.mortgage * 1.1) >= current_gameboard[
                    'go_increment'] and action_choices.free_mortgage in allowable_moves:
                # free mortgages till we can afford it. the second condition should not be necessary but just in case.
                param = dict()
                param['player'] = player
                param['asset'] = m
                print player.player_name, ': I am going to free mortgage on ', param[
                    'asset'].name
                player._agent_memory[
                    'previous_action'] = action_choices.free_mortgage
                return (action_choices.free_mortgage, param)

    else:  # it is our current move. We should raise money if necessary, especially if we're low on cash.
        if player.current_cash < current_gameboard['go_increment'] and \
            action_choices.make_sell_property_offer in allowable_moves: # let's try to see if we can sell property to other players at a premium
            # the current agent does not try to raise money any other way. The reason is that selling houses, hotels, properties
            # or mortgaging properties are all available to us both in post-roll and also in handle_negative_cash_balance. A more proactive
            # agent (which isn't us) may want to make sure cash reserves are high before rolling the dice. Similarly, a more opportunistic
            # agent may choose to make a sell offer even if cash reserves aren't too low.
            param = agent_helper_functions.identify_sale_opportunity_to_player(
                player, current_gameboard)
            if param and player._agent_memory[
                    'previous_action'] != action_choices.make_sell_property_offer:  # we only make one offer per turn. Otherwise we'd
                # be stuck in a loop
                print player.player_name, ': I am making an offer to sell ', param[
                    'asset'].name, ' to ', param[
                        'to_player'].player_name, 'for ' + str(
                            param['price']) + ' dollars'
                player._agent_memory[
                    'previous_action'] = action_choices.make_sell_property_offer
                return (action_choices.make_sell_property_offer, param)
        elif action_choices.make_sell_property_offer in allowable_moves:  # let's try to see if we can sell property to other players at an insane premium
            # even though we don't 'need' the money
            param = agent_helper_functions.identify_sale_opportunity_to_player(
                player, current_gameboard)
            if param and player._agent_memory[
                    'previous_action'] != action_choices.make_sell_property_offer:  # we only make one offer per turn. Otherwise we'd
                # be stuck in a loop
                print player.player_name, ': I am making an offer to sell ', param[
                    'asset'].name, ' to ', param[
                        'to_player'].player_name, 'for ' + str(
                            param['price']) + ' dollars'
                player._agent_memory[
                    'previous_action'] = action_choices.make_sell_property_offer
                return (action_choices.make_sell_property_offer, param)

    # if we ran the gamut, and did not return, then it's time to skip turn or conclude actions
    if action_choices.skip_turn in allowable_moves:
        print player.player_name, ': I am skipping turn'
        player._agent_memory['previous_action'] = action_choices.skip_turn
        return (action_choices.skip_turn, dict())
    elif action_choices.concluded_actions in allowable_moves:
        print player.player_name, ': I am concluding actions'
        # player._agent_memory['previous_action'] = action_choices.concluded_actions
        return (action_choices.concluded_actions, dict())
    else:
        raise Exception
Пример #4
0
def make_post_roll_move(player, current_gameboard, allowable_moves, code):
    """
    The agent is in the post-roll phase and must decide what to do (next). The main decision we make here is singular:
    should we buy the property we landed on, if that option is available?

    --If we do buy the property, we end the phase by concluding the turn.

    --If we cannot buy a property, we conclude the turn. If we have negative cash balance, we do not handle it here, but
    in the handle_negative_cash_balance function. This means that the background agent never calls any of
    the mortgage or sell properties here UNLESS we need to mortgage or sell a property in order to buy the current
     one and it is well worth our while.

    Note that if your agent decides not to buy the property before concluding the turn, the property will move to
    auction before your turn formally concludes.

    This background agent never sells a house or hotel in post_roll.

    :param player: A Player instance. You should expect this to be the player that is 'making' the decision (i.e. the player
    instantiated with the functions specified by this decision agent).
    :param current_gameboard: A dict. The global data structure representing the current game board.
    :param allowable_moves: A set of functions, each of which is defined in action_choices (imported in this file), and that
    will always be a subset of the action choices for post-die-roll in the game schema. Your returned action choice must be from
    allowable_moves; we will check for this when you return.
    :param code: See the preamble of this file for an explanation of this code
    :return: A 2-element tuple, the first of which is the action you want to take, and the second is a dictionary of
    parameters that will be passed into the function representing that action when it is executed.
    The dictionary must exactly contain the keys and expected value types expected by that action in
    action_choices
        """
    current_location = current_gameboard['location_sequence'][
        player.current_position]
    if action_choices.buy_property in allowable_moves:
        if code == -1:
            print player.player_name, ': I did not succeed the last time in buying this property. Concluding actions...'
            return (action_choices.concluded_actions, dict())

        params = dict()
        params['player'] = player
        params['asset'] = current_location
        params['current_gameboard'] = current_gameboard

        if make_buy_property_decision(player, current_gameboard,
                                      params['asset']):
            print player.player_name, ': I am attempting to buy property ', params[
                'asset'].name
            player._agent_memory[
                'previous_action'] = action_choices.buy_property
            return (action_choices.buy_property, params)
        else:
            # make_buy returned false, but is there still a chance?
            if agent_helper_functions.will_property_complete_set(
                    player, current_location, current_gameboard):
                # if we can raise enough money, then the 'next' time around we'll succeed in buying
                to_mortgage = agent_helper_functions.identify_potential_mortgage(
                    player, current_location.price, True)
                if to_mortgage:
                    params['asset'] = to_mortgage
                    print player.player_name, ': I am attempting to mortgage property ', params[
                        'asset'].name
                    player._agent_memory[
                        'previous_action'] = action_choices.mortgage_property
                    return (action_choices.mortgage_property, params)

                else:  # last chance.
                    to_sell = agent_helper_functions.identify_potential_sale(
                        player, current_location.price, True)
                    if to_sell:
                        params['asset'] = to_sell
                        print player.player_name, ': I am attempting to sell property ', params[
                            'asset'].name, ' to the bank'
                        player._agent_memory[
                            'previous_action'] = action_choices.sell_property
                        return (action_choices.sell_property, params)

    if action_choices.concluded_actions in allowable_moves:
        # player._agent_memory['previous_action'] = action_choices.concluded_actions
        return (action_choices.concluded_actions, dict())

    else:
        raise Exception
def make_out_of_turn_move(player, current_gameboard, allowable_moves, code):
    """
    The agent is in the out-of-turn phase and must decide what to do (next). This simple dummy agent skips the turn, and
     doesn't do anything.
    :param player: A Player instance. You should expect this to be the player that is 'making' the decision (i.e. the player
    instantiated with the functions specified by this decision agent).
    :param current_gameboard: A dict. The global data structure representing the current game board.
    :param allowable_moves: A set of functions, each of which is defined in action_choices (imported in this file), and that
    will always be a subset of the action choices for out_of_turn in the game schema. Your returned action choice must be from
    allowable_moves; we will check for this when you return.
    :param code: See the preamble of this file for an explanation of this code
    :return: A 2-element tuple, the first of which is the action you want to take, and the second is a dictionary of
    parameters that will be passed into the function representing that action when it is executed.
    The dictionary must exactly contain the keys and expected value types expected by that action in
    action_choices
    """
    '''
    NOTE: The background agent that could make_sell_property_offer is deprecated (available as background_agent_v1_deprecated.py)
    This version of the agent can only make_trade_offer and accept trade offer. Trade involves buy or sell or exchange property offers.
    Accept_sell_property_offer function is still available in case some different agent decides to make a sell property offer.
    Ideally, accept_sell_property_offer() function should never enter allowable moves.
    Make sell property offer can be replicated by making a trade offer that only offers to sell properties in return for cash
    and doesnot involve a buy property or exchange property offer.
    A buy property offer can be duplicated by including only requested properties by offering cash without offering properties.
    Properties and cash can be exchanged which lets both players get an advantage of increasing their respective number of monopolies.
    This version of the agent background_agent_v1 supports making sell property offers in return for cash via make_trade_offer, 
    buy trade offers and exchange property offers.
    '''

    if action_choices.accept_trade_offer in allowable_moves:
        param = dict()
        param['player'] = player
        param['current_gameboard'] = current_gameboard
        logger.debug(
            player.player_name + ': Should I accept the trade offer by ' +
            player.outstanding_trade_offer['from_player'].player_name + '?')
        logger.debug('(' + player.player_name +
                     ' currently has cash balance of ' +
                     str(player.current_cash) + ')')

        if (player.outstanding_trade_offer['cash_offered'] <= 0 and len(player.outstanding_trade_offer['property_set_offered'])==0) and \
                (player.outstanding_trade_offer['cash_wanted'] > 0 or len(player.outstanding_trade_offer['property_set_wanted']) > 0):
            logger.debug(
                'Asking for free money or property without money or property in return.'
            )
            logger.debug(
                player.player_name + " rejected trade offer from " +
                player.outstanding_trade_offer['from_player'].player_name)
            pass  #asking for free money or property without anything in return(ie no money and no property offered), -->reject the trade offer

        elif player.outstanding_trade_offer[
                'cash_wanted'] - player.outstanding_trade_offer[
                    'cash_offered'] > player.current_cash:
            logger.debug(
                'Cash wanted from me in the trade offer is more than the cash in hand with me.'
            )
            logger.debug(
                player.player_name + " rejected trade offer from " +
                player.outstanding_trade_offer['from_player'].player_name)
            pass  #cash wanted is more than that offered and the net difference exceeds the cash that the player has --> then reject the tade offer

        else:
            reject_flag = 0
            offered_properties_net_worth = 0
            wanted_properties_net_worth = 0
            for prop in player.outstanding_trade_offer['property_set_wanted']:
                if prop.is_mortgaged:
                    reject_flag = 1  #cannot trade mortgaged properties, reject trade offer
                    logger.debug('Trade offer invovlves mortgaged properties.')
                    logger.debug(player.player_name +
                                 " rejected trade offer from " +
                                 player.outstanding_trade_offer['from_player'].
                                 player_name)
                    break
                else:
                    wanted_properties_net_worth += prop.price

            if reject_flag == 0:
                for prop in player.outstanding_trade_offer[
                        'property_set_offered']:
                    if prop.is_mortgaged:
                        reject_flag = 1  #from_player cannot offer mortgaged properties, reject trade offer
                        logger.debug(
                            'Trade offer invovlves mortgaged properties.')
                        logger.debug(
                            player.player_name +
                            " rejected trade offer from " + player.
                            outstanding_trade_offer['from_player'].player_name)
                        break
                    else:
                        offered_properties_net_worth += prop.price
            if reject_flag == 0:
                #GOAL -- increase monopolies
                #calculate the net worth of offer vs net worth of request --> makes sense to accept trade only if the offer is greater than request
                #net worth of offer = cash + total price of all houses
                #positive net_amount_requested implies that the requested net amount is greater than offered net amount
                net_offer_worth = (offered_properties_net_worth + player.outstanding_trade_offer['cash_offered']) - \
                                  (wanted_properties_net_worth + player.outstanding_trade_offer['cash_wanted'])
                net_amount_requested = -1 * net_offer_worth

                count_create_new_monopoly = 0
                count_lose_existing_monopoly = 0  ##ideally player doesnot have to worry about losing monopolies since the player who makes the offer
                #only requests for lone properties
                for prop in player.outstanding_trade_offer[
                        'property_set_offered']:
                    if agent_helper_functions.will_property_complete_set(
                            player, prop, current_gameboard):
                        count_create_new_monopoly += 1
                for prop in player.outstanding_trade_offer[
                        'property_set_wanted']:
                    if prop.color in player.full_color_sets_possessed:
                        count_lose_existing_monopoly += 1

                #if you end up losing more monopolies than gaining monopolies (although this condition should never come up) then reject trade offer
                if count_lose_existing_monopoly - count_create_new_monopoly > 0:
                    logger.debug('Player loses more monopolies than he gains.')
                    logger.debug(player.player_name +
                                 " rejected trade offer from " +
                                 player.outstanding_trade_offer['from_player'].
                                 player_name)
                    reject_flag = 1

                #if you end up losing the same number of monopolies as you gain, then accept the offer based on the following multiple conditions.
                #Basically you get no new monopolies since ideally you dont lose monopolies (only properties that dont belong to your monopolized color
                # groups are only requested from you in the trade.)
                elif count_lose_existing_monopoly - count_create_new_monopoly == 0:
                    if (player.outstanding_trade_offer['cash_wanted'] -
                            player.outstanding_trade_offer['cash_offered']
                        ) >= player.current_cash:
                        logger.debug(
                            'Cash wanted from me in the trade offer is more than the cash in hand with me.'
                        )
                        logger.debug(
                            player.player_name +
                            " rejected trade offer from " + player.
                            outstanding_trade_offer['from_player'].player_name)
                        reject_flag = 1  ##just double checking although this condition was verified before getting here.
                    elif player.current_cash - (
                            player.outstanding_trade_offer['cash_wanted'] -
                            player.outstanding_trade_offer['cash_offered']
                    ) < current_gameboard['go_increment'] / 2:
                        logger.debug(
                            'Cash wanted from me in the trade offer is more than the cash in hand with me.'
                        )
                        logger.debug(
                            player.player_name +
                            " rejected trade offer from " + player.
                            outstanding_trade_offer['from_player'].player_name)
                        reject_flag = 1  ##too risky if players cash after transaction drops below half of go_increment value --> hence reject trade offer
                    elif (player.current_cash - (player.outstanding_trade_offer['cash_wanted'] - player.outstanding_trade_offer['cash_offered']) < current_gameboard['go_increment']) \
                            and net_offer_worth <= 0:
                        logger.debug('No gain from accepting trade offer.')
                        logger.debug(
                            player.player_name +
                            " rejected trade offer from " + player.
                            outstanding_trade_offer['from_player'].player_name)
                        reject_flag = 1  ##if player has cash > go_increement/2 and < go_increement but net worth of total transaction is negative --> reject trade offer
                    else:
                        reject_flag = 0  ##accept only if you end up getting a higher net worth by accepting the trade although you get no new monopolies

                #else you get to monopolize more locations than you had before --> then ACCEPT THE TRADE OFFER
                elif count_create_new_monopoly - count_lose_existing_monopoly > 0:
                    if (player.outstanding_trade_offer['cash_wanted'] -
                            player.outstanding_trade_offer['cash_offered']
                        ) >= player.current_cash:
                        logger.debug(
                            'Cash wanted from me in the trade offer is more than the cash in hand with me.'
                        )
                        logger.debug(
                            player.player_name +
                            " rejected trade offer from " + player.
                            outstanding_trade_offer['from_player'].player_name)
                        reject_flag = 1  ##just double checking although this condition was verified before getting here.
                    else:
                        reject_flag = 0

            if reject_flag == 0:
                logger.debug(
                    player.player_name + " accepted trade offer from " +
                    player.outstanding_trade_offer['from_player'].player_name)
                logger.debug(
                    player.player_name + " recieved amount = " +
                    str(player.outstanding_trade_offer['cash_offered']) +
                    " and offered amount = " +
                    str(player.outstanding_trade_offer['cash_wanted']) +
                    " during trade")
                player.agent._agent_memory[
                    'previous_action'] = action_choices.accept_trade_offer
                return (action_choices.accept_trade_offer, param)
            elif reject_flag == 1:
                logger.debug(
                    player.player_name + " rejected trade offer from " +
                    player.outstanding_trade_offer['from_player'].player_name)
                pass

    if action_choices.accept_sell_property_offer in allowable_moves:
        ## Ideally accept_sell_offer should never enter allowable moves since henceforth make_trade_offer also takes care of make_sell_offer and
        ## accept_trade_offer takes care of accept_sell_offer.
        ## This case is included to accomodate a make_sell_property offer raised by an external agent.
        ## Our agent will never make a sell property offer, only makes trade offers which raises an accpet_trade_offer action.
        param = dict()
        param['player'] = player
        param['current_gameboard'] = current_gameboard
        # we accept an offer under one of two conditions:
        logger.debug(player.player_name+ ': Should I accept the offer by '+player.outstanding_property_offer['from_player'].player_name+' to buy '+\
            player.outstanding_property_offer['asset'].name+' for '+str(player.outstanding_property_offer['price'])+'?')
        logger.debug('(' + player.player_name +
                     ' currently has cash balance of ' +
                     str(player.current_cash) + ')')
        if player.outstanding_property_offer[
                'asset'].is_mortgaged or player.outstanding_property_offer[
                    'price'] > player.current_cash:
            pass  # ignore the offer if the property is mortgaged or will result in insolvency. This pass doesn't require 'filling' in.
        elif player.current_cash-player.outstanding_property_offer['price'] >= current_gameboard['go_increment'] and \
            player.outstanding_property_offer['price']<=player.outstanding_property_offer['asset'].price:
            # 1. we can afford it, and it's at or below market rate so let's buy it
            logger.debug(player.player_name+ ': I am accepting the offer to buy '+player.outstanding_property_offer['asset'].name+' since I can afford' \
                                                    'it and it is being offered at or below market rate.')
            player.agent._agent_memory[
                'previous_action'] = action_choices.accept_sell_property_offer
            return (action_choices.accept_sell_property_offer, param)
        elif agent_helper_functions.will_property_complete_set(
                player, player.outstanding_property_offer['asset'],
                current_gameboard):
            # 2. less affordable, but we stand to gain by monopoly
            if player.current_cash - player.outstanding_property_offer[
                    'price'] >= current_gameboard[
                        'go_increment'] / 2:  # risky, but worth it
                logger.debug(player.player_name+ ': I am accepting the offer to buy '+ player.outstanding_property_offer[
                    'asset'].name+ ' since I can afford ' \
                                   'it (albeit barely so) and it will let me complete my color set.')
                player.agent._agent_memory[
                    'previous_action'] = action_choices.accept_sell_property_offer
                return (action_choices.accept_sell_property_offer, param)

    if player.status != 'current_move':  # these actions are considered only if it's NOT our turn to roll the dice.
        if action_choices.improve_property in allowable_moves:  # beef up full color sets to maximize rent potential.
            param = agent_helper_functions.identify_improvement_opportunity(
                player, current_gameboard)
            if param:
                if player.agent._agent_memory[
                        'previous_action'] == action_choices.improve_property and code == -1:
                    logger.debug(
                        player.player_name + ': I want to improve property ' +
                        param['asset'].name +
                        ' but I cannot, due to reasons I do not understand. Aborting improvement attempt...'
                    )
                else:
                    logger.debug(player.player_name +
                                 ': I am going to improve property ' +
                                 param['asset'].name)
                    player.agent._agent_memory[
                        'previous_action'] = action_choices.improve_property
                    return (action_choices.improve_property, param)

        player_mortgaged_assets_list = list()
        if player.mortgaged_assets:
            player_mortgaged_assets_list = _set_to_sorted_list_mortgaged_assets(
                player.mortgaged_assets)
        for m in player_mortgaged_assets_list:
            if player.current_cash - (m.mortgage * 1.1) >= current_gameboard[
                    'go_increment'] and action_choices.free_mortgage in allowable_moves:
                # free mortgages till we can afford it. the second condition should not be necessary but just in case.
                param = dict()
                param['player'] = player
                param['asset'] = m
                param['current_gameboard'] = current_gameboard
                logger.debug(player.player_name +
                             ': I am going to free mortgage on ' +
                             param['asset'].name)
                player.agent._agent_memory[
                    'previous_action'] = action_choices.free_mortgage
                return (action_choices.free_mortgage, param)

    else:
        #purpose_flags are sent while curating a trade offer to imply why the trade offer was made:
        ## 1 --> low on cash, urgently in need of cash
        ## 2 --> gain monopoly
        if player.current_cash < current_gameboard[
                'go_increment'] and action_choices.make_trade_offer in allowable_moves:
            # in this case, the trade offer is a duplication of make_sell_property_offer since the player is in urgent need of cash and
            #cannot strategize a trade
            potential_offer_list = agent_helper_functions.identify_property_trade_offer_to_player(
                player, current_gameboard)
            potential_request_list = agent_helper_functions.identify_property_trade_wanted_from_player(
                player, current_gameboard)
            param = agent_helper_functions.curate_trade_offer(
                player,
                potential_offer_list,
                potential_request_list,
                current_gameboard,
                purpose_flag=1)
            #logger.debug(param)
            if param and player.agent._agent_memory[
                    'previous_action'] != action_choices.make_trade_offer:  # we only make one offer per turn. Otherwise we'd
                # be stuck in a loop
                logger.debug(
                    player.player_name + ': I am making an offer to trade ' +
                    list(param['offer']['property_set_offered'])[0].name +
                    ' to ' + param['to_player'].player_name + ' for ' +
                    str(param['offer']['cash_wanted']) + ' dollars')
                player.agent._agent_memory[
                    'previous_action'] = action_choices.make_trade_offer
                return (action_choices.make_trade_offer, param)

        elif action_choices.make_trade_offer in allowable_moves:
            # trade offer is being curated to maximise monopolies
            potential_offer_list = agent_helper_functions.identify_property_trade_offer_to_player(
                player, current_gameboard)
            potential_request_list = agent_helper_functions.identify_property_trade_wanted_from_player(
                player, current_gameboard)
            param = agent_helper_functions.curate_trade_offer(
                player,
                potential_offer_list,
                potential_request_list,
                current_gameboard,
                purpose_flag=2)
            #logger.debug(param)
            if param and player.agent._agent_memory[
                    'previous_action'] != action_choices.make_trade_offer:  # we only make one offer per turn. Otherwise we'd
                # be stuck in a loop
                logger.debug(player.player_name +
                             ': I am making a trade offer with ' +
                             param['to_player'].player_name)
                player.agent._agent_memory[
                    'previous_action'] = action_choices.make_trade_offer
                return (action_choices.make_trade_offer, param)

    # if we ran the gamut, and did not return, then it's time to skip turn or conclude actions
    if action_choices.skip_turn in allowable_moves:
        logger.debug(player.player_name + ': I am skipping turn')
        player.agent._agent_memory[
            'previous_action'] = action_choices.skip_turn
        return (action_choices.skip_turn, dict())
    elif action_choices.concluded_actions in allowable_moves:
        logger.debug(player.player_name + ': I am concluding actions')
        # player.agent._agent_memory['previous_action'] = action_choices.concluded_actions
        return (action_choices.concluded_actions, dict())
    else:
        logger.error("Exception")