from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random from otreeutils.surveys import ( generate_likert_field, generate_likert_table, create_player_model_for_survey ) from collections import Counter author = 'Nathaniel Burke' doc = """ Identity team based public goods game with switching. """ class Constants(BaseConstants): name_in_url = 'team_game' players_per_group = 4 num_rounds = 20 max_players_in_team = 6 total_players = 8 switching_rounds = [3,6,9,12,15,18] multiplier = [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75] # access multiplier like multiplier[group.team_size-1] ppr = [1.000, 0.625, 0.500, 0.438, 0.400, 0.375, 0.357, 0.344] # access ppr like ppr[group.team_size-1] team_ranges = [[220,420],[100,300]] # 1st is A, 2nd is B class Player(BasePlayer): team = models.IntegerField() #team 1 is Female, team 2 is Male desired_team = models.IntegerField( #1 is stay, 2 is switch choices=[ [1, 'I want to stay with my team'], [2, 'I want to switch teams'], ], widget=widgets.RadioSelect, label="Would you like to switch teams?" ) votes_for_switch = models.IntegerField(initial=0) votes_against_switch = models.IntegerField(initial=0) switch_honored = models.BooleanField() label = models.StringField() voted_for_players = models.StringField() sex = models.IntegerField() endowment = models.CurrencyField() payout = models.CurrencyField() votingchannel = models.IntegerField() comprehension_1 = models.FloatField(label='What is your team multiplier if you have 4 members?') comprehension_2 = models.FloatField(label='If your team has 5 members and your team contributes 500 points in total to the Team account, how many points will be distributed to each team member?') comprehension_3 = models.IntegerField( choices=[ [1, 'Same'], [2, 'Different'], ], widget=widgets.RadioSelect, label="Do the two teams have the same endowment range or different ranges?" ) def comprehension_1_error_message(player, comprehension_1): print('value is', comprehension_1) if comprehension_1 != 1.75: return 'Try again. Check the table to see what your team multiplier is for different number of people on the team' def comprehension_2_error_message(player, comprehension_2): print('value is', comprehension_2) if comprehension_2 != 200: return 'Try again. Check the table to see what the multiplier factor is for having 5 team members. Then, multiply the points by that factor. Last, divide that number by the number of members on the team.' def comprehension_3_error_message(player, comprehension_3): print('value is', comprehension_3) if comprehension_3 != 2: return 'Try again. Look at the table above that lists the multipliers based on how many people are on the team' contribution = models.CurrencyField( min=0, label="How much will you contribute?" ) def get_average_contribution(self): contributionSum = 0 rounds = self.in_rounds(1, self.round_number) for round in rounds: contributionSum += round.contribution return (c(contributionSum) / len(rounds)) def get_average_contribution_pct(self): contributionSum = 0 endowmentSum = 0 rounds = self.in_rounds(1, self.round_number) for round in rounds: contributionSum += float(round.contribution) endowmentSum += float(round.endowment) return (contributionSum/endowmentSum)*100 def get_label(self): return self.participant.label def contribution_max(self): return self.endowment def get_team_contribution(self): return self.group.total_contribution - self.contribution def get_team_size(self): return len(self.group.get_players()) def set_payoffs(self): rounds = self.in_rounds(1, self.round_number) for round in rounds: payoffSum += float(round.payoff) self.participant.vars['group_identity_switch_payoff'] = self.payoffSum def make_field(fChoices, fLabel): return models.IntegerField( choices=fChoices, widget=widgets.RadioSelect, label=fLabel, ) class Subsession(BaseSubsession): def creating_session(self): print('in creating_session', self.round_number) def set_player_endowment(self): for p in self.get_players(): p.sex = p.participant.vars['player_sex'] if p.sex == 1: p.endowment = c(random.randint(Constants.team_ranges[0][0], Constants.team_ranges[0][1])) elif p.sex == 2: p.endowment = c(random.randint(Constants.team_ranges[1][0], Constants.team_ranges[1][1])) def set_player_endowment_2(self): for p in self.get_players(): if p.team == 1: p.endowment = c(random.randint(Constants.team_ranges[0][0], Constants.team_ranges[0][1])) elif p.team == 2: p.endowment = c(random.randint(Constants.team_ranges[1][0], Constants.team_ranges[1][1])) def voting_channel(self): for p in self.get_players(): if p.team == 1: p.votingchannel = 100+self.round_number elif p.team==2: p.votingchannel = 200+self.round_number def group_players(self): players = self.get_players() firstT = [p for p in players if p.sex == 1] secondT = [p for p in players if p.sex == 2] group_matrix = [] group_matrix.append(firstT) group_matrix.append(secondT) self.set_group_matrix(group_matrix) def group_players_new(self): players = self.get_players() firstT = [p for p in players if p.team == 1] secondT = [p for p in players if p.team == 2] group_matrix = [] group_matrix.append(firstT) group_matrix.append(secondT) self.set_group_matrix(group_matrix) def sync_team_by_sex(self): players = self.get_players() for p in players: p.team = p.sex def sync_team_by_previous(self): players = self.get_players() for p in players: if (p.in_round(self.round_number - 1).desired_team == 2 and p.in_round(self.round_number - 1).switch_honored == True): if (p.in_round(self.round_number - 1).team == 2): p.team = 1 else: p.team = 2 else: p.team = p.in_round(self.round_number - 1).team def carry_over_data(self): for p in self.get_players(): # p.endowment = c(p.in_round(self.round_number - 1).payout) p.sex = p.in_round(self.round_number - 1).sex def switch_teams(self): groups = self.get_groups() total_players = 0 for group in groups: total_players += len(group.get_players()) for group in groups: group_size = len(group.get_players()) opposite_group_size = total_players - group_size available_spots = Constants.max_players_in_team - opposite_group_size ordered = group.get_sorted_switch_players() #majority ordered maj_ordered = [] for player in ordered: if (player.votes_for_switch > opposite_group_size/2): maj_ordered.append(player) while (available_spots > 0 and len(maj_ordered) > 0): maj_ordered[len(maj_ordered)-1].switch_honored = True maj_ordered.pop() def count_votes(self): #get all the players players = self.get_players() #use delimiter (,) to put votes in a list votes = [] for player in players: if (player.voted_for_players != "-1"): if not player.voted_for_players == None : votes += player.voted_for_players.split(",") #count votes in the list and store in a dictionary dictionary = Counter(votes) print(dictionary) #Find users based on keys and assign their votes for with dictionary value for key, value in dictionary.items(): #Find user based on key for targetplayer in players: if (str(key).strip() == str(targetplayer.participant_id).strip()): targetplayer.votes_for_switch = value print("test") print(value) break class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() team_size = models.IntegerField() average_share = models.CurrencyField() def attempted(self): players = self.get_players() attempted = [] for player in players: if player.desired_team == 2: attempted.append(player) return attempted def get_joined_team(self): players = self.subsession.get_players() joined = [] for player in players: if player.switch_honored == True and player.team != self.id_in_subsession: joined.append(player) return joined def get_left_team(self): players = self.subsession.get_players() left = [] for player in players: if player.switch_honored == True and player.team == self.id_in_subsession: left.append(player) return left def get_other_sdp(self): players = self.subsession.get_players() otherPlayers = [] for player in players: if self.id_in_subsession != player.team and player.desired_team == 2: otherPlayers.append(player) return otherPlayers def get_other_sdp_size(self): other = self.get_other_sdp() return len(other) def get_switch_desired_players(self): players = self.get_players() switchers = [] for p in players: if (p.desired_team == 2): switchers.append(p) return switchers def get_sorted_switch_players(self): #call this after voting players = self.get_switch_desired_players() players_ordered = [] #lowest votes: idx = 0, highest votes: idx = len(players_ordered)-1 for p in players: idx = 0 inserted = False while (idx < len(players_ordered)): if (p.votes_for_switch >= players_ordered[idx].votes_for_switch): idx += 1 else: players_ordered.insert(idx, p) inserted = True break if not inserted: players_ordered.append(p) return players_ordered def get_multiplier_value(self): return Constants.multiplier[self.team_size-1] def get_ppr_value(self): return Constants.ppr[self.team_size-1] def get_total_contribution_with_multiplier(self): return self.total_contribution * self.get_multiplier_value() def get_ppr_value(self): return Constants.ppr[self.team_size-1] pass