Example #1
0
def update_resource_level(experiment,
                          group,
                          round_data,
                          regrowth_rate,
                          max_resource_level=None):
    if max_resource_level is None:
        max_resource_level = get_max_resource_level(
            round_data.round_configuration)
    current_resource_level_dv = get_resource_level_dv(
        group, round_data, shared_resource_enabled=False)
    current_resource_level = current_resource_level_dv.int_value
    group_harvest_dv = get_group_harvest_dv(group, round_data)
    regrowth_dv = get_regrowth_dv(group, round_data)
    # FIXME: would be nicer to extend Group behavior and have group.get_total_harvest() instead of
    # get_total_group_harvest(group, ...), see if we can enable this
    # dynamically
    total_harvest = get_total_group_harvest(group, round_data)
    logger.debug("Harvest: total group harvest for playable round: %s",
                 total_harvest)
    if current_resource_level > 0:
        if total_harvest > current_resource_level:
            adjusted_harvest = adjust_harvest_decisions(
                current_resource_level, group, round_data, total_harvest)
            total_harvest = adjusted_harvest

        group.log("Harvest: removing %s from current resource level %s" %
                  (total_harvest, current_resource_level))
        group_harvest_dv.update_int(total_harvest)
        current_resource_level = current_resource_level - total_harvest
        resource_regrowth = calculate_regrowth(current_resource_level,
                                               regrowth_rate,
                                               max_resource_level)
        group.log("Regrowth: adding %s to current resource level %s" %
                  (resource_regrowth, current_resource_level))
        regrowth_dv.update_int(resource_regrowth)
        # clamp resource
        current_resource_level_dv.update_int(
            min(current_resource_level + resource_regrowth,
                max_resource_level))
    else:
        group.log("current resource level is 0, no one can harvest")
        group_harvest_dv.update_int(0)
        ParticipantRoundDataValue.objects.for_group(
            group,
            parameter=get_harvest_decision_parameter(),
            round_data=round_data).update(is_active=False)
        for pgr in group.participant_group_relationship_set.all():
            # Create adjusted data values
            ParticipantRoundDataValue.objects.create(
                participant_group_relationship=pgr,
                round_data=round_data,
                parameter=get_harvest_decision_parameter(),
                int_value=0)
    ''' XXX: transfer resource levels across chat and quiz rounds if they exist '''
    if experiment.has_next_round:
        ''' set group round data resource_level for each group + regrowth '''
        group.log("Transferring resource level %s to next round" %
                  current_resource_level_dv.int_value)
        group.copy_to_next_round(current_resource_level_dv, group_harvest_dv,
                                 regrowth_dv)
Example #2
0
def _zero_harvest_decisions(participant_group_relationship_ids, round_data):
    # FIXME: possible performance issue, generates two queries per participant
    parameters = (
        get_harvest_decision_parameter(), get_participant_ready_parameter())
    data_values = ParticipantRoundDataValue.objects.filter(round_data=round_data,
                                                           participant_group_relationship__pk__in=participant_group_relationship_ids,
                                                           parameter__in=parameters)
    for dv in data_values:
        if dv.parameter == get_harvest_decision_parameter():
            dv.update_int(0, submitted=True)
        elif dv.parameter == get_participant_ready_parameter():
            dv.update_boolean(True)
Example #3
0
def adjust_harvest_decisions(current_resource_level,
                             group,
                             round_data,
                             total_harvest,
                             group_size=0):
    if group_size == 0:
        group_size = group.size
    # pass in the group size to handle group cluster case
    average_harvest = current_resource_level / group_size
    group.log(
        "GROUP HARVEST ADJUSTMENT - original total harvest: %s, resource level: %s, average harvest: %s"
        % (total_harvest, current_resource_level, average_harvest))
    hds = ParticipantRoundDataValue.objects.for_group(
        group=group,
        parameter=get_harvest_decision_parameter(),
        round_data=round_data,
        int_value__gt=0).order_by('int_value')
    total_adjusted_harvest = 0
    # FIXME: should be the same as group.size
    total_number_of_decisions = hds.count()
    logger.debug("total number of decisions: %s - group size: %s",
                 total_number_of_decisions, group_size)
    decisions_allocated = 0
    for hd in hds:
        if hd.int_value <= average_harvest:
            group.log("preserving %s < average harvest" % hd)
            total_adjusted_harvest += hd.int_value
        else:
            # now to assign the overs, find out how much resource level is
            # remaining
            remaining_resource_level = current_resource_level - \
                total_adjusted_harvest
            remaining_decisions = total_number_of_decisions - \
                decisions_allocated
            average_harvest = remaining_resource_level / remaining_decisions
            hd.is_active = False
            hd.save()
            logger.debug("Assigning %s to hd %s", average_harvest, hd)
            ParticipantRoundDataValue.objects.create(
                participant_group_relationship=hd.
                participant_group_relationship,
                parameter=get_harvest_decision_parameter(),
                round_data=round_data,
                int_value=average_harvest,
                submitted=True)
            total_adjusted_harvest += average_harvest
        decisions_allocated += 1

    logger.debug("harvested total %s", total_adjusted_harvest)
    return total_adjusted_harvest
