Ejemplo n.º 1
0
def simulate_game_instance(game_elements, history_log_file=None, np_seed=6):
    """
    Simulate a game instance.
    :param game_elements: The dict output by set_up_board
    :param np_seed: The numpy seed to use to control randomness.
    :return: None
    """
    logger.debug("size of board " + str(len(game_elements['location_sequence'])))
    for i in range(len(game_elements['location_sequence'])):
        logger.debug(game_elements['location_sequence'][i].name)
    logger.debug(
        "start pos: " + str(game_elements['location_objects']['States Avenue'].start_position) + " end pos: " + str(
            game_elements['location_objects']['States Avenue'].end_position))
    logger.debug(
        "start pos: " + str(game_elements['location_objects']['Virginia Avenue'].start_position) + " end pos: " + str(
            game_elements['location_objects']['Virginia Avenue'].end_position))
    logger.debug("start pos: " + str(
        game_elements['location_objects']['Pennsylvania Railroad'].start_position) + " end pos: " + str(
        game_elements['location_objects']['Pennsylvania Railroad'].end_position))
    np.random.seed(np_seed)
    np.random.shuffle(game_elements['players'])
    game_elements['seed'] = np_seed
    game_elements['card_seed'] = np_seed
    game_elements['choice_function'] = np.random.choice

    num_die_rolls = 0
    # game_elements['go_increment'] = 100 # we should not be modifying this here. It is only for testing purposes.
    # One reason to modify go_increment is if your decision agent is not aggressively trying to monopolize. Since go_increment
    # by default is 200 it can lead to runaway cash increases for simple agents like ours.

    logger.debug(
        'players will play in the following order: ' + '->'.join([p.player_name for p in game_elements['players']]))
    logger.debug('Beginning play. Rolling first die...')
    current_player_index = 0
    num_active_players = 4
    winner = None
    workbook = None
    if history_log_file:
        workbook = xlsxwriter.Workbook(history_log_file)

    while num_active_players > 1:
        disable_history(
            game_elements)  # comment this out when you want history to stay. Currently, it has high memory consumption, we are working to solve the problem (most likely due to deep copy run-off).
        current_player = game_elements['players'][current_player_index]
        while current_player.status == 'lost':
            current_player_index += 1
            current_player_index = current_player_index % len(game_elements['players'])
            current_player = game_elements['players'][current_player_index]
        current_player.status = 'current_move'

        # pre-roll for current player + out-of-turn moves for everybody else,
        # till we get num_active_players skip turns in a row.

        skip_turn = 0
        if current_player.make_pre_roll_moves(game_elements) == 2:  # 2 is the special skip-turn code
            skip_turn += 1
        out_of_turn_player_index = current_player_index + 1
        out_of_turn_count = 0
        while skip_turn != num_active_players and out_of_turn_count <= 200:
            out_of_turn_count += 1
            # print('checkpoint 1')
            out_of_turn_player = game_elements['players'][out_of_turn_player_index % len(game_elements['players'])]
            if out_of_turn_player.status == 'lost':
                out_of_turn_player_index += 1
                continue
            oot_code = out_of_turn_player.make_out_of_turn_moves(game_elements)
            # add to game history
            game_elements['history']['function'].append(out_of_turn_player.make_out_of_turn_moves)
            params = dict()
            params['self'] = out_of_turn_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(oot_code)

            if oot_code == 2:
                skip_turn += 1
            else:
                skip_turn = 0
            out_of_turn_player_index += 1

        # now we roll the dice and get into the post_roll phase,
        # but only if we're not in jail.
        # but only if we're not in jail.

        r = roll_die(game_elements['dies'], np.random.choice)
        for i in range(len(r)):
            game_elements['die_sequence'][i].append(r[i])

        # add to game history
        game_elements['history']['function'].append(roll_die)
        params = dict()
        params['die_objects'] = game_elements['dies']
        params['choice'] = np.random.choice
        game_elements['history']['param'].append(params)
        game_elements['history']['return'].append(r)

        num_die_rolls += 1
        game_elements['current_die_total'] = sum(r)
        logger.debug('dies have come up ' + str(r))
        if not current_player.currently_in_jail:
            check_for_go = True
            move_player_after_die_roll(current_player, sum(r), game_elements, check_for_go)
            # add to game history
            game_elements['history']['function'].append(move_player_after_die_roll)
            params = dict()
            params['player'] = current_player
            params['rel_move'] = sum(r)
            params['current_gameboard'] = game_elements
            params['check_for_go'] = check_for_go
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

            current_player.process_move_consequences(game_elements)
            # add to game history
            game_elements['history']['function'].append(current_player.process_move_consequences)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

            # post-roll for current player. No out-of-turn moves allowed at this point.
            current_player.make_post_roll_moves(game_elements)
            # add to game history
            game_elements['history']['function'].append(current_player.make_post_roll_moves)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

        else:
            current_player.currently_in_jail = False  # the player is only allowed to skip one turn (i.e. this one)

        if current_player.current_cash < 0:
            code = current_player.agent.handle_negative_cash_balance(current_player, game_elements)
            # add to game history
            game_elements['history']['function'].append(current_player.agent.handle_negative_cash_balance)
            params = dict()
            params['player'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(code)
            if code == -1 or current_player.current_cash < 0:
                current_player.begin_bankruptcy_proceedings(game_elements)
                # add to game history
                game_elements['history']['function'].append(current_player.begin_bankruptcy_proceedings)
                params = dict()
                params['self'] = current_player
                params['current_gameboard'] = game_elements
                game_elements['history']['param'].append(params)
                game_elements['history']['return'].append(None)

                num_active_players -= 1
                diagnostics.print_asset_owners(game_elements)
                diagnostics.print_player_cash_balances(game_elements)

                if num_active_players == 1:
                    for p in game_elements['players']:
                        if p.status != 'lost':
                            winner = p
                            p.status = 'won'
        else:
            current_player.status = 'waiting_for_move'

        current_player_index = (current_player_index + 1) % len(game_elements['players'])

        if diagnostics.max_cash_balance(
                game_elements) > 300000:  # this is our limit for runaway cash for testing purposes only.
            # We print some diagnostics and return if any player exceeds this.
            diagnostics.print_asset_owners(game_elements)
            diagnostics.print_player_cash_balances(game_elements)
            return

    if workbook:
        write_history_to_file(game_elements, workbook)
    # let's print some numbers
    logger.debug('printing final asset owners: ')
    diagnostics.print_asset_owners(game_elements)
    logger.debug('number of dice rolls: ' + str(num_die_rolls))
    logger.debug('printing final cash balances: ')
    diagnostics.print_player_cash_balances(game_elements)

    if winner:
        logger.debug('We have a winner: ' + winner.player_name)
        return winner.player_name

    return None
Ejemplo n.º 2
0
    def simulate_game_instance(self, history_log_file=None, np_seed=838885):
        """
        Simulate a game instance.
        :param game_elements: The dict output by set_up_board
        :param np_seed: The numpy seed to use to control randomness.
        :return: None
        """
        logger.debug("size of board "+ str(len(self.game_elem['location_sequence'])))
        #for i in range(len(self.game_elem['location_sequence'])):
        #    logger.debug(self.game_elem['location_sequence'][i].name)
        #logger.debug("start pos: " + str(self.game_elem['location_objects']['States Avenue'].start_position) + " end pos: " + str(self.game_elem['location_objects']['States Avenue'].end_position))
        #logger.debug("start pos: " + str(self.game_elem['location_objects']['Virginia Avenue'].start_position) + " end pos: " + str(self.game_elem['location_objects']['Virginia Avenue'].end_position))
        #logger.debug("start pos: " + str(self.game_elem['location_objects']['Pennsylvania Railroad'].start_position) + " end pos: " + str(self.game_elem['location_objects']['Pennsylvania Railroad'].end_position))
        np.random.seed(np_seed)
        np.random.shuffle(self.game_elem['players'])
        self.game_elem['seed'] = np_seed
        self.game_elem['card_seed'] = np_seed
        self.game_elem['choice_function'] = np.random.choice

        num_die_rolls = 0
        # game_elements['go_increment'] = 100 # we should not be modifying this here. It is only for testing purposes.
        # One reason to modify go_increment is if your decision agent is not aggressively trying to monopolize. Since go_increment
        # by default is 200 it can lead to runaway cash increases for simple agents like ours.

        logger.debug('players will play in the following order: '+'->'.join([p.player_name for p in self.game_elem['players']]))
        logger.debug('Beginning play. Rolling first die...')
        current_player_index = 0
        num_active_players = 4
        winner = None

        while num_active_players > 1:
            self.disable_history()
            if self.start_stop_flag==True:
                current_player = self.game_elem['players'][current_player_index]
                while current_player.status == 'lost':
                    current_player_index += 1
                    current_player_index = current_player_index % len(self.game_elem['players'])
                    current_player = self.game_elem['players'][current_player_index]
                current_player.status = 'current_move'

                # pre-roll for current player + out-of-turn moves for everybody else,
                # till we get num_active_players skip turns in a row.

                skip_turn = 0
                if current_player.make_pre_roll_moves(self.game_elem) == 2:  #2 is the special skip-turn code
                    skip_turn += 1
                out_of_turn_player_index = current_player_index + 1
                out_of_turn_count = 0
                while skip_turn != num_active_players and out_of_turn_count<=200:
                    out_of_turn_count += 1
                    # print('checkpoint 1')
                    out_of_turn_player = self.game_elem['players'][out_of_turn_player_index%len(self.game_elem['players'])]
                    if out_of_turn_player.status == 'lost':
                        out_of_turn_player_index += 1
                        continue
                    oot_code = out_of_turn_player.make_out_of_turn_moves(self.game_elem)
                    # add to game history
                    self.game_elem['history']['function'].append(out_of_turn_player.make_out_of_turn_moves)
                    params = dict()
                    params['self']=out_of_turn_player
                    params['current_gameboard']=self.game_elem
                    self.game_elem['history']['param'].append(params)
                    self.game_elem['history']['return'].append(oot_code)

                    if oot_code == 2:
                        skip_turn += 1
                    else:
                        skip_turn = 0
                    out_of_turn_player_index += 1

                # now we roll the dice and get into the post_roll phase,
                # but only if we're not in jail.


                r = roll_die(self.game_elem['dies'], np.random.choice)
                self.dice_list = r
                for i in range(len(r)):
                    self.game_elem['die_sequence'][i].append(r[i])
                # add to game history
                self.game_elem['history']['function'].append(roll_die)
                params = dict()
                params['die_objects'] = self.game_elem['dies']
                params['choice'] = np.random.choice
                self.game_elem['history']['param'].append(params)
                self.game_elem['history']['return'].append(r)

                num_die_rolls += 1
                self.game_elem['current_die_total'] = sum(r)
                logger.debug('dies have come up ' + str(r))
                if not current_player.currently_in_jail:
                    check_for_go = True
                    move_player_after_die_roll(current_player, sum(r), self.game_elem, check_for_go)
                    # add to game history
                    self.game_elem['history']['function'].append(move_player_after_die_roll)
                    params = dict()
                    params['player'] = current_player
                    params['rel_move'] = sum(r)
                    params['current_gameboard'] = self.game_elem
                    params['check_for_go'] = check_for_go
                    self.game_elem['history']['param'].append(params)
                    self.game_elem['history']['return'].append(None)

                    current_player.process_move_consequences(self.game_elem)
                    # add to game history
                    self.game_elem['history']['function'].append(current_player.process_move_consequences)
                    params = dict()
                    params['self'] = current_player
                    params['current_gameboard'] = self.game_elem
                    self.game_elem['history']['param'].append(params)
                    self.game_elem['history']['return'].append(None)

                    # post-roll for current player. No out-of-turn moves allowed at this point.
                    current_player.make_post_roll_moves(self.game_elem)
                    # add to game history
                    self.game_elem['history']['function'].append(current_player.make_post_roll_moves)
                    params = dict()
                    params['self'] = current_player
                    params['current_gameboard'] = self.game_elem
                    self.game_elem['history']['param'].append(params)
                    self.game_elem['history']['return'].append(None)

                else:
                    current_player.currently_in_jail = False # the player is only allowed to skip one turn (i.e. this one)

                if current_player.current_cash < 0:
                    code = current_player.agent.handle_negative_cash_balance(current_player, self.game_elem)
                    # add to game history
                    self.game_elem['history']['function'].append(current_player.agent.handle_negative_cash_balance)
                    params = dict()
                    params['player'] = current_player
                    params['current_gameboard'] = self.game_elem
                    self.game_elem['history']['param'].append(params)
                    self.game_elem['history']['return'].append(code)
                    if code == -1 or current_player.current_cash < 0:
                        current_player.begin_bankruptcy_proceedings(self.game_elem)
                        # add to game history
                        self.game_elem['history']['function'].append(current_player.begin_bankruptcy_proceedings)
                        params = dict()
                        params['self'] = current_player
                        params['current_gameboard'] = self.game_elem
                        self.game_elem['history']['param'].append(params)
                        self.game_elem['history']['return'].append(None)

                        num_active_players -= 1
                        diagnostics.print_asset_owners(self.game_elem)
                        diagnostics.print_player_cash_balances(self.game_elem)

                        if num_active_players == 1:
                            for p in self.game_elem['players']:
                                if p.status != 'lost':
                                    winner = p
                                    p.status = 'won'
                else:
                    current_player.status = 'waiting_for_move'

                current_player_index = (current_player_index+1)%len(self.game_elem['players'])

                '''
                The following line determines the speed of your game visualization and game.
                0.1 is the default setting for this package.
                You can reduce it if you want the game to run faster or increase it to slow down the execution.
                '''
                time.sleep(0.1)
                self.update_board()

                if diagnostics.max_cash_balance(self.game_elem) > 300000: # this is our limit for runaway cash for testing purposes only.
                                                                         # We print some diagnostics and return if any player exceeds this.
                    diagnostics.print_asset_owners(self.game_elem)
                    diagnostics.print_player_cash_balances(self.game_elem)
                    return

        logger.debug('printing final asset owners: ')
        diagnostics.print_asset_owners(self.game_elem)
        logger.debug('number of dice rolls: '+ str(num_die_rolls))
        logger.debug('printing final cash balances: ')
        diagnostics.print_player_cash_balances(self.game_elem)

        if winner:
            logger.debug('We have a winner: '+ winner.player_name)

        return
Ejemplo n.º 3
0
def simulate_game_instance(game_elements, history_log_file=None, np_seed=2):
    """
    Simulate a game instance.
    :param game_elements: The dict output by set_up_board
    :param np_seed: The numpy seed to use to control randomness.
    :return: None
    """
    logger.debug("size of board " +
                 str(len(game_elements['location_sequence'])))
    np.random.seed(np_seed)
    np.random.shuffle(game_elements['players'])
    game_elements['seed'] = np_seed
    game_elements['card_seed'] = np_seed
    game_elements['choice_function'] = np.random.choice
    count_json = 0  # a counter to keep track of how many rounds the game has to be played before storing the current_state of gameboard to file.
    num_die_rolls = 0
    tot_time = 0
    # game_elements['go_increment'] = 100 # we should not be modifying this here. It is only for testing purposes.
    # One reason to modify go_increment is if your decision agent is not aggressively trying to monopolize. Since go_increment
    # by default is 200 it can lead to runaway cash increases for simple agents like ours.

    logger.debug('players will play in the following order: ' +
                 '->'.join([p.player_name for p in game_elements['players']]))
    logger.debug('Beginning play. Rolling first die...')
    current_player_index = 0
    num_active_players = 4
    winner = None
    workbook = None
    if history_log_file:
        workbook = xlsxwriter.Workbook(history_log_file)
    game_elements['start_time'] = time.time()
    while num_active_players > 1:
        disable_history(
            game_elements
        )  # comment this out when you want history to stay. Currently, it has high memory consumption, we are working to solve the problem (most likely due to deep copy run-off).
        current_player = game_elements['players'][current_player_index]
        while current_player.status == 'lost':
            current_player_index += 1
            current_player_index = current_player_index % len(
                game_elements['players'])
            current_player = game_elements['players'][current_player_index]
        current_player.status = 'current_move'

        # pre-roll for current player + out-of-turn moves for everybody else,
        # till we get num_active_players skip turns in a row.

        skip_turn = 0
        if current_player.make_pre_roll_moves(
                game_elements) == 2:  # 2 is the special skip-turn code
            skip_turn += 1
        out_of_turn_player_index = current_player_index + 1
        out_of_turn_count = 0
        while skip_turn != num_active_players and out_of_turn_count <= 5:  ##oot count reduced to 20 from 200 to keep the game short
            out_of_turn_count += 1
            # print('checkpoint 1')
            out_of_turn_player = game_elements['players'][
                out_of_turn_player_index % len(game_elements['players'])]
            if out_of_turn_player.status == 'lost':
                out_of_turn_player_index += 1
                continue

            oot_code = out_of_turn_player.make_out_of_turn_moves(game_elements)
            # add to game history
            game_elements['history']['function'].append(
                out_of_turn_player.make_out_of_turn_moves)
            params = dict()
            params['self'] = out_of_turn_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(oot_code)

            if oot_code == 2:
                skip_turn += 1
            else:
                skip_turn = 0
            out_of_turn_player_index += 1

        # now we roll the dice and get into the post_roll phase,
        # but only if we're not in jail.
        # but only if we're not in jail.

        logger.debug("Printing cash balance and net worth of each player: ")
        diagnostics.print_player_net_worths_and_cash_bal(game_elements)

        r = roll_die(game_elements['dies'], np.random.choice)
        for i in range(len(r)):
            game_elements['die_sequence'][i].append(r[i])

        # add to game history
        game_elements['history']['function'].append(roll_die)
        params = dict()
        params['die_objects'] = game_elements['dies']
        params['choice'] = np.random.choice
        game_elements['history']['param'].append(params)
        game_elements['history']['return'].append(r)

        num_die_rolls += 1
        game_elements['current_die_total'] = sum(r)
        logger.debug('dies have come up ' + str(r))
        if not current_player.currently_in_jail:
            check_for_go = True
            game_elements['move_player_after_die_roll'](current_player, sum(r),
                                                        game_elements,
                                                        check_for_go)
            # add to game history
            game_elements['history']['function'].append(
                game_elements['move_player_after_die_roll'])
            params = dict()
            params['player'] = current_player
            params['rel_move'] = sum(r)
            params['current_gameboard'] = game_elements
            params['check_for_go'] = check_for_go
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

            current_player.process_move_consequences(game_elements)
            # add to game history
            game_elements['history']['function'].append(
                current_player.process_move_consequences)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

            # post-roll for current player. No out-of-turn moves allowed at this point.
            current_player.make_post_roll_moves(game_elements)
            # add to game history
            game_elements['history']['function'].append(
                current_player.make_post_roll_moves)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(None)

        else:
            current_player.currently_in_jail = False  # the player is only allowed to skip one turn (i.e. this one)

        if current_player.current_cash < 0:
            code = current_player.handle_negative_cash_balance(game_elements)
            # add to game history
            game_elements['history']['function'].append(
                current_player.handle_negative_cash_balance)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = game_elements
            game_elements['history']['param'].append(params)
            game_elements['history']['return'].append(code)
            if code == flag_config_dict[
                    'failure_code'] or current_player.current_cash < 0:
                current_player.begin_bankruptcy_proceedings(game_elements)
                # add to game history
                game_elements['history']['function'].append(
                    current_player.begin_bankruptcy_proceedings)
                params = dict()
                params['self'] = current_player
                params['current_gameboard'] = game_elements
                game_elements['history']['param'].append(params)
                game_elements['history']['return'].append(None)

                num_active_players -= 1
                diagnostics.print_asset_owners(game_elements)
                diagnostics.print_player_cash_balances(game_elements)

                if num_active_players == 1:
                    for p in game_elements['players']:
                        if p.status != 'lost':
                            winner = p
                            p.status = 'won'
            else:
                current_player.status = 'waiting_for_move'
        else:
            current_player.status = 'waiting_for_move'

        current_player_index = (current_player_index + 1) % len(
            game_elements['players'])
        tot_time = time.time() - game_elements['start_time']

        if card_utility_actions.check_for_game_termination(
                game_elements, tot_time):
            # game terminates if check_for_game_termination returns true.
            # We print some diagnostics and return if any player exceeds this.
            diagnostics.print_asset_owners(game_elements)
            diagnostics.print_player_cash_balances(game_elements)
            logger.debug("Game ran for " + str(tot_time) + " seconds.")
            break

        #This is an example of how you may want to write out gameboard state to file.
        #Uncomment the following piece of code to write out the gameboard current_state to file at the "count_json" iteration.
        #All the data from game_elements will be written to a .json file which can be read back to intialize a new game with
        #those gameboard values to start the game from that point onwards.
        '''
        if count_json == 50:
            outfile = '../current_gameboard_state.json'
            oot_code = read_write_current_state.write_out_current_state_to_file(game_elements, outfile)
            if oot_code == 1:
                print("Successfully written gameboard current state to file.")
                logger.debug("Successfully written gameboard current state to file.")
                print("Cash in hand with players when writing gameboard state to file: ")
                for player in game_elements['players']:
                    print(player.player_name, " current cash=", player.current_cash)
            else:
                print("Something went wrong when trying to write gameboard state to file. "
                      "Rest of the game will be played as normal but will not log state to file.")
        '''
        count_json += 1

    logger.debug('Liquid Cash remaining with Bank = ' +
                 str(game_elements['bank'].total_cash_with_bank))

    if workbook:
        write_history_to_file(game_elements, workbook)
    # let's print some numbers
    logger.debug('printing final asset owners: ')
    diagnostics.print_asset_owners(game_elements)
    logger.debug('number of dice rolls: ' + str(num_die_rolls))
    logger.debug('printing final cash balances: ')
    diagnostics.print_player_cash_balances(game_elements)
    logger.debug("printing net worth of each player: ")
    diagnostics.print_player_net_worths(game_elements)
    logger.debug("Game ran for " + str(tot_time) + " seconds.")

    if winner:
        logger.debug('We have a winner: ' + winner.player_name)
        return winner.player_name
    else:
        winner = card_utility_actions.check_for_winner(game_elements)
        if winner is not None:
            logger.debug('We have a winner: ' + winner.player_name)
            return winner.player_name
        else:
            logger.debug('Game has no winner, do not know what went wrong!!!')
            return None  # ideally should never get here
Ejemplo n.º 4
0
def simulate_hypothetical_game(hypothetical_gameboard, die_roll_substitute, num_total_die_rolls=-1):
    """
    If you want to simulate the game from a different 'starting' point than when you spawned the hypothetical universe,
    then you should make those changes (e.g., you could change the current_player, but you should do so safely i.e.
    make sure there aren't 'two' current players!) before calling simulate.

    :param hypothetical_gameboard:
    :param die_roll_substitute: This is a function that takes the list of Dice objects in the hypothetical gameboard as
    its argument. See expected function signature (and example) at the end of this file
    :param num_total_die_rolls: If -1, then the 'hypothetical' game will play out till the end. Otherwise, specify the total
    number of die rolls that the game should run for (following which, it will terminate with no winner, assuming there is
    more than one active player still).
    :return: A player instance representing the winner, or None
    """
    num_die_rolls = 0 # this field will start from 0 i.e. it is counting how many 'die rolls' have happened only in the alternate universe

    current_player_index = -1
    num_active_players = 0
    winner = None
    for i, p in enumerate(hypothetical_gameboard['players']):
        if p.status == 'won':
            print('there is already a winner here. returning...')
            winner = p
            return winner
        elif p.status != 'lost':
            num_active_players += 1
            if p.status == 'current_move':
                if current_player_index != -1:
                    print('there is more than one current player. Terminating with no winner...')
                    return winner
                current_player_index = i

    print('In your alternate universe, the current player is ',hypothetical_gameboard['players'][current_player_index].player_name)
    print('Number of active players is ',num_active_players)

    print('STARTING HYPOTHETICAL GAMEPLAY...')
    while num_active_players > 1 and (num_total_die_rolls==-1 or num_total_die_rolls>num_die_rolls):
        current_player = hypothetical_gameboard['players'][current_player_index]
        while current_player.status == 'lost':
            current_player_index += 1
            current_player_index = current_player_index % len(hypothetical_gameboard['players'])
            current_player = hypothetical_gameboard['players'][current_player_index]
        current_player.status = 'current_move'

        # pre-roll for current player + out-of-turn moves for everybody else,
        # till we get num_active_players skip turns in a row.

        skip_turn = 0
        if current_player.make_pre_roll_moves(hypothetical_gameboard) == 2: # 2 is the special skip-turn code
            skip_turn += 1
        out_of_turn_player_index = current_player_index + 1
        out_of_turn_count = 0
        while skip_turn != num_active_players and out_of_turn_count<=200:
            out_of_turn_count += 1
            # print('checkpoint 1')
            out_of_turn_player = hypothetical_gameboard['players'][out_of_turn_player_index%len(hypothetical_gameboard['players'])]
            if out_of_turn_player.status == 'lost':
                out_of_turn_player_index += 1
                continue
            oot_code = out_of_turn_player.make_out_of_turn_moves(hypothetical_gameboard)
            # add to game history
            hypothetical_gameboard['history']['function'].append(out_of_turn_player.make_out_of_turn_moves)
            params = dict()
            params['self']=out_of_turn_player
            params['current_gameboard']=hypothetical_gameboard
            hypothetical_gameboard['history']['param'].append(params)
            hypothetical_gameboard['history']['return'].append(oot_code)

            if  oot_code == 2:
                skip_turn += 1
            else:
                skip_turn = 0
            out_of_turn_player_index += 1

        # now we roll the dice and get into the post_roll phase,
        # but only if we're not in jail.


        r = die_roll_substitute(hypothetical_gameboard['dies'], hypothetical_gameboard)
        # add to game history
        hypothetical_gameboard['history']['function'].append(die_roll_substitute)
        params = dict()
        params['die_objects'] = hypothetical_gameboard['dies']
        params['hypothetical_gameboard'] = hypothetical_gameboard
        hypothetical_gameboard['history']['param'].append(params)
        hypothetical_gameboard['history']['return'].append(r)

        num_die_rolls += 1
        hypothetical_gameboard['current_die_total'] = sum(r)
        print('dies have come up ',str(r))
        if not current_player.currently_in_jail:
            check_for_go = True
            move_player_after_die_roll(current_player, sum(r), hypothetical_gameboard, check_for_go)
            # add to game history
            hypothetical_gameboard['history']['function'].append(move_player_after_die_roll)
            params = dict()
            params['player'] = current_player
            params['rel_move'] = sum(r)
            params['current_gameboard'] = hypothetical_gameboard
            params['check_for_go'] = check_for_go
            hypothetical_gameboard['history']['param'].append(params)
            hypothetical_gameboard['history']['return'].append(None)

            current_player.process_move_consequences(hypothetical_gameboard)
            # add to game history
            hypothetical_gameboard['history']['function'].append(current_player.process_move_consequences)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = hypothetical_gameboard
            hypothetical_gameboard['history']['param'].append(params)
            hypothetical_gameboard['history']['return'].append(None)

            # post-roll for current player. No out-of-turn moves allowed at this point.
            current_player.make_post_roll_moves(hypothetical_gameboard)
            # add to game history
            hypothetical_gameboard['history']['function'].append(current_player.make_post_roll_moves)
            params = dict()
            params['self'] = current_player
            params['current_gameboard'] = hypothetical_gameboard
            hypothetical_gameboard['history']['param'].append(params)
            hypothetical_gameboard['history']['return'].append(None)

        else:
            current_player.currently_in_jail = False # the player is only allowed to skip one turn (i.e. this one)

        if current_player.current_cash < 0:
            code = current_player.handle_negative_cash_balance(current_player, hypothetical_gameboard)
            # add to game history
            hypothetical_gameboard['history']['function'].append(current_player.handle_negative_cash_balance)
            params = dict()
            params['player'] = current_player
            params['current_gameboard'] = hypothetical_gameboard
            hypothetical_gameboard['history']['param'].append(params)
            hypothetical_gameboard['history']['return'].append(code)
            if code == -1 or current_player.current_cash < 0:
                current_player.begin_bankruptcy_proceedings(hypothetical_gameboard)
                # add to game history
                hypothetical_gameboard['history']['function'].append(current_player.begin_bankruptcy_proceedings)
                params = dict()
                params['self'] = current_player
                params['current_gameboard'] = hypothetical_gameboard
                hypothetical_gameboard['history']['param'].append(params)
                hypothetical_gameboard['history']['return'].append(None)

                num_active_players -= 1
                diagnostics.print_asset_owners(hypothetical_gameboard)
                diagnostics.print_player_cash_balances(hypothetical_gameboard)

                if num_active_players == 1:
                    for p in hypothetical_gameboard['players']:
                        if p.status != 'lost':
                            winner = p
                            p.status = 'won'
        else:
            current_player.status = 'waiting_for_move'

        current_player_index = (current_player_index+1)%len(hypothetical_gameboard['players'])
    print('ENDING HYPOTHETICAL GAMEPLAY AND RETURNING...')
    return winner