from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random import csv author = 'William Brown' doc = """ STAR voting contest with full information """ class Constants(BaseConstants): name_in_url = 'STAR_voting_CI' players_per_group = 5 num_rounds = 40 num_sessions = int(num_rounds / 10) file = open("STAR_voting_CI/voting_preferences.csv", 'r') data = csv.reader(file, delimiter=',') payouts = [] for x in range(num_sessions): payouts.append(list()) for _ in range(4): payouts[x].append(data.__next__()) class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 10 or self.round_number == 20 or self.round_number == 30: matrix = self.get_group_matrix() for row in matrix: sys_random = random.SystemRandom() sys_random.shuffle(row) self.set_group_matrix(matrix) class Group(BaseGroup): average_A = models.FloatField(initial=0, min=0, max=5) average_B = models.FloatField(initial=0, min=0, max=5) average_C = models.FloatField(initial=0, min=0, max=5) average_D = models.FloatField(initial=0, min=0, max=5) runoff_total_1 = models.IntegerField(initial=0, min=0, max=Constants.players_per_group) runoff_total_2 = models.IntegerField(initial=0, min=0, max=Constants.players_per_group) runoff_cand_1 = models.StringField() runoff_cand_2 = models.StringField() winner = models.StringField() winner_num = models.IntegerField() def get_runoff(self): sys_random = random.SystemRandom() a_ratings = [] b_ratings = [] c_ratings = [] d_ratings = [] runoff_cand = [] players = self.get_players() for p in players: a_ratings.append(p.vote_choice_A) b_ratings.append(p.vote_choice_B) c_ratings.append(p.vote_choice_C) d_ratings.append(p.vote_choice_D) cand_avg = { "A": sum(a_ratings), "B": sum(b_ratings), "C": sum(c_ratings), "D": sum(d_ratings), } self.average_A = cand_avg["A"] self.average_B = cand_avg["B"] self.average_C = cand_avg["C"] self.average_D = cand_avg["D"] for name, votes in cand_avg.items(): runoff_cand.append((name,votes)) def takeSecond(elem): return elem[1] sys_random.shuffle(runoff_cand) runoff_cand.sort(key=takeSecond, reverse=True) del runoff_cand[2:4] return [item[0] for item in runoff_cand] def determine_winner(self, runoff_cands): sys_random = random.SystemRandom() players = self.get_players() self.runoff_cand_1 = runoff_cands[0] self.runoff_cand_2 = runoff_cands[1] candidate_votes = { } for c in runoff_cands: candidate_votes[c] = 0 for p in players: vote_choices = { "A": p.vote_choice_A, "B": p.vote_choice_B, "C": p.vote_choice_C, "D": p.vote_choice_D, } player_vote = [] maximum = 0 for c in runoff_cands: if vote_choices[c] == maximum: player_vote.append(c) if vote_choices[c] > maximum: player_vote = [] player_vote.append(c) maximum = vote_choices[c] if len(player_vote) > 1: pass else: player_vote = "".join(player_vote) candidate_votes[player_vote] += 1 self.runoff_total_1 = candidate_votes[runoff_cands[0]] self.runoff_total_2 = candidate_votes[runoff_cands[1]] winning_candidate = [] maximum = 0 for name, votes in candidate_votes.items(): if votes == maximum: winning_candidate.append(name) if votes > maximum: winning_candidate = [] winning_candidate.append(name) maximum = votes self.winner = sys_random.choice(winning_candidate) self.winner_num = 0 if self.winner == "A": self.winner_num = 0 elif self.winner == "B": self.winner_num = 1 elif self.winner == "C": self.winner_num = 2 else: self.winner_num = 3 def get_payoffs(self): players = self.get_players() for p in players: p.round_payoff = int(Constants.payouts[(self.round_number-1) // 10][self.winner_num][p.id_in_group - 1]) p.payoff += p.round_payoff class Player(BasePlayer): player_payoff = models.StringField() round_payoff = models.IntegerField() vote_choice_A = models.IntegerField( choices=[1, 2, 3, 4], doc="""Rating of player for candidate A""" ) vote_choice_B = models.IntegerField( choices=[1, 2, 3, 4], doc="""Rating of player for candidate B""" ) vote_choice_C = models.IntegerField( choices=[1, 2, 3, 4], doc="""Rating of player for candidate C""" ) vote_choice_D = models.IntegerField( choices=[1, 2, 3, 4], doc="""Rating of player for candidate D""" ) def player_payoff_1(self): self.player_payoff = Constants.payouts[(self.round_number-1) // 10][0][self.id_in_group - 1] return self.player_payoff def player_payoff_2(self): self.player_payoff = Constants.payouts[(self.round_number-1) // 10][1][self.id_in_group - 1] return self.player_payoff def player_payoff_3(self): self.player_payoff = Constants.payouts[(self.round_number-1) // 10][2][self.id_in_group - 1] return self.player_payoff def player_payoff_4(self): self.player_payoff = Constants.payouts[(self.round_number-1) // 10][3][self.id_in_group - 1] return self.player_payoff