Example #4
0
def get_total_harvest(participant_group_relationship, session_id):
    q = ParticipantRoundDataValue.objects.for_participant(
        participant_group_relationship,
        parameter=get_harvest_decision_parameter(),
        participant_group_relationship__group__session_id=session_id
    ).aggregate(total_harvest=models.Sum('int_value'))
    return _zero_if_none(q['total_harvest'])
Example #5
0
def get_player_data(group, previous_round_data, current_round_data, self_pgr):
    """ Returns a tuple ([list of player data dictionaries], { dictionary of this player's data })

     FIXME: refactor this into its own class as opposed to an arcane data structure
    """
    prdvs = ParticipantRoundDataValue.objects.for_group(
        group=group,
        round_data__in=[previous_round_data, current_round_data],
        parameter__in=(get_player_status_parameter(), get_storage_parameter(),
                       get_harvest_decision_parameter()))
    # nested dict mapping participant group relationship -> dict(parameter ->
    # participant round data value)
    player_dict = defaultdict(lambda: defaultdict(lambda: None))
    player_status_parameter = get_player_status_parameter()
    for prdv in prdvs:
        player_dict[prdv.participant_group_relationship][prdv.parameter] = prdv
    player_data = []
    for pgr, pgrdv_dict in player_dict.iteritems():
        # FIXME: figure out a way to handle default values elegantly in this case since we aren't using the accessor
        # methods
        for int_parameter in (get_harvest_decision_parameter(),
                              get_storage_parameter()):
            if pgrdv_dict[int_parameter] is None:
                pgrdv_dict[int_parameter] = DefaultValue(0)
        if pgrdv_dict[player_status_parameter] is None:
            pgrdv_dict[player_status_parameter] = DefaultValue(True)
        player_data.append({
            'id':
            pgr.pk,
            'number':
            pgr.participant_number,
            'lastHarvestDecision':
            pgrdv_dict[get_harvest_decision_parameter()].int_value,
            'alive':
            pgrdv_dict[get_player_status_parameter()].boolean_value,
            'storage':
            pgrdv_dict[get_storage_parameter()].int_value
        })
    own_player = player_dict[self_pgr]
    return (player_data, {
        'lastHarvestDecision':
        own_player[get_harvest_decision_parameter()].int_value,
        'alive':
        own_player[get_player_status_parameter()].boolean_value,
        'storage':
        own_player[get_storage_parameter()].int_value
    })
Example #6
0
def _zero_harvest_decisions(participant_group_relationship_ids, round_data):
    data_values = ParticipantRoundDataValue.objects.with_parameter(
        get_harvest_decision_parameter(), round_data=round_data,
        participant_group_relationship__pk__in=participant_group_relationship_ids)
    data_values.update(int_value=0, submitted=True)
    data_values = ParticipantRoundDataValue.objects.with_parameter(
        get_participant_ready_parameter(), round_data=round_data,
        participant_group_relationship__pk__in=participant_group_relationship_ids)
    data_values.update(boolean_value=True)
    '''
def _zero_harvest_decisions(participant_group_relationship_ids, round_data):
    data_values = ParticipantRoundDataValue.objects.with_parameter(
        get_harvest_decision_parameter(), round_data=round_data,
        participant_group_relationship__pk__in=participant_group_relationship_ids)
    data_values.update(int_value=0, submitted=True)
    data_values = ParticipantRoundDataValue.objects.with_parameter(
        get_participant_ready_parameter(), round_data=round_data,
        participant_group_relationship__pk__in=participant_group_relationship_ids)
    data_values.update(boolean_value=True)
    '''
