from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants from time import time from random import choice import pytz class Initialisation(Page): timeout_seconds = 1 def before_next_page(self): print('ROUND = ', self.round_number + 1) self.player.inactive = self.player.participant.vars['inactive'] self.player.creating_score() self.participant.vars['score'] = self.player.score print('SCORE = ', self.player.participant.vars['score']) class ShuffleGroups(WaitPage): template_name = 't4_seq_hawk_dove/Wait.html' wait_for_all_groups = True # def is_displayed(self): # return self.round_number <= self.subsession.last_round def vars_for_template(self): endexp = self.player.participant.vars['experimentended'] role = self.participant.vars['role'] return dict( endexp=endexp, role=role ) def after_all_players_arrive(self): self.subsession.num_active = 0 for p in self.subsession.get_players(): if p.score < 1: self.subsession.num_active += 1 print('Number of active players = ', self.subsession.num_active) self.subsession.shuffle_groups() class AssignRoles(WaitPage): template_name = 't4_seq_hawk_dove/Wait.html' def vars_for_template(self): endexp = self.player.participant.vars['experimentended'] role = self.participant.vars['role'] return dict( endexp=endexp, role=role ) def after_all_players_arrive(self): self.group.assign_roles() self.group.defender_choices() class StartExperiment(Page): def get_timeout_seconds(self): # if self.round_number == 1 and not self.player.inactive: # return 60 # elif self.round_number == 1 and self.player.inactive: # return 0 # elif self.round_number > 1: return 0 def is_displayed(self): return self.player.participant.vars['num_timeouts'] < Constants.allowed_timeouts # and self.player.participant.vars['role'] != 'inactive' and self.round_number <= self.subsession.last_round def vars_for_template(self): role = self.participant.vars['role'] round = self.round_number return dict( role=role, round=round ) def before_next_page(self): # Start timer for answering this round's decision for p in self.group.get_players(): # Participant has 2 minutes (rounds 1-9) or 1 minute (rounds 10-50) to complete all decisions if self.round_number < Constants.timer_switch: if self.session.config['group']: p.participant.vars['end_time'] = time() + 90 # 90 secs in first rounds for group treatments else: p.participant.vars['end_time'] = time() + 120 # 120 secs for individual tms (4 attacker choices) else: if self.session.config['group']: p.participant.vars['end_time'] = time() + 40 else: p.participant.vars['end_time'] = time() + 60 class Decision1Attacker(Page): template_name = 't4_seq_hawk_dove/DecisionsAttacker.html' form_model = 'player' form_fields = ['choice_a1'] timer_text = 'Time left to make this round\'s decisions:' def is_displayed(self): return self.player.participant.vars['role'] == 'attacker' # and self.round_number <= self.subsession.last_round def vars_for_template(self): group = self.session.config['group'] if not group: up = self.group.d1_up7 down = self.group.d1_down7 total = self.group.d1_total7 elif group: up = self.group.dsel_up7 down = self.group.dsel_down7 total = self.group.dsel_total7 num_defenders = self.group.defenders_active defender = self.group.defender1_id decision = 1 cost_fight = int(self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2) highpayoff = self.subsession.value + self.subsession.endowment # Decision tree if self.session.config['vc_ratio'] == 'high': if self.session.config['group']: image_path = 'high_g.png' else: image_path = 'high.png' elif self.session.config['vc_ratio'] == 'low': if self.session.config['group']: image_path = 'low_g.png' else: image_path = 'low.png' return dict( # Treatment type group=group, # Earlier defender choices up=up, down=down, total=total, # Number of defenders num_defenders=num_defenders, defender=defender, decision=decision, cost_fight=cost_fight, highpayoff=highpayoff, # Decision tree image_path=image_path, ) def get_timeout_seconds(self): return self.player.timeout_seconds() def before_next_page(self): # Register timeouts if self.timeout_happened: self.player.register_timeouts() self.player.choice_a1 = 2 # 2 means no decision was made else: self.player.num_completed += 1 class Decision2Attacker(Page): template_name = 't4_seq_hawk_dove/DecisionsAttacker.html' form_model = 'player' form_fields = ['choice_a2'] timer_text = 'Time left to make this round\'s decisions:' def is_displayed(self): return self.player.participant.vars['role'] == 'attacker' and not self.session.config['group'] and \ self.group.defenders_active >= 2 # and self.round_number <= self.subsession.last_round def vars_for_template(self): group = self.session.config['group'] up = self.group.d2_up7 down = self.group.d2_down7 total = self.group.d2_total7 num_defenders = self.group.defenders_active # self.group.groupsize - 1 defender = self.group.defender2_id decision = 2 cost_fight = int(self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2) highpayoff = self.subsession.value + self.subsession.endowment # Decision tree if self.session.config['vc_ratio'] == 'high': if self.session.config['group']: image_path = 'high_g.png' else: image_path = 'high.png' elif self.session.config['vc_ratio'] == 'low': if self.session.config['group']: image_path = 'low_g.png' else: image_path = 'low.png' return dict( # Treatment type group=group, # Earlier defender choices up=up, down=down, total=total, # Number of defenders num_defenders=num_defenders, defender=defender, decision=decision, cost_fight=cost_fight, highpayoff=highpayoff, # Decision tree image_path=image_path, ) def get_timeout_seconds(self): return self.player.timeout_seconds() def before_next_page(self): # Register timeouts if self.timeout_happened: self.player.register_timeouts() self.player.choice_a2 = 2 # 2 means no decision was made else: self.player.num_completed += 1 class Decision3Attacker(Page): template_name = 't4_seq_hawk_dove/DecisionsAttacker.html' form_model = 'player' form_fields = ['choice_a3'] timer_text = 'Time left to make this round\'s decisions:' def is_displayed(self): return self.player.participant.vars['role'] == 'attacker' and not self.session.config['group'] and \ self.group.defenders_active >= 3 # and self.round_number <= self.subsession.last_round def vars_for_template(self): group = self.session.config['group'] up = self.group.d3_up7 down = self.group.d3_down7 total = self.group.d3_total7 num_defenders = self.group.defenders_active # self.group.groupsize - 1 defender = self.group.defender2_id decision = 3 cost_fight = int(self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2) highpayoff = self.subsession.value + self.subsession.endowment # Decision tree if self.session.config['vc_ratio'] == 'high': if self.session.config['group']: image_path = 'high_g.png' else: image_path = 'high.png' elif self.session.config['vc_ratio'] == 'low': if self.session.config['group']: image_path = 'low_g.png' else: image_path = 'low.png' return dict( # Treatment type group=group, # Earlier defender choices up=up, down=down, total=total, # Number of defenders num_defenders=num_defenders, defender=defender, decision=decision, cost_fight=cost_fight, highpayoff=highpayoff, # Decision tree image_path=image_path, ) def get_timeout_seconds(self): return self.player.timeout_seconds() def before_next_page(self): # Register timeouts if self.timeout_happened: self.player.register_timeouts() self.player.choice_a3 = 2 # 2 means no decision was made else: self.player.num_completed += 1 class Decision4Attacker(Page): template_name = 't4_seq_hawk_dove/DecisionsAttacker.html' form_model = 'player' form_fields = ['choice_a4'] timer_text = 'Time left to make this round\'s decisions:' def is_displayed(self): return self.player.participant.vars['role'] == 'attacker' and not self.session.config['group'] and \ self.group.defenders_active == 4 # and self.round_number <= self.subsession.last_round def vars_for_template(self): group = self.session.config['group'] up = self.group.d4_up7 down = self.group.d4_down7 total = self.group.d4_total7 num_defenders = self.group.defenders_active # self.group.groupsize - 1 defender = self.group.defender2_id decision = 4 cost_fight = int(self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2) highpayoff = self.subsession.value + self.subsession.endowment # Decision tree if self.session.config['vc_ratio'] == 'high': if self.session.config['group']: image_path = 'high_g.png' else: image_path = 'high.png' elif self.session.config['vc_ratio'] == 'low': if self.session.config['group']: image_path = 'low_g.png' else: image_path = 'low.png' return dict( # Treatment type group=group, # Earlier defender choices up=up, down=down, total=total, # Number of defenders num_defenders=num_defenders, defender=defender, decision=decision, cost_fight=cost_fight, highpayoff=highpayoff, # Decision tree image_path=image_path, ) def get_timeout_seconds(self): return self.player.timeout_seconds() def before_next_page(self): # Register timeouts if self.timeout_happened: self.player.register_timeouts() self.player.choice_a4 = 2 # 2 means no decision was made else: self.player.num_completed += 1 class DecisionDefender(Page): form_model = 'player' form_fields = ['choice_d'] timer_text = 'Time left to make this round\'s decision:' def is_displayed(self): return self.player.participant.vars['role'] == 'defender' # and self.round_number <= self.subsession.last_round def vars_for_template(self): group = self.session.config['group'] cost_fight = int(self.subsession.endowment + (self.subsession.value - self.subsession.cost) / 2) highpayoff = self.subsession.value + self.subsession.endowment if self.session.config['vc_ratio'] == 'high': if self.session.config['group']: image_path = 'high_g.png' else: image_path = 'high.png' elif self.session.config['vc_ratio'] == 'low': if self.session.config['group']: image_path = 'low_g.png' else: image_path = 'low.png' other_defenders = Constants.players_per_group - 2 if group == True: up = self.group.dsel_up7 down = self.group.dsel_down7 total = self.group.dsel_total7 else: if self.player.role() == 'defender1': up = self.group.d1_up7 down = self.group.d1_down7 total = self.group.d1_total7 if self.player.role() == 'defender2': up = self.group.d2_up7 down = self.group.d2_down7 total = self.group.d2_total7 if self.player.role() == 'defender3': up = self.group.d3_up7 down = self.group.d3_down7 total = self.group.d3_total7 if self.player.role() == 'defender4': up = self.group.d4_up7 down = self.group.d4_down7 total = self.group.d4_total7 return dict( group=group, cost_fight=cost_fight, highpayoff=highpayoff, image_path=image_path, other_defenders=other_defenders, up=up, down=down, total=total, ) def get_timeout_seconds(self): return self.player.timeout_seconds() def before_next_page(self): # Register timeouts if self.timeout_happened: self.player.register_timeouts() self.player.choice_d = 2 # 2 means no decision was made # if self.round_number == 1 or self.round_number == self.subsession.last_round: # # Start timer for answering norm questions # self.participant.vars['end_time'] = time() + 12 ####### Only for testing: CHANGE BACK TO 120!!!! # if self.round_number == 1: # self.participant.vars['choice_d1'] = self.player.choice_d if self.round_number == Constants.num_rounds: #self.subsession.last_round: self.participant.vars['choice_dl'] = self.player.choice_d class ResultsWaitPage(WaitPage): template_name = 't4_seq_hawk_dove/Wait.html' def is_displayed(self): return self.round_number <= self.subsession.last_round def vars_for_template(self): endexp = self.player.participant.vars['experimentended'] role = self.participant.vars['role'] return dict( endexp=endexp, role=role ) def after_all_players_arrive(self): # if self.group.groupsize > 1: self.group.set_payoffs() self.group.defender_choices() class Results(Page): form_model = 'player' form_fields = ['rewpun'] def is_displayed(self): return not self.player.inactive # self.round_number <= self.subsession.last_round and timer_text = 'Time left to view the results:' def vars_for_template(self): # Dropout info inactive = self.player.participant.vars['inactive'] num_timeouts = self.player.participant.vars['num_timeouts'] last_warning = num_timeouts == Constants.allowed_timeouts - 1 if num_timeouts > 4: num_timeouts = 4 endexp = self.player.participant.vars['experimentended'] # Treatment info role = self.participant.vars['role'] num_defenders = self.group.defenders_active # Constants.players_per_group - 1 # self.group.groupsize - 1 group = self.session.config['group'] reward_tm = self.session.config['reward'] punish_tm = self.session.config['punishment'] if not group: def_dropout = num_defenders - self.group.num_decisions else: def_dropout = 0 # Results sel_defender = self.group.attack_paid decision1 = False decision2 = False decision3 = False decision4 = False a1_choice = 2 d1_choice = 2 rpayoff1 = 0 a2_choice = 2 d2_choice = 2 rpayoff2 = 0 a3_choice = 2 d3_choice = 2 rpayoff3 = 0 a4_choice = 2 d4_choice = 2 rpayoff4 = 0 num_decisions = 0 # get_roles = [p.role() for p in self.group.get_players()] # if 'attacker' in get_roles: # attacker = self.group.get_player_by_role('attacker') # else: # attacker = None if not group: # if not attacker is None: print('get attacker values)') if self.player.role() == 'attacker': if not self.group.get_player_by_role('defender1').inactive: # if self.group.defender1_id is not None: decision1 = True num_decisions += 1 a1_choice = self.player.choice_a1 print('a1_choice = ', self.player.choice_a1, a1_choice) d1_choice = self.group.get_player_by_role('defender1').choice_d rpayoff1 = self.player.rpayoff1 if not self.group.get_player_by_role('defender2').inactive: # if self.group.defender2_id is not None: decision2 = True num_decisions += 1 a2_choice = self.player.choice_a2 d2_choice = self.group.get_player_by_role('defender2').choice_d rpayoff2 = self.player.rpayoff2 if not self.group.get_player_by_role('defender3').inactive: # if self.group.defender3_id is not None: decision3 = True num_decisions += 1 a3_choice = self.player.choice_a3 d3_choice = self.group.get_player_by_role('defender3').choice_d rpayoff3 = self.player.rpayoff3 if not self.group.get_player_by_role('defender4').inactive: # if self.group.defender4_id is not None: decision4 = True num_decisions += 1 a4_choice = self.player.choice_a4 d4_choice = self.group.get_player_by_role('defender4').choice_d rpayoff4 = self.player.rpayoff4 if self.player.role() == 'defender1': decision1 = True num_decisions += 1 # if not attacker is None: # a1_choice = self.group.get_player_by_role('attacker').choice_a1 # else: # a1_choice = 2 a1_choice = self.player.choice_a1 print('a1_choice = ', self.player.choice_a1, a1_choice) d1_choice = self.player.choice_d rpayoff1 = self.player.round_payoff elif self.player.role() == 'defender2': decision1 = True num_decisions += 1 # if not attacker is None: # a1_choice = self.group.get_player_by_role('attacker').choice_a1 # else: # a1_choice = 2 a1_choice = self.player.choice_a1 d1_choice = self.player.choice_d rpayoff1 = self.player.round_payoff elif self.player.role() == 'defender3': decision1 = True num_decisions += 1 # if not attacker is None: # a1_choice = self.group.get_player_by_role('attacker').choice_a1 # else: # a1_choice = 2 a1_choice = self.player.choice_a1 d1_choice = self.player.choice_d rpayoff1 = self.player.round_payoff elif self.player.role() == 'defender4': decision1 = True num_decisions += 1 # if not attacker is None: # a1_choice = self.group.get_player_by_role('attacker').choice_a1 # else: # a1_choice = 2 a1_choice = self.player.choice_a1 d1_choice = self.player.choice_d rpayoff1 = self.player.round_payoff else: # If group treatments decision1 = True num_decisions += 1 # if not attacker is None: # a1_choice = self.group.get_player_by_role('attacker').choice_a1 # else: # a1_choice = 2 a1_choice = self.group.get_player_by_role('attacker').choice_a1 if a1_choice == 1: d1_choice = self.group.dsel_choice elif a1_choice == 0: d1_choice = -1 elif a1_choice == 2: d1_choice == 2 # if a1_choice == 1 and d1_choice == 2: # rpayoff1 = 0 # else: rpayoff1 = self.player.round_payoff print('Check values of payoffs 1 - 4', rpayoff1, rpayoff2, rpayoff3, rpayoff4) if rpayoff1 is None: rpayoff1 = 0 if rpayoff2 is None: rpayoff2 = 0 if rpayoff3 is None: rpayoff3 = 0 if rpayoff4 is None: rpayoff4 = 0 print('Check values of payoffs 1 - 4', rpayoff1, rpayoff2, rpayoff3, rpayoff4) print('Check values of d_choice 1 - 4', d1_choice, d2_choice, d3_choice, d4_choice) if d1_choice is None: d1_choice = 2 if d2_choice is None: d2_choice = 2 if d3_choice is None: d3_choice = 2 if d4_choice is None: d4_choice = 2 defenders = [] if group and role == 'defender' and reward_tm: if not self.group.get_player_by_role('defender1').inactive: # self.group.defender1_id is not None: if self.round_number > 1: defenders.append( {'id': 1, 'num_likes': self.group.get_player_by_role('defender1').in_round(self.round_number - 1).num_likes}) else: defenders.append( {'id': 1, 'num_likes': self.group.get_player_by_role('defender1').participant.vars['num_likes']}) if not self.group.get_player_by_role('defender2').inactive: # self.group.defender2_id is not None: if self.round_number > 1: defenders.append( {'id': 2, 'num_likes': self.group.get_player_by_role('defender2').in_round(self.round_number - 1).num_likes}) else: defenders.append( {'id': 2, 'num_likes': self.group.get_player_by_role('defender2').participant.vars['num_likes']}) if not self.group.get_player_by_role('defender3').inactive: # self.group.defender3_id is not None: if self.round_number > 1: defenders.append( {'id': 3, 'num_likes': self.group.get_player_by_role('defender3').in_round(self.round_number - 1).num_likes}) else: defenders.append( {'id': 3, 'num_likes': self.group.get_player_by_role('defender3').participant.vars['num_likes']}) if not self.group.get_player_by_role('defender4').inactive: # self.group.defender4_id is not None: if self.round_number > 1: defenders.append( {'id': 4, 'num_likes': self.group.get_player_by_role('defender4').in_round(self.round_number - 1).num_likes}) else: defenders.append( {'id': 4, 'num_likes': self.group.get_player_by_role('defender4').participant.vars['num_likes']}) defenders = sorted(defenders, key=lambda d: d['num_likes'], reverse=True) print('Ordered defenders list = ', defenders) return dict( inactive=inactive, endexp=endexp, num_timeouts=num_timeouts, last_warning=last_warning, role=role, num_defenders=num_defenders, group=group, reward_tm=reward_tm, punish_tm=punish_tm, def_dropout=def_dropout, sel_defender=sel_defender, decision1=decision1, decision2=decision2, decision3=decision3, decision4=decision4, num_decisions=num_decisions, a1_choice=a1_choice, d1_choice=d1_choice, a2_choice=a2_choice, d2_choice=d2_choice, a3_choice=a3_choice, d3_choice=d3_choice, a4_choice=a4_choice, d4_choice=d4_choice, rpayoff1=rpayoff1, rpayoff2=rpayoff2, rpayoff3=rpayoff3, rpayoff4=rpayoff4, defenders=defenders, ) def get_timeout_seconds(self): if self.participant.vars['inactive']: return 0 else: return 30 def before_next_page(self): # End experiment if: if self.player.participant.vars['num_timeouts'] >= Constants.allowed_timeouts and \ self.round_number < Constants.num_rounds: # Player missed too many decisions self.participant.vars['inactive'] = True self.player.participant.vars['experimentended'] = 'no' if self.session.config['group'] and self.group.defenders_active == 1 and not \ self.player.participant.vars['inactive'] and self.round_number < Constants.num_rounds: # Player is only defender left in group treatments self.player.experimentended = True self.player.participant.vars['experimentended'] = 'plb' self.player.participant.vars['inactive'] = True if self.group.defenders_active == 0 and not self.player.participant.vars['inactive'] and \ self.round_number < Constants.num_rounds: # No defenders to match attacker with self.player.experimentended = True self.player.participant.vars['experimentended'] = 'plb' self.player.participant.vars['inactive'] = True if self.group.attacker_active == 0 and not self.player.participant.vars['inactive'] and \ self.round_number < Constants.num_rounds: # Defenders were not matched with active attacker self.player.experimentended = True self.player.participant.vars['inactive'] = True self.player.participant.vars['experimentended'] = 'pla' class RewardPunishWait(WaitPage): template_name = 't4_seq_hawk_dove/Wait.html' def is_displayed(self): # Extra results page only for selected defender return (self.session.config['reward'] or self.session.config['punishment']) and \ self.group.get_player_by_role('attacker').choice_a1 > 0 and \ self.player.participant.vars['num_timeouts'] < Constants.allowed_timeouts # self.round_number <= self.subsession.last_round and \ def vars_for_template(self): endexp = self.player.participant.vars['experimentended'] # if self.round_number == 1: # role = "" # else: role = self.participant.vars['role'] return dict( endexp=endexp, role=role ) def after_all_players_arrive(self): if self.session.config['reward']: self.group.rewards() if self.session.config['punishment']: self.group.punishments() class RewardPunishment(Page): def is_displayed(self): # Extra results page only for selected defender return (self.session.config['reward'] or self.session.config['punishment']) and \ self.player.participant.vars['role'] == 'defender' and \ self.group.get_player_by_role('attacker').choice_a1 > 0 and \ self.group.dsel_choice < 2 and self.player.participant.vars['num_timeouts'] < Constants.allowed_timeouts #and \ # self.round_number <= self.subsession.last_round timer_text = 'Time left to view the results:' def vars_for_template(self): role = self.participant.vars['role'] reward_tm = self.session.config['reward'] punish_tm = self.session.config['punishment'] points_lost = self.group.num_punishers * Constants.punish_r sel_defender = self.group.attack_paid if self.player.rewpun == 3: pun_payoff = 0 else: pun_payoff = 1 return dict( role=role, reward_tm=reward_tm, punish_tm=punish_tm, points_lost=points_lost, sel_defender = sel_defender, pun_payoff=pun_payoff, ) def get_timeout_seconds(self): if self.participant.vars['inactive']: return 0 else: return 20 class PayoffWait(WaitPage): template_name = 't4_seq_hawk_dove/Wait.html' def is_displayed(self): return self.round_number == Constants.num_rounds def vars_for_template(self): endexp = self.player.participant.vars['experimentended'] role = self.participant.vars['role'] return dict( endexp=endexp, role=role, ) def after_all_players_arrive(self): self.group.final_payoff() page_sequence = [Initialisation,ShuffleGroups,AssignRoles, StartExperiment, Decision1Attacker, Decision2Attacker, Decision3Attacker, Decision4Attacker, DecisionDefender, ResultsWaitPage, Results, RewardPunishWait, RewardPunishment, PayoffWait]