from ._builtin import Page, WaitPage from .models import Constants from time import time from random import randint, choice class FirstWaitPage(WaitPage): group_by_arrival_time = True template_name = 'guessing_game/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 unmatched: treatment = choice(Constants.treatments) for p in unmatched: p.participant.vars['guessing_treatment'] = treatment p.treatment = p.participant.vars['guessing_treatment'] return unmatched[:1] # 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) >= 4: treatment = choice(Constants.treatments) for p in still_waiting[0:4]: p.participant.vars['guessing_treatment'] = treatment p.treatment = p.participant.vars['guessing_treatment'] return still_waiting[:4] 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 TaskGssInstructions(Page): template_name = 'guessing_game/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): t = 'a half' if self.participant.vars['guessing_treatment'] == '1/3': t = 'a third' elif self.participant.vars['guessing_treatment'] == '2/3': t = 'two thirds' return { 'others_in_group': Constants.group_size - 1, 'treatment': t } class TaskGssDecision(Page): template_name = 'guessing_game/Guess.html' timeout_seconds = 60 form_model = 'player' form_fields = ['guess'] def vars_for_template(self): t = 'a half' if self.participant.vars['guessing_treatment'] == '1/3': t = 'a third' elif self.participant.vars['guessing_treatment'] == '2/3': t = 'two thirds' return {'treatment': t} def before_next_page(self): if self.timeout_happened: self.player.guess = randint(0, 100) self.player.timeout = True class ResultsWaitPage(WaitPage): def after_all_players_arrive(self): self.group.set_payoffs() class TaskGssResults(Page): template_name = 'guessing_game/Results.html' timeout_seconds = Constants.seconds_for_summary def vars_for_template(self): sorted_guesses = ', '.join(map(str, sorted(p.guess for p in self.group.get_players()))) t = 'a half' if self.participant.vars['guessing_treatment'] == '1/3': t = 'a third' elif self.participant.vars['guessing_treatment'] == '2/3': t = 'two thirds' if self.group.num_winners: other_winners = self.group.num_winners - 1 else: other_winners = None return dict(sorted_guesses=sorted_guesses, treatment=t, other_winners=other_winners) def before_next_page(self): if self.round_number == Constants.num_rounds: self.participant.vars['unmatched'] = False page_sequence = [ FirstWaitPage, TaskGssInstructions, TaskGssDecision, ResultsWaitPage, TaskGssResults ]