Example #8
0
def round_ended_handler(sender, experiment=None, **kwargs):
    '''
    calculates new resource levels for practice or regular rounds based on the group harvest and resultant regrowth.
    also responsible for transferring those parameters to the next round as needed.
    '''
    round_configuration = experiment.current_round
    round_data = experiment.get_round_data(round_configuration)
    logger.debug("ending boundary effects round: %s", round_configuration)
    try:
        if round_configuration.is_playable_round:
            regrowth_rate = get_regrowth_rate(round_configuration)
            harvest_decision_parameter = get_harvest_decision_parameter()
            for pgr in experiment.participant_group_relationships:
                # FIXME: not thread-safe but this *should* only be invoked once per experiment. If we start getting
                # spurious data values, revisit this section
                prdvs = ParticipantRoundDataValue.objects.filter(
                    round_data=round_data,
                    participant_group_relationship=pgr,
                    parameter=harvest_decision_parameter,
                    is_active=True)
                number_of_harvest_decisions = prdvs.count()
                if number_of_harvest_decisions == 0:
                    # create zero harvest decisions for any unsubmitted harvest decisions
                    ParticipantRoundDataValue.objects.create(
                        round_data=round_data,
                        participant_group_relationship=pgr,
                        parameter=harvest_decision_parameter,
                        is_active=True,
                        int_value=0)
                    logger.debug(
                        "autozero harvest decision for participant %s", pgr)
                elif number_of_harvest_decisions > 1:
                    # deactivate all prior harvest decisions
                    logger.debug(
                        "multiple harvest decisions found for %s, deactivating all but the latest",
                        pgr)
                    final_harvest_decision = prdvs.latest('date_created')
                    prdvs.exclude(pk=final_harvest_decision.pk).update(
                        is_active=False)

            # FIXME: generify and merge update_shared_resource_level and
            # update_resource_level to operate on "group-like" objects if
            # possible
            if is_shared_resource_enabled(round_configuration):
                for group_cluster in experiment.active_group_clusters:
                    update_shared_resource_level(experiment, group_cluster,
                                                 round_data, regrowth_rate)
            else:
                for group in experiment.groups:
                    update_resource_level(experiment, group, round_data,
                                          regrowth_rate)
            update_participants(experiment, round_data, round_configuration)
    except:
        logger.exception('Failed to end round cleanly')
Example #9
0
def adjust_harvest_decisions(current_resource_level, group, round_data, total_harvest, group_size=0):
    if group_size == 0:
        group_size = group.size
    # pass in the group size to handle group cluster case
    average_harvest = current_resource_level / group_size
    group.log("GROUP HARVEST ADJUSTMENT - original total harvest: %s, resource level: %s, average harvest: %s" %
              (total_harvest, current_resource_level, average_harvest))
    hds = ParticipantRoundDataValue.objects.for_group(group=group, parameter=get_harvest_decision_parameter(),
                                                      round_data=round_data, int_value__gt=0).order_by('int_value')
    total_adjusted_harvest = 0
    # FIXME: should be the same as group.size
    total_number_of_decisions = hds.count()
    logger.debug("total number of decisions: %s - group size: %s",
                 total_number_of_decisions, group_size)
    decisions_allocated = 0
    for hd in hds:
        if hd.int_value <= average_harvest:
            group.log("preserving %s < average harvest" % hd)
            total_adjusted_harvest += hd.int_value
        else:
            # now to assign the overs, find out how much resource level is
            # remaining
            remaining_resource_level = current_resource_level - \
                total_adjusted_harvest
            remaining_decisions = total_number_of_decisions - \
                decisions_allocated
            average_harvest = remaining_resource_level / remaining_decisions
            hd.is_active = False
            hd.save()
            logger.debug("Assigning %s to hd %s", average_harvest, hd)
            ParticipantRoundDataValue.objects.create(participant_group_relationship=hd.participant_group_relationship,
                                                     parameter=get_harvest_decision_parameter(), round_data=round_data,
                                                     int_value=average_harvest,
                                                     submitted=True)
            total_adjusted_harvest += average_harvest
        decisions_allocated += 1

    logger.debug("harvested total %s", total_adjusted_harvest)
    return total_adjusted_harvest
