from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) from random import sample, choice, random, shuffle from types import SimpleNamespace import datetime from time import time from math import ceil, floor from numpy import array_split import pytz author = 'Eva Vriens' doc = """ Sequential Hawk Dove Game - PRIN Honour Norms project """ class Constants(BaseConstants): name_in_url = 'seq_hawk_dove_1' num_rounds = 1 players_per_group = 5 allowed_timeouts = 3 # For testing test = False inc_norms = True inc_risksvo = True # Punishment punish_r = 3 # Punishment costs 3 points for receiver punish_s = 1 # Punishment costs 1 point for sender # Incentivization norm questions norm_inc = 1 appr_inc = 0.5 # Payment exchange_rate = 0.25 sn_pnb = 't4_seq_hawk_dove_1/sn_pnb.html' sn_ee = 't4_seq_hawk_dove_1/sn_ee.html' sn_ne = 't4_seq_hawk_dove_1/sn_ne.html' ap_beh = 't4_seq_hawk_dove_1/ap_beh.html' ap_pun = 't4_seq_hawk_dove_1/ap_pun.html' instr1 = 't4_instr/Instr1.html' instr2 = 't4_instr/Instr2.html' instr3 = 't4_instr/Instr3.html' instr4 = 't4_instr/Instr4.html' instr5 = 't4_instr/Instr5.html' class Subsession(BaseSubsession): num_active = models.IntegerField() value = models.IntegerField() cost = models.IntegerField() showup = models.FloatField() endowment = models.IntegerField() reputation = models.BooleanField() def creating_session(self): # Cost and value self.endowment = 3 self.showup = 3.5 if self.session.config['vc_ratio'] == 'high': # ratio = 1/2 self.value = 6 self.cost = 12 else: # ratio = 1/4 self.value = 2 self.cost = 8 self.reputation = self.session.config['reputation'] for p in self.get_players(): p.participant.vars['num_timeouts'] = 0 p.participant.vars['choice_if_challenged'] = [] p.participant.vars['dsel_last7'] = [] p.participant.vars['experimentended'] = 'no' # alternative: 'plb' if no group members left; 'pla' if no attacker; 'ns' if never started p.participant.vars['num_selected'] = 0 p.participant.vars['num_likes'] = 0 def shuffle_groups(self): # Create groups and assign player roles # Sort players > from player list where if inactive player has score 1 sorted_players = sorted( self.get_players(), key=lambda player: player.participant.vars['score'] ) print('sorted players list', sorted_players) group_matrix = [] group_matrix_ids = [] ppg = Constants.players_per_group for i in range(0, len(sorted_players), ppg): group_matrix.append(sorted_players[i:i + ppg]) print(group_matrix) # Store in session vars to retrieve for next round shuffling in group treatments for pg in group_matrix: group_matrix_ids.append([p.id_in_subsession for p in pg]) print('Group matrix ids = ', group_matrix_ids) self.session.vars['group_matrix'] = group_matrix_ids self.set_group_matrix(group_matrix) # If there are inactive players they are altogether in the final group # In case an active player is grouped with otherwise inactive players > no payoff / this round doesn't count def norm_calculations(self): print('Calculation norm incentives') for p in self.get_players(): # If bot decision after timeout wasn't registered -> repeat bot decision if p.ee is None: p.ee = -99 if p.ne is None: p.ne = -99 if p.pnb is None: p.pnb = -99 # if p.beh_u is None: # p.beh_u = -99 # if p.beh_d is None: # p.beh_d = -99 if p.pun_u is None: p.pun_u = -99 if p.pun_d is None: p.pun_d = -99 # Calculate payoff for defenders if p.participant.vars['role'] == 'defender' and not p.inactive: # ----- FIRST ROUND ----- # # Empirical expectations num_down = len([q for q in p.get_others_in_subsession() if q.choice_d == 1 and q.participant.vars['role'] == 'defender' and not q.inactive]) num_defs = len([q for q in p.get_others_in_subsession() if q.participant.vars['role'] == 'defender' and q.choice_d < 2 and not q.inactive]) print('Num that played down = {} and num active defenders = {}'.format(num_down, num_defs)) print('List of players that played down = ', [q for q in p.get_others_in_subsession() if q.choice_d == 1 and q.participant.vars['role'] == 'defender' and not q.inactive]) if num_down > 0: p.ee_percdown1 = round(num_down / num_defs * 100) else: p.ee_percdown1 = 0 if p.ee >= 0: p.ee_payoff1 = round((100 - abs(p.ee - p.ee_percdown1)) / 100, 2) else: print('Player did not make decision in time so ee payoff = 0') p.ee_payoff1 = 0 print('%D = {}, EE = {}, EE payoff = {}'.format(p.ee_percdown1, p.ee, p.ee_payoff1)) p.participant.vars['ee_payoff1'] = p.ee_payoff1 # Normative expectations num_down = len([q for q in p.get_others_in_subsession() if q.pnb == 1 and q.participant.vars['role'] == 'defender' and not q.inactive]) if num_down > 0: p.ne_percdown1 = round(num_down / num_defs * 100) else: p.ne_percdown1 = 0 if p.ne >= 0: p.ne_payoff1 = round((100 - abs(p.ne - p.ne_percdown1)) / 100, 2) else: print('Player did not make decision in time so ne payoff = 0') p.ne_payoff1 = 0 print('%D = {}, NE = {}, NE payoff = {}'.format(p.ne_percdown1, p.ne, p.ne_payoff1)) p.participant.vars['ne_payoff1'] = p.ne_payoff1 # Appropriateness choosing up # print('BEH_U = ', p.beh_u) # ans_up = [q.beh_u for q in p.get_others_in_subsession() if # q.beh_u > 0 and q.participant.vars['role'] == 'defender' and not q.inactive] # p.mode_bu1 = max(set(ans_up), key=ans_up.count) if ans_up else 0 # p.payoff_bu1 = Constants.appr_inc if p.beh_u == p.mode_bu1 else 0 # print('List of answers bup = ', ans_up) # print('Mode bup = {}, guess = {}, payoff = {}'.format(p.mode_bu1, p.beh_u, p.payoff_bu1)) # p.participant.vars['payoff_bu1'] = p.payoff_bu1 # Appropriateness choosing down # ans_down = [q.beh_d for q in p.get_others_in_subsession() if # q.beh_d > 0 and q.participant.vars['role'] == 'defender' and not q.inactive] # p.mode_bd1 = max(set(ans_down), key=ans_down.count) if ans_down else 0 # p.payoff_bd1 = Constants.appr_inc if p.beh_d == p.mode_bd1 else 0 # print('List of answers bup = ', ans_down) # print('Mode bdown = {}, guess = {}, payoff = {}'.format(p.mode_bd1, p.beh_d, p.payoff_bd1)) # p.participant.vars['payoff_bd1'] = p.payoff_bd1 # Appropriateness punishing if up ans_up = [q.pun_u for q in p.get_others_in_subsession() if q.pun_u > 0 and q.participant.vars['role'] == 'defender' and not q.inactive] p.mode_pu1 = max(set(ans_up), key=ans_up.count) if ans_up else 0 p.payoff_pu1 = Constants.appr_inc if p.pun_u == p.mode_pu1 else 0 print('List of answers bup = ', ans_up) print('Mode pup = {}, guess = {}, payoff = {}'.format(p.mode_pu1, p.pun_u, p.payoff_pu1)) p.participant.vars['payoff_pu1'] = p.payoff_pu1 # Appropriateness punishing if down ans_down = [q.pun_d for q in p.get_others_in_subsession() if q.pun_d > 0 and q.participant.vars['role'] == 'defender' and not q.inactive] p.mode_pd1 = max(set(ans_down), key=ans_down.count) if ans_down else 0 p.payoff_pd1 = Constants.appr_inc if p.pun_d == p.mode_pd1 else 0 print('List of answers bup = ', ans_down) print('Mode pdown = {}, guess = {}, payoff = {}'.format(p.mode_pd1, p.pun_d, p.payoff_pd1)) p.participant.vars['payoff_pd1'] = p.payoff_pd1 class Group(BaseGroup): attacker_active = models.IntegerField() defenders_active = models.IntegerField() attacker_id = models.IntegerField() defender1_id = models.IntegerField() defender2_id = models.IntegerField() defender3_id = models.IntegerField() defender4_id = models.IntegerField() no_attacker = models.BooleanField(initial=False) attack_paid = models.IntegerField(initial=0) num_decisions = models.IntegerField() num_likes = models.IntegerField() # Number of likes assigned in this round num_punishers = models.IntegerField(initial=0) # Defender's choices if challenged d1_up = models.IntegerField(initial=0) d1_down = models.IntegerField(initial=0) d1_total = models.IntegerField(initial=0) d2_up = models.IntegerField(initial=0) d2_down = models.IntegerField(initial=0) d2_total = models.IntegerField(initial=0) d3_up = models.IntegerField(initial=0) d3_down = models.IntegerField(initial=0) d3_total = models.IntegerField(initial=0) d4_up = models.IntegerField(initial=0) d4_down = models.IntegerField(initial=0) d4_total = models.IntegerField(initial=0) # Group-level treatments dsel_id = models.IntegerField() dsel_choice = models.IntegerField() dsel_round_payoff = models.FloatField() dsel_up7 = models.IntegerField(initial=0) dsel_down7 = models.IntegerField(initial=0) dsel_total7 = models.IntegerField(initial=0) def assign_roles(self): print('ASSIGN ROLES IN ROUND ', self.round_number) player_roles = {} sorted_players = sorted( self.get_players(), key=lambda player: player.participant.vars['score'] ) id = 0 for p in sorted_players: # if self.round_number == 1: # If individual treatments -> assign id's randomly based on score variable (attacker gets id = 0) p.defender_id = id p.participant.vars['defender_id'] = p.defender_id id += 1 # For all treatments and all rounds: assign roles p.role() player_roles[p] = p.role() print('Player roles in round ', self.round_number, ' are ', player_roles) # Number of active players self.defenders_active = len([p for p in self.get_players() if p.participant.vars['role'] == 'defender']) # and p.score < 1]) self.attacker_active = len([p for p in self.get_players() if p.participant.vars['role'] == 'attacker']) # and p.score < 1]) self.attacker_id = self.get_player_by_role('attacker').id_in_subsession self.defender1_id = self.get_player_by_role('defender1').id_in_subsession self.defender2_id = self.get_player_by_role('defender2').id_in_subsession self.defender3_id = self.get_player_by_role('defender3').id_in_subsession self.defender4_id = self.get_player_by_role('defender4').id_in_subsession def set_payoffs(self): attacker = self.get_player_by_role('attacker') if not self.session.config['group']: defenders = [ {'defender': self.get_player_by_role('defender1'), 'choice_a': attacker.choice_a1, 'id': 1}, {'defender': self.get_player_by_role('defender2'), 'choice_a': attacker.choice_a2, 'id': 2}, {'defender': self.get_player_by_role('defender3'), 'choice_a': attacker.choice_a3, 'id': 3}, {'defender': self.get_player_by_role('defender4'), 'choice_a': attacker.choice_a4, 'id': 4} ] else: defenders = [ {'defender': self.get_player_by_role('defender1'), 'choice_a': attacker.choice_a1, 'id': 1}, {'defender': self.get_player_by_role('defender2'), 'choice_a': attacker.choice_a1, 'id': 2}, {'defender': self.get_player_by_role('defender3'), 'choice_a': attacker.choice_a1, 'id': 3}, {'defender': self.get_player_by_role('defender4'), 'choice_a': attacker.choice_a1, 'id': 4} ] print(defenders) if self.session.config['group']: # Store attacker choice as defender variable for d in defenders: d['defender'].choice_a1 = d['choice_a'] # attacker.choice_a1 # For group treatments: select defender to respond # Prepare dictionary: how often defender has been selected dict_num_selected = {} for d in defenders: # if self.round_number > 1: # d['defender'].num_selected = d['defender'].in_round(self.round_number - 1).num_selected # Add to dictionary only if defener made a valid choice (< 2) if not d['defender'].choice_d == 2: dict_num_selected[d['id']] = d['defender'].num_selected print('$$$$$$ Defenders have been selected to respond X times:', dict_num_selected) valid_decisions = [] if len(dict_num_selected) > 0: minval = min(dict_num_selected.values()) valid_decisions = [k for k, v in dict_num_selected.items() if v == minval] # else: no defender made valid choice if self.round_number > 4 and len(list(dict_num_selected)) >= 2: # Add two random ids to avoid going in perfect order valid_decisions += sample(list(dict_num_selected), 2) print('$$$$$$ Defenders left to choose from with minimum number selected:', valid_decisions) if attacker.choice_a1 == 1: if valid_decisions: # For group treatments: attack_paid signals selected player from valid decisions list # For individual treatments: attack_paid selects one of attacker decisions for payment self.attack_paid = choice(valid_decisions) print('$$$$$$$ The selected defender is', self.attack_paid) else: # If none of the defenders made a valid choice in time self.attack_paid = 99 for d in defenders: # If defender is selected defender: if self.attack_paid == d['id']: d['defender'].was_challenged = True d['defender'].participant.vars['choice_if_challenged'].append(d['defender'].choice_d) print('Choices if challenged', d['defender'].participant.vars['choice_if_challenged']) if d['defender'].choice_d == 1: d['defender'].fight = True else: d['defender'].fight = False # if self.round_number == 1: d['defender'].num_selected += 1 # else: # d['defender'].num_selected = d['defender'].in_round(self.round_number - 1).num_selected + 1 print('$$$$$$$ Increase in num_selected, now', d['defender'].num_selected) # Remaining defenders elif d['choice_a'] == 1 and self.attack_paid != d['id']: # attacker.choice_a1 == 1 and self.attack_paid != d['id']: d['defender'].was_challenged = False d['defender'].fight = False # If selected: store in part vars for next round/app d['defender'].participant.vars['num_selected'] = d['defender'].num_selected # Get decision of selected defender if self.attack_paid == 1: self.dsel_choice = self.get_player_by_role('defender1').choice_d self.dsel_id = self.get_player_by_role('defender1').id_in_subsession self.get_player_by_role('defender1').selected_defender = True elif self.attack_paid == 2: self.dsel_choice = self.get_player_by_role('defender2').choice_d self.dsel_id = self.get_player_by_role('defender2').id_in_subsession self.get_player_by_role('defender2').selected_defender = True elif self.attack_paid == 3: self.dsel_choice = self.get_player_by_role('defender3').choice_d self.dsel_id = self.get_player_by_role('defender3').id_in_subsession self.get_player_by_role('defender3').selected_defender = True elif self.attack_paid == 4: self.dsel_choice = self.get_player_by_role('defender4').choice_d self.dsel_id = self.get_player_by_role('defender4').id_in_subsession self.get_player_by_role('defender4').selected_defender = True elif self.attack_paid == 99: # No choice made by any of the defenders: self.dsel_choice = 2 else: # Attacker did not attack: for d in defenders: d['defender'].was_challenged = False d['defender'].fight = False self.dsel_choice = 2 print('SELECTED CHOICE CHECK', self.dsel_choice) if self.dsel_choice < 2: attacker.participant.vars['dsel_last7'].append(self.dsel_choice) # SET PAYOFFS if attacker.choice_a1 == 1: # Payoffs if attacker attacks and defender defends: if self.dsel_choice == 1: # self.d1_down += 1 self.dsel_round_payoff = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 attacker.round_payoff = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 # Payoffs if attacker attacks and defender does nothing: elif self.dsel_choice == 0: # self.d1_up += 1 self.dsel_round_payoff = self.subsession.endowment attacker.round_payoff = self.subsession.endowment + self.subsession.value # Payoffs if none of the defenders made a choice elif self.dsel_choice == 2: self.dsel_round_payoff = 0 attacker.round_payoff = 0 # Payoffs if attacker doesn't attack elif attacker.choice_a1 == 0: attacker.round_payoff = self.subsession.endowment self.dsel_round_payoff = self.subsession.endowment + self.subsession.value # Payoff if attacker doesn't make choice elif attacker.choice_a1 == 2: self.dsel_round_payoff = 0 attacker.round_payoff = 0 for d in defenders: # Store the dictionary of focal player choices for each defender # d['defender'].participant.vars['choice_if_challenged'].append(self.dsel_choice) d['defender'].round_payoff = self.dsel_round_payoff # !!!!!!!!! TBD: If payoff for fight should vary depending on whether defender is selected or not print('@@@ Selected defender payoff = ', self.dsel_round_payoff) else: # Individual level treatments # Payoff for defenders for d in defenders: # Store attacker choice under a1 for all defenders d['defender'].choice_a1 = d['choice_a'] if d['defender'].choice_d == 2: # no decision was made so no payoff this round d['defender'].round_payoff = 0 d['defender'].not_valid = True else: # If A attacked if d['choice_a'] == 1: d['defender'].was_challenged = True d['defender'].participant.vars['choice_if_challenged'].append(d['defender'].choice_d) print('Choices if challenged', d['defender'].participant.vars['choice_if_challenged']) if d['defender'].choice_d == 1: # d['defender'].num_down += 1 d['defender'].round_payoff = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 d['defender'].fight = True elif d['defender'].choice_d == 0: # d['defender'].num_up += 1 d['defender'].round_payoff = self.subsession.endowment d['defender'].fight = False # If A didn't do anything elif d['choice_a'] == 0: d['defender'].was_challenged = False d['defender'].fight = False d['defender'].round_payoff = self.subsession.endowment + self.subsession.value # If A didn't make a choice if d['choice_a'] == 2: d['defender'].was_challenged = False d['defender'].timeout_other = True d['defender'].not_valid = True d['defender'].round_payoff = 0 # First store attacker's round payoff against each defender decision for results table for d in defenders: if d['id'] == 1: if d['choice_a'] == 1: if d['defender'].choice_d == 1: attacker.rpayoff1 = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 elif d['defender'].choice_d == 0: attacker.rpayoff1 = self.subsession.endowment + self.subsession.value elif d['choice_a'] == 0: attacker.rpayoff1 = self.subsession.endowment elif d['choice_a'] == 2: attacker.rpayoff1 = 0 attacker.not_valid = True elif d['id'] == 2: if d['choice_a'] == 1: if d['defender'].choice_d == 1: attacker.rpayoff2 = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 elif d['defender'].choice_d == 0: attacker.rpayoff2 = self.subsession.endowment + self.subsession.value elif d['choice_a'] == 0: attacker.rpayoff2 = self.subsession.endowment elif d['choice_a'] == 2: attacker.rpayoff2 = 0 attacker.not_valid = True elif d['id'] == 3: if d['choice_a'] == 1: if d['defender'].choice_d == 1: attacker.rpayoff3 = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 elif d['defender'].choice_d == 0: attacker.rpayoff3 = self.subsession.endowment + self.subsession.value elif d['choice_a'] == 0: attacker.rpayoff3 = self.subsession.endowment elif d['choice_a'] == 2: attacker.rpayoff3 = 0 attacker.not_valid = True elif d['id'] == 4: if d['choice_a'] == 1: if d['defender'].choice_d == 1: attacker.rpayoff4 = self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2 elif d['defender'].choice_d == 0: attacker.rpayoff4 = self.subsession.endowment + self.subsession.value elif d['choice_a'] == 0: attacker.rpayoff4 = self.subsession.endowment elif d['choice_a'] == 2: attacker.rpayoff4 = 0 attacker.not_valid = True # Calculate round payoff for attacker > randomly draw one decision against valid_decisions = [] for d in defenders: # Draw random payoff only from decisions against defenders where both A and B made their decision in time if not d['defender'].choice_d == 2 or d['choice_a'] == 2: valid_decisions.append(d['id']) print('List of valid decisions for payoff attacker = ', valid_decisions) self.num_decisions = len(valid_decisions) if valid_decisions: self.attack_paid = choice(valid_decisions) if self.attack_paid == 1: attacker.round_payoff = attacker.rpayoff1 elif self.attack_paid == 2: attacker.round_payoff = attacker.rpayoff2 elif self.attack_paid == 3: attacker.round_payoff = attacker.rpayoff3 elif self.attack_paid == 4: attacker.round_payoff = attacker.rpayoff4 else: # If neither defender made a decision in time: no payoff this round attacker.not_valid = True attacker.round_payoff = 0 def defender_choices(self): defender1 = self.get_player_by_role('defender1').participant.vars['choice_if_challenged'] num_up_down = {i: defender1.count(i) for i in defender1} self.d1_up = num_up_down.get(0, 0) self.d1_down = num_up_down.get(1, 0) self.d1_total = self.d1_down + self.d1_up print('Defender 1 played {} up and {} down'.format(self.d1_up, self.d1_down)) defender2 = self.get_player_by_role('defender2').participant.vars['choice_if_challenged'] num_up_down = {i: defender2.count(i) for i in defender2} self.d2_up = num_up_down.get(0, 0) self.d2_down = num_up_down.get(1, 0) self.d2_total = self.d2_down + self.d2_up defender3 = self.get_player_by_role('defender3').participant.vars['choice_if_challenged'] num_up_down = {i: defender3.count(i) for i in defender3} self.d3_up = num_up_down.get(0, 0) self.d3_down = num_up_down.get(1, 0) self.d3_total = self.d3_down + self.d3_up defender4 = self.get_player_by_role('defender4').participant.vars['choice_if_challenged'] num_up_down = {i: defender4.count(i) for i in defender4} self.d4_up = num_up_down.get(0, 0) self.d4_down = num_up_down.get(1, 0) self.d4_total = self.d4_down + self.d4_up if self.session.config['group']: self.dsel_up7 = self.d1_up + self.d2_up + self.d3_up + self.d4_up self.dsel_down7 = self.d1_down + self.d2_down + self.d3_down + self.d4_down self.dsel_total7 = self.dsel_up7 + self.dsel_down7 def rewards(self): current_likes = 0 for p in self.get_players(): if p.participant.vars['role'] == 'defender' and p.rewpun == 1: p.reward = True if p.reward: current_likes += 1 print('Number of likes given = ', current_likes) self.num_likes = current_likes for p in self.get_players(): if p.defender_id == self.attack_paid: # if self.round_number == 1: p.num_likes = current_likes # else: # p.num_likes = p.in_round(self.round_number - 1).num_likes + current_likes print('Number of likes for selected player = ', p.num_likes) else: # if self.round_number == 1: p.num_likes == 0 # else: # p.num_likes = p.in_round(self.round_number - 1).num_likes p.participant.vars['num_likes'] = p.num_likes def punishments(self): num_punishments = 0 for p in self.get_players(): if p.participant.vars['role'] == 'defender' and p.rewpun == 3: p.punish = True if p.punish: print('THIS PLAYER PUNISHED') num_punishments += 1 p.round_payoff -= Constants.punish_s print('Number of punishments given = ', num_punishments) for p in self.get_players(): if p.defender_id == self.attack_paid: self.num_punishers = num_punishments p.round_payoff -= Constants.punish_r * self.num_punishers self.dsel_round_payoff -= Constants.punish_r * self.num_punishers print('Number of punishments for selected player = ', self.num_punishers) class Player(BasePlayer): # Score for grouping inactive = models.BooleanField(initial=False) prac_missed = models.IntegerField() score = models.FloatField() # Attacker makes 4 choices each round: choice_a1 = models.IntegerField( choices=[ [1, 'Challenge'], [0, 'Leave'], [99, 'No choice'], ], widget=widgets.RadioSelect, label="", # initial=99, ) choice_a2 = models.IntegerField( choices=[ [1, 'Challenge'], [0, 'Leave'], ], widget=widgets.RadioSelect, label="", # initial=99, ) choice_a3 = models.IntegerField( choices=[ [1, 'Challenge'], [0, 'Leave'], ], widget=widgets.RadioSelect, label="", # initial=99, ) choice_a4 = models.IntegerField( choices=[ [1, 'Challenge'], [0, 'Leave'], ], widget=widgets.RadioSelect, label="", # initial=99, ) # Defender makes 1 choice per round choice_d = models.IntegerField( choices=[ [0, 'Up'], # 'Acquiesce'], [1, 'Down'], # 'Resist'], ], widget=widgets.RadioSelect, label="", ) experimentended = models.BooleanField(initial=False) not_valid = models.BooleanField(initial=False) # For payoff: Set to true if attacker or defender didn't make choice (= 2) # Treatment 5/6: Reward system reward = models.BooleanField(initial=False, blank=True) # Like not mandatory, so blank=True num_likes = models.IntegerField(initial=0) rewpun = models.IntegerField(initial=2, blank=True, choices=[ [1, 'reward'], [2, 'nothing'], [3, 'punish'] ]) # Treatment 6: Punishment system punish = models.BooleanField(initial=False, blank=True) # Punishment not mandatory, so blank=True # For defenders: defender_id = models.IntegerField() # id used to assign to defender role was_challenged = models.BooleanField() # stores per round whether defender was challenged fight = models.BooleanField() # stores per round if attacker and defender fight selected_defender = models.BooleanField(initial=False) num_selected = models.IntegerField(initial = 0) # Number of times up/down chosen if challenged # num_up = models.IntegerField(initial=0) # num_down = models.IntegerField(initial=0) playing_status = models.IntegerField( choices=[ [1, 'Attacker'], [2, 'Defender'], ], ) round_payoff = models.FloatField() rpayoff1 = models.FloatField(initial=0) rpayoff2 = models.FloatField(initial=0) rpayoff3 = models.FloatField(initial=0) rpayoff4 = models.FloatField(initial=0) timeout = models.IntegerField(initial=0) timeout_other = models.BooleanField(initial=False) # To indicate if participant receives average payoff started = models.BooleanField(initial=False) # Used for grouping: if assigned to group value changed to True groupnumber = models.IntegerField() num_completed = models.IntegerField(initial=0) # For attacker: number of completed decisions num_players = models.IntegerField() # Beliefs pnb = models.IntegerField( choices=[ [0, 'Up'], # 'Acquiesce'], [1, 'Down'], # 'Resist'], ], widget=widgets.RadioSelect, label="", initial = -99 ) ee = models.IntegerField(min=0, max=100, label="") # , initial=-99) ne = models.IntegerField(min=0, max=100, label="") # , initial=-99) ee_percdown1 = models.IntegerField() ee_payoff1 = models.FloatField() ne_percdown1 = models.IntegerField() ne_payoff1 = models.FloatField() # Appropriateness # beh_u = models.IntegerField( # choices=[ # [1, 'Very socially inappropriate'], # [2, 'Somewhat socially inappropriate'], # [3, 'Somewhat socially appropriate'], # [4, 'Very socially appropriate'] # ], # widget=widgets.RadioSelect, # label="", # initial=-99 # ) # beh_d = models.IntegerField( # choices=[ # [1, 'Very socially inappropriate'], # [2, 'Somewhat socially inappropriate'], # [3, 'Somewhat socially appropriate'], # [4, 'Very socially appropriate'] # ], # widget=widgets.RadioSelect, # label="", # initial=-99 # ) pun_u = models.IntegerField( choices=[ [1, 'Very socially inappropriate'], [2, 'Somewhat socially inappropriate'], [3, 'Somewhat socially appropriate'], [4, 'Very socially appropriate'] ], widget=widgets.RadioSelect, label="", initial=-99 ) pun_d = models.IntegerField( choices=[ [1, 'Very socially inappropriate'], [2, 'Somewhat socially inappropriate'], [3, 'Somewhat socially appropriate'], [4, 'Very socially appropriate'] ], widget=widgets.RadioSelect, label="", initial=-99 ) # mode_bu1 = models.IntegerField() # payoff_bu1 = models.FloatField() # mode_bd1 = models.IntegerField() # payoff_bd1 = models.FloatField() mode_pu1 = models.IntegerField() payoff_pu1 = models.FloatField() mode_pd1 = models.IntegerField() payoff_pd1 = models.FloatField() # store time # timestamp_start = models.FloatField() # # Retrieve time # minutes_left_wait = models.IntegerField() # Function that stores time spent on WaitPage def time_passed(self): return time() - self.participant.vars.get('instr_timestamp', 0) def minutes_left(self): time2 = ceil(20 - (self.time_passed() / 60)) self.minutes_left_wait = time2 return time2 def role(self): # if self.round_number == 1: # Create roles: Person with lowest score value is attacker if self.defender_id == 0: # self.id_in_group % Constants.players_per_group == 1: self.participant.vars['role'] = 'attacker' self.playing_status = 1 return 'attacker' # First round: defender roles are assigned sequentially based on score in group elif self.defender_id == 1: # self.id_in_group % Constants.players_per_group == 2: self.participant.vars['role'] = 'defender' self.playing_status = 2 # self.defender_id = 2 return 'defender1' elif self.defender_id == 2: # self.id_in_group % Constants.players_per_group == 3: self.participant.vars['role'] = 'defender' self.playing_status = 2 # self.defender_id = 3 return 'defender2' elif self.defender_id == 3: # self.id_in_group % Constants.players_per_group == 4: self.participant.vars['role'] = 'defender' self.playing_status = 2 # self.defender_id = 4 return 'defender3' else: self.participant.vars['role'] = 'defender' self.playing_status = 2 # self.defender_id = 1 return 'defender4' def timeout_seconds(self): if self.inactive: timeout = 0 else: # timeout = self.participant.vars['end_time'] - time(tz=pytz.utc) timeout = (self.participant.vars['end_time'] - datetime.datetime.now(tz=pytz.utc)).total_seconds() return timeout def timeout_norms(self): timeout = (self.participant.vars['end_time'] - datetime.datetime.now(tz=pytz.utc)).total_seconds() return timeout def register_timeouts(self): if self.timeout == 0: # Increment only if not incremented before (i.e. on page on which timeout happened) self.participant.vars['num_timeouts'] += 1 self.timeout = 1 if self.participant.vars['num_timeouts'] == Constants.allowed_timeouts: print('Player', self.id_in_subsession, 'with role', self.participant.vars['role'], 'let time run out', Constants.allowed_timeouts, ' times in a row so will be removed from game') # Show timeout page print('Player who dropped out has role', self.role()) # self.participant.vars['inactive'] = True def creating_score(self): if self.prac_missed > 0: # In round 1: Inactive if one or more practice decisions missed -> more missed, higher score self.score = self.prac_missed else: self.score = random()