from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) doc = '' class Constants(BaseConstants): name_in_url = 'Lying_Test' players_per_group = 2 num_rounds = 60 playerA_initial_endowment = c(0) fee = c(1) playerB_initial_endowment = fee * 2 penalty = fee * 2 max_rounds_per_payer = 6 class Subsession(BaseSubsession): # Define variables to be stored in database and used for round skipping/management round_used = models.BooleanField(initial=False) first_player = models.IntegerField(initial=0) second_player = models.IntegerField(initial=0) # Function to randomize treament assignment ONLY to the group for the specific round (called on Wait0) def group_randomization(self, current_player, round_used, first_player, second_player): if round_used == True: import random groups = self.get_groups() for group in groups: group_members = group.get_players() if current_player in group_members: chosen_group = group if current_player.participant.id_in_session in [first_player, second_player] and not chosen_group.TRANSFER_SUCCESS in [True, False]: chosen_group.TRANSFER_SUCCESS = random.choice([True, False]) if chosen_group.TRANSFER_SUCCESS == True: chosen_group.transfer_short = "Transfer succeeded" else: chosen_group.transfer_short = "Transfer failed" print('transfer success =', chosen_group.TRANSFER_SUCCESS) chosen_group.DECISION_FIRST = random.choice([True, False]) print('decision first =', chosen_group.DECISION_FIRST) # Fucntion to check and randomize groups by arrival time (called by 'group_by_arrival_time = True' in Wait0) def group_by_arrival_time_method(self, waiting_players): import random print("Number of players in waiting area: " + str(len(waiting_players))) print("Round #: " + str(self.round_number)) for p in waiting_players: if p.waiting_too_long(): p.participant.vars['participant_done'] = True print("No pairing found... player proceeding to next section") return [p] else: if len(waiting_players) == 1: print("Only one player, waiting for additional players to create group...") else: current_player = waiting_players[len(waiting_players)-1] other_players = waiting_players[:len(waiting_players)-1] # Create a matrix of all the previous groupings (only the actually playable groups) old_matrix = [] for ii in range(1,self.round_number): self.group_like_round(ii) old_matrix2 = self.get_group_matrix() for jj in range(0, len(old_matrix2)): # Only include the groups in which there are 2 in them (to exclude non-playable groups) if len(old_matrix2[jj]) == 2: old_matrix.append(old_matrix2[jj]) # Create matrix for all previous pairings for THAT specific player players_prev_pairings = [] for ii in range(0, len(old_matrix)): if current_player in old_matrix[ii]: players_prev_pairings.append(old_matrix[ii]) players_potential_pairings = [] for ii in range(0, len(other_players)): players_potential_pairings.append([current_player, other_players[ii]]) players_potential_pairings.append([other_players[ii], current_player]) filtered_pairings = [item for item in players_potential_pairings if item not in players_prev_pairings] # print("filtered_pairings:") # print(filtered_pairings) if len(filtered_pairings) == 0: print("New vaild pairings, waiting on new player...") else: chosen_pairing = random.choice(filtered_pairings) self.round_used = True self.first_player = chosen_pairing[0].participant.id_in_session self.second_player = chosen_pairing[1].participant.id_in_session all_players = self.get_players() for player in all_players: if self.round_number == 1: if player in chosen_pairing: player.player_round_num = player.player_round_num + 1 else: player.player_round_num = player.player_round_num else: if player in chosen_pairing: player.player_round_num = player.in_round(self.round_number-1).player_round_num + 1 else: player.player_round_num = player.in_round(self.round_number - 1).player_round_num return chosen_pairing class Group(BaseGroup): TRANSFER_SUCCESS = models.BooleanField() DECISION_FIRST = models.BooleanField() A_META_BELIEVE = models.FloatField(min=0, max=1, widget=widgets.Slider(attrs={'step': '0.01'})) B_TRANSFER = models.BooleanField(choices=[[True, 'Yes'], [False, 'No']], widget=widgets.RadioSelectHorizontal) B_BELIEVE = models.FloatField(min=0, max=1, widget=widgets.Slider(attrs={'step': '0.01'})) automatic_transfer_result = models.StringField() b_transfer_result = models.StringField() penalty_result = models.StringField() transfer_short = models.StringField() def group_randomization(self): import random self.TRANSFER_SUCCESS = random.choice([True, False]) if self.TRANSFER_SUCCESS == True: self.transfer_short = "Transfer succeeded" else: self.transfer_short = "Transfer failed" print('transfer success =', self.TRANSFER_SUCCESS) self.DECISION_FIRST = random.choice([True, False]) print('decision first =', self.DECISION_FIRST) def set_payoffs(self): group_members = self.get_players() for player in group_members: role = player.role() if role == "Seller": player.payoff = Constants.playerA_initial_endowment + self.TRANSFER_SUCCESS * Constants.fee + self.B_TRANSFER * Constants.fee else: player.payoff = Constants.playerB_initial_endowment - self.TRANSFER_SUCCESS * Constants.fee - self.B_TRANSFER * Constants.fee - (1-self.TRANSFER_SUCCESS) * (1-self.B_TRANSFER) * 2 * Constants.fee if self.TRANSFER_SUCCESS == True: self.automatic_transfer_result = "Automatic transfer was successful." else: self.automatic_transfer_result = "Automatic transfer was NOT successful." if self.B_TRANSFER == True: self.b_transfer_result = "'Buyer' agreed to transfer the amount due." else: self.b_transfer_result = "'Buyer' refused to transfer the amount due." if self.TRANSFER_SUCCESS == False and self.B_TRANSFER == False: self.penalty_result = "Therefore, a penalty against the 'buyer' was applied." else: self.penalty_result = "" class Player(BasePlayer): player_round_num = models.IntegerField(initial=0) def role(self): return {1: 'Seller', 2: 'Buyer'}[self.id_in_group] def completion_check(self): if self.player_round_num == Constants.max_rounds_per_payer: self.participant.vars['participant_done'] = True return "" def waiting_too_long(self): import time return time.time() - self.participant.vars['wait_page_arrival'] > 10*60