Example #10
0
def get_player_data(group, previous_round_data, current_round_data, self_pgr):
    """ Returns a tuple ([list of player data dictionaries], { dictionary of this player's data })

     FIXME: refactor this into its own class as opposed to an arcane data structure
    """
    prdvs = ParticipantRoundDataValue.objects.for_group(group=group,
                                                        round_data__in=[
                                                            previous_round_data, current_round_data],
                                                        parameter__in=(get_player_status_parameter(),
                                                                       get_storage_parameter(),
                                                                       get_harvest_decision_parameter()))
    # nested dict mapping participant group relationship -> dict(parameter ->
    # participant round data value)
    player_dict = defaultdict(lambda: defaultdict(lambda: None))
    player_status_parameter = get_player_status_parameter()
    for prdv in prdvs:
        player_dict[prdv.participant_group_relationship][prdv.parameter] = prdv
    player_data = []
    for pgr, pgrdv_dict in player_dict.iteritems():
        # FIXME: figure out a way to handle default values elegantly in this case since we aren't using the accessor
        # methods
        for int_parameter in (get_harvest_decision_parameter(), get_storage_parameter()):
            if pgrdv_dict[int_parameter] is None:
                pgrdv_dict[int_parameter] = DefaultValue(0)
        if pgrdv_dict[player_status_parameter] is None:
            pgrdv_dict[player_status_parameter] = DefaultValue(True)
        player_data.append({
            'id': pgr.pk,
            'number': pgr.participant_number,
            'lastHarvestDecision': pgrdv_dict[get_harvest_decision_parameter()].int_value,
            'alive': pgrdv_dict[get_player_status_parameter()].boolean_value,
            'storage': pgrdv_dict[get_storage_parameter()].int_value
        })
    own_player = player_dict[self_pgr]
    return (player_data, {
        'lastHarvestDecision': own_player[get_harvest_decision_parameter()].int_value,
        'alive': own_player[get_player_status_parameter()].boolean_value,
        'storage': own_player[get_storage_parameter()].int_value
    })
Example #11
0
def round_ended_handler(sender, experiment=None, **kwargs):
    '''
    calculates new resource levels for practice or regular rounds based on the group harvest and resultant regrowth.
    also responsible for transferring those parameters to the next round as needed.
    '''
    round_configuration = experiment.current_round
    round_data = experiment.get_round_data(round_configuration)
    logger.debug("ending boundary effects round: %s", round_configuration)
    try:
        if round_configuration.is_playable_round:
            regrowth_rate = get_regrowth_rate(round_configuration)
            harvest_decision_parameter = get_harvest_decision_parameter()
            for pgr in experiment.participant_group_relationships:
                # FIXME: not thread-safe but this *should* only be invoked once per experiment.  If we start getting
                # spurious data values, revisit this section
                prdvs = ParticipantRoundDataValue.objects.filter(
                    round_data=round_data,
                    participant_group_relationship=pgr,
                    parameter=harvest_decision_parameter,
                    is_active=True)
                # create zero harvest decisions for any unsubmitted harvest
                # decisions
                if prdvs.count() == 0:
                    prdv = ParticipantRoundDataValue.objects.create(round_data=round_data,
                                                                    participant_group_relationship=pgr,
                                                                    parameter=harvest_decision_parameter,
                                                                    is_active=True,
                                                                    int_value=0)
                    logger.debug(
                        "autozero harvest decision for participant %s", pgr)
                elif prdvs.count() > 1:
                    # another degenerate data condition, deactivate all prior
                    logger.debug(
                        "multiple harvest decisions found for %s, deactivating all but the latest", pgr)
                    prdv = prdvs.latest('id')
                    prdvs.exclude(pk=prdv.pk).update(is_active=False)

            # FIXME: generify and merge update_shared_resource_level and
            # update_resource_level to operate on "group-like" objects if
            # possible
            if is_shared_resource_enabled(round_configuration):
                for group_cluster in experiment.active_group_clusters:
                    update_shared_resource_level(
                        experiment, group_cluster, round_data, regrowth_rate)
            else:
                for group in experiment.groups:
                    update_resource_level(
                        experiment, group, round_data, regrowth_rate)
            update_participants(experiment, round_data, round_configuration)
    except:
        logger.exception('Failed to end round cleanly')
Example #12
0
def update_resource_level(experiment, group, round_data, regrowth_rate, max_resource_level=None):
    if max_resource_level is None:
        max_resource_level = get_max_resource_level(
            round_data.round_configuration)
    current_resource_level_dv = get_resource_level_dv(
        group, round_data, shared_resource_enabled=False)
    current_resource_level = current_resource_level_dv.int_value
    group_harvest_dv = get_group_harvest_dv(group, round_data)
    regrowth_dv = get_regrowth_dv(group, round_data)
    # FIXME: would be nicer to extend Group behavior and have group.get_total_harvest() instead of
    # get_total_group_harvest(group, ...), see if we can enable this
    # dynamically
    total_harvest = get_total_group_harvest(group, round_data)
    logger.debug(
        "Harvest: total group harvest for playable round: %s", total_harvest)
    if current_resource_level > 0:
        if total_harvest > current_resource_level:
            adjusted_harvest = adjust_harvest_decisions(
                current_resource_level, group, round_data, total_harvest)
            total_harvest = adjusted_harvest

        group.log("Harvest: removing %s from current resource level %s" %
                  (total_harvest, current_resource_level))
        group_harvest_dv.update_int(total_harvest)
        current_resource_level = current_resource_level - total_harvest
        resource_regrowth = calculate_regrowth(
            current_resource_level, regrowth_rate, max_resource_level)
        group.log("Regrowth: adding %s to current resource level %s" %
                  (resource_regrowth, current_resource_level))
        regrowth_dv.update_int(resource_regrowth)
        # clamp resource
        current_resource_level_dv.update_int(
            min(current_resource_level + resource_regrowth, max_resource_level))
    else:
        group.log("current resource level is 0, no one can harvest")
        group_harvest_dv.update_int(0)
        ParticipantRoundDataValue.objects.for_group(group, parameter=get_harvest_decision_parameter(),
                                                    round_data=round_data).update(is_active=False)
        for pgr in group.participant_group_relationship_set.all():
            # Create adjusted data values
            ParticipantRoundDataValue.objects.create(participant_group_relationship=pgr,
                                                     round_data=round_data, parameter=get_harvest_decision_parameter(
                                                     ),
                                                     int_value=0)
    ''' XXX: transfer resource levels across chat and quiz rounds if they exist '''
    if experiment.has_next_round:
        ''' set group round data resource_level for each group + regrowth '''
        group.log("Transferring resource level %s to next round" %
                  current_resource_level_dv.int_value)
        group.copy_to_next_round(
            current_resource_level_dv, group_harvest_dv, regrowth_dv)
Example #13
0
def round_started_handler(sender, experiment=None, **kwargs):
    if experiment is None:
        logger.error(
            "Received round started signal with no experiment: %s", sender)
        raise ValueError("Received round started signal with no experiment")
    round_configuration = experiment.current_round
    logger.debug("setting up round %s", round_configuration)
    # initialize group and participant data values
    if round_configuration.is_playable_round:
        experiment.initialize_data_values(
            group_cluster_parameters=(get_group_cluster_bonus_parameter(),),
            group_parameters=(get_group_local_bonus_parameter(),),
            participant_parameters=(get_harvest_decision_parameter(), get_conservation_decision_parameter(),
                                    get_participant_link_parameter(
            ), get_participant_payoff_parameter(),
                get_chat_between_group_parameter(
            ), get_chat_within_group_parameter(),
            )
        )
Example #14
0
def get_total_harvest(participant_group_relationship, session_id):
    q = ParticipantRoundDataValue.objects.for_participant(participant_group_relationship,
                                                          parameter=get_harvest_decision_parameter(),
                                                          participant_group_relationship__group__session_id=session_id).aggregate(
        total_harvest=models.Sum('int_value'))
    return _zero_if_none(q['total_harvest'])
Example #15
0
def get_total_group_harvest(group, round_data):
    q = ParticipantRoundDataValue.objects.for_group(group=group,
                                                    parameter=get_harvest_decision_parameter(),
                                                    round_data=round_data).aggregate(total_harvest=models.Sum('int_value'))
    return _zero_if_none(q['total_harvest'])
Example #16
0
def get_total_group_harvest(group, round_data):
    q = ParticipantRoundDataValue.objects.for_group(
        group=group,
        parameter=get_harvest_decision_parameter(),
        round_data=round_data).aggregate(total_harvest=models.Sum('int_value'))
    return _zero_if_none(q['total_harvest'])