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 class FirstWaitPage(WaitPage): group_by_arrival_time = True template_name = 'cooperation/FirstWaitingPage.html' def is_displayed(self): # After max waiting time has expired mark player as unmatched self.participant.vars.setdefault('start_waiting_for_partners', time()) if self.request: if self.request.method == 'POST': self.participant.vars['unmatched'] = True return self.round_number == 1 def get_players_for_group(self, waiting_players): for p in waiting_players: p.refresh_from_db() # Move forward unmatched players unmatched = [p for p in waiting_players if p.participant.vars.get('unmatched')] if len(unmatched) == 1: return unmatched[:1] elif unmatched: return unmatched[:2] # Group players still waiting for partner(s) still_waiting = [p for p in waiting_players if not p.participant.vars.get('unmatched')] if len(still_waiting) >= 2: return self.subsession.set_partner_based_on_identity(still_waiting, 'cooperate', 2) def after_all_players_arrive(self): players = self.group.get_players() # Handle potential race condition causing 'unmatched' players to actually be grouped if len(players) > 1: for p in players: if p.participant.vars.get('unmatched'): p.participant.vars.pop('unmatched', None) class TaskCprInstructions(Page): template_name = 'cooperation/Instructions.html' timeout_seconds = 60 * 2 def is_displayed(self): # Erase start_waiting_for_partners self.participant.vars.pop('start_waiting_for_partners', None) return self.round_number == 1 def vars_for_template(self): partner_treatment = self.player.cooperate_partner if partner_treatment == 'name': partner_name = self.player.get_others_in_group()[0].participant.vars['data']['first_name'] self.player.cooperate_partner_name = partner_name partner = f"The second participant is called {partner_name}." elif partner_treatment == 'same_class': partner = "The second participant is also in your house." elif partner_treatment == 'other_house': partner = "The second participant is from another house." elif partner_treatment == 'other_region': partner = "The second participant comes from another house/section in the Civil Service Academy." else: partner = '' if self.participant.vars.get('is_teacher'): partner = '' return {'partner': partner} class TaskCprDecision(Page): template_name = 'cooperation/Decision.html' timeout_seconds = 60 form_model = 'player' form_fields = ['cooperate_decision'] def before_next_page(self): if self.timeout_happened: self.player.cooperate_decision = choice([0, 1]) self.player.timeout = True class TaskCprDecisionAfter(Page): template_name = 'cooperation/Empathy.html' timeout_seconds = 60 form_model = 'player' form_fields = ['empathy'] class ResultsWaitPage(WaitPage): def after_all_players_arrive(self): for p in self.group.get_players(): if p.id_in_group == 4: self.group.random_matching = p.participant.vars['cooperation_treatment'] p.set_payoff() class TaskCprResults(Page): template_name = 'cooperation/Results.html' timeout_seconds = 60 def vars_for_template(self): if self.participant.vars.get('unmatched'): other_cooperate = self.participant.vars['other_cooperate'] other_payoff = Constants.endowment - self.participant.vars['other_cooperate'] + \ self.player.cooperate_decision * Constants.multiplier else: other_cooperate = self.player.get_others_in_group()[0].cooperate_decision other_payoff = self.player.get_others_in_group()[0].payoff return { 'other_cooperate': other_cooperate, 'other_payoff': other_payoff, 'next_round': self.round_number + 1 } def before_next_page(self): if self.round_number == Constants.num_rounds: self.participant.vars['unmatched'] = False page_sequence = [ FirstWaitPage, TaskCprInstructions, TaskCprDecision, TaskCprDecisionAfter, ResultsWaitPage, TaskCprResults ]