def handle_negative_cash_balance(player, current_gameboard): """ You have a negative cash balance at the end of your move (i.e. your post-roll phase is over) and you must handle this issue before we move to the next player's pre-roll. If you do not succeed in restoring your cash balance to 0 or positive, bankruptcy proceeds will begin and you will lost the game. The background agent tries a number of things to get itself out of a financial hole. First, it checks whether mortgaging alone can save it. If not, then it begins selling unimproved properties in ascending order of price, the idea being that it might as well get rid of cheap properties. This may not be the most optimal move but it is reasonable. If it ends up selling all unimproved properties and is still insolvent, it starts selling improvements, followed by a sale of the (now) unimproved properties. :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: -1 if you do not try to address your negative cash balance, or 1 if you tried and believed you succeeded. Note that even if you do return 1, we will check to see whether you have non-negative cash balance. The rule of thumb is to return 1 as long as you 'try', or -1 if you don't try (in which case you will be declared bankrupt and lose the game) """ mortgage_potentials = list() max_sum = 0 for a in player.assets: if a.is_mortgaged: continue elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: mortgage_potentials.append((a,a.mortgage)) max_sum += a.mortgage if mortgage_potentials and max_sum+player.current_cash >= 0: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(mortgage_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.mortgage_property(player, p[0], current_gameboard) # if we got here, it means we're still in trouble. Next move is to sell unimproved properties. We don't check if # the total will cover our debts, since we're desperate at this point. sale_potentials = list() for a in player.assets: if a.is_mortgaged: sale_potentials.append((a, (a.price/2)-(1.1*a.mortgage))) elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: sale_potentials.append((a,a.price/2)) if sale_potentials: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(sale_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.sell_property(player, p[0], current_gameboard) count = 0 # if we're STILL not done, then the only option is to start selling houses and hotels, if we have 'em while (player.num_total_houses > 0 or player.num_total_hotels > 0) and count <3: # often times, a sale may not succeed due to uniformity requirements. We keep trying till everything is sold, # or cash balance turns non-negative. count += 1 # there is a slim chance that it is impossible to sell an improvement unless the player does something first (e.g., replace 4 houses with a hotel). # The count ensures we terminate at some point, regardless. for a in player.assets: if a.num_houses > 0: action_choices.sell_house_hotel(player, a, current_gameboard,True, False) if player.current_cash >= 0: return 1 # we're done elif a.num_hotels > 0: action_choices.sell_house_hotel(player, a, current_gameboard, False, True) if player.current_cash >= 0: return 1 # we're done # final straw final_sale_assets = player.assets.copy() for a in final_sale_assets: action_choices.sell_property(player, a, current_gameboard) # this could be refined further; we may be able to get away with a mortgage at this point. if player.current_cash >= 0: return 1 # we're done return 1 # if we didn't succeed in establishing solvency, it will get caught by the simulator. Since we tried, we return 1.
def handle_negative_cash_balance(player, current_gameboard): """ You have a negative cash balance at the end of your move (i.e. your post-roll phase is over) and you must handle this issue before we move to the next player's pre-roll. If you do not succeed in restoring your cash balance to 0 or positive, bankruptcy proceeds will begin and you will lost the game. The background agent tries a number of things to get itself out of a financial hole. First, it checks whether mortgaging alone can save it. If not, then it begins selling unimproved properties in ascending order of price, the idea being that it might as well get rid of cheap properties. This may not be the most optimal move but it is reasonable. If it ends up selling all unimproved properties and is still insolvent, it starts selling improvements, followed by a sale of the (now) unimproved properties. :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: -1 if you do not try to address your negative cash balance, or 1 if you tried and believed you succeeded. Note that even if you do return 1, we will check to see whether you have non-negative cash balance. The rule of thumb is to return 1 as long as you 'try', or -1 if you don't try (in which case you will be declared bankrupt and lose the game) """ mortgage_potentials = list() max_sum = 0 sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_player_assets_list: if a.is_mortgaged: continue elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: mortgage_potentials.append((a,a.mortgage)) max_sum += a.mortgage if mortgage_potentials and max_sum+player.current_cash >= 0: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(mortgage_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.mortgage_property(player, p[0], current_gameboard) # if we got here, it means we're still in trouble. Next move is to sell unimproved properties. We don't check if # the total will cover our debts, since we're desperate at this point. # following sale potentials doesnot include properties from monopolized color groups sale_potentials = list() sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_player_assets_list: if a.color in player.full_color_sets_possessed: continue elif a.is_mortgaged: sale_potentials.append((a, (a.price/2)-((1+current_gameboard['bank'].mortgage_percentage)*a.mortgage))) elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: sale_potentials.append((a,a.price/2)) if sale_potentials: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(sale_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.sell_property(player, p[0], current_gameboard) # if selling properties from non monopolized color groups doesnot relieve the player from debt, then only we start thinking about giving up monopolized groups. # If we come across a unimproved property which belongs to a monopoly, we still have to loop through the other properties from the same color group and # sell the houses and hotels first because we cannot sell this property when the color group has improved properties # We first check if selling houses and hotels one by one on the other improved properties of the same color group relieves the player of his debt. If it does # then we return without selling the current property else we sell the property and the player loses monopoly of that color group. sale_potentials = list() sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_player_assets_list: if a.is_mortgaged: sale_potentials.append((a, (a.price/2)-((1+current_gameboard['bank'].mortgage_percentage)*a.mortgage))) elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: sale_potentials.append((a,a.price/2)) if sale_potentials: sorted_potentials = sorted(sale_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for prop in sorted_player_assets_list: if prop!=p[0] and prop.color==p[0].color and p[0].color in player.full_color_sets_possessed: if prop.num_hotels>0: action_choices.sell_house_hotel(player, prop, current_gameboard, False, True) if player.current_cash >= 0: return 1 elif prop.num_houses>0: while prop.num_houses>0: action_choices.sell_house_hotel(player, prop, current_gameboard, True, False) if player.current_cash >= 0: return 1 else: continue action_choices.sell_property(player, p[0], current_gameboard) if p[0].color in player.full_color_sets_possessed: player.full_color_sets_possessed.remove(p[0].color) #we reach here if the player still hasnot cleared his debt. The above loop has now resulted in some more non monopolized properties. #Hence we have to go through the process of looping through these properties once again to decide on the potential properties that can be mortgaged or sold. mortgage_potentials = list() max_sum = 0 sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_player_assets_list: if a.is_mortgaged: continue elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: mortgage_potentials.append((a,a.mortgage)) max_sum += a.mortgage if mortgage_potentials and max_sum+player.current_cash >= 0: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(mortgage_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.mortgage_property(player, p[0], current_gameboard) # following sale potentials loops through the properties that have become unmonopolized due to the above loops and # doesnot include properties from monopolized color groups sale_potentials = list() sorted_player_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_player_assets_list: if a.color in player.full_color_sets_possessed: continue elif a.is_mortgaged: sale_potentials.append((a, (a.price/2)-((1+current_gameboard['bank'].mortgage_percentage)*a.mortgage))) elif a.loc_class=='real_estate' and (a.num_houses>0 or a.num_hotels>0): continue else: sale_potentials.append((a,a.price/2)) if sale_potentials: # if the second condition is not met, no point in mortgaging sorted_potentials = sorted(sale_potentials, key=lambda x: x[1]) # sort by mortgage in ascending order for p in sorted_potentials: if player.current_cash >= 0: return 1 # we're done action_choices.sell_property(player, p[0], current_gameboard) count = 0 # if we're STILL not done, then the only option is to start selling houses and hotels from the remaining improved monopolized properties, if we have 'em while (player.num_total_houses > 0 or player.num_total_hotels > 0) and count <3: # often times, a sale may not succeed due to uniformity requirements. We keep trying till everything is sold, # or cash balance turns non-negative. count += 1 # there is a slim chance that it is impossible to sell an improvement unless the player does something first (e.g., replace 4 houses with a hotel). # The count ensures we terminate at some point, regardless. sorted_assets_list = _set_to_sorted_list_assets(player.assets) for a in sorted_assets_list: if a.num_houses > 0: action_choices.sell_house_hotel(player, a, current_gameboard,True, False) if player.current_cash >= 0: return 1 # we're done elif a.num_hotels > 0: action_choices.sell_house_hotel(player, a, current_gameboard, False, True) if player.current_cash >= 0: return 1 # we're done # final straw final_sale_assets = player.assets.copy() sorted_player_assets_list = _set_to_sorted_list_assets(final_sale_assets) for a in sorted_player_assets_list: action_choices.sell_property(player, a, current_gameboard) # this could be refined further; we may be able to get away with a mortgage at this point. if player.current_cash >= 0: return 1 # we're done return 1 # if we didn't succeed in establishing solvency, it will get caught by the simulator. Since we tried, we return 1.