import sys sys.path.append("improv_focus") from stories import * from feedback import * from yes_and import * from otree.api import * import random random.seed(10) class C(BaseConstants): NAME_IN_URL = 'improv_focus' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 10 TIMEOUT = 25 DROPOUT = 60 STORY1_ROUNDS = 2 STORY2_ROUNDS = 4 QUIZ_ROUNDS = 6 STORY3_ROUNDS = 6 STORY4_ROUNDS = 8 STORY3_ROUNDS_YA = 8 STORY4_ROUNDS_YA = 10 ''' STORY2_ROUNDS = 0 QUIZ_ROUNDS = 2 STORY3_ROUNDS = 2 STORY4_ROUNDS = 4 STORY3_ROUNDS_YA = 4 STORY4_ROUNDS_YA = 6 ''' STORY1_OPENING = get_story1_opening() STORY2_OPENING = get_story2_opening() STORY3_OPENING = get_story1_opening() STORY4_OPENING = get_story2_opening() TREATMENTS = [True, False] FORM_TEMPLATE = __name__ + '/form.html' class Subsession(BaseSubsession): prev_treatment = True num_groups_created = 0 class Group(BaseGroup): playerA_line = models.LongStringField(label='Continue the story!', initial='', blank=True) playerB_line = models.LongStringField(label='Continue the story!', initial='', blank=True) is_dropout = models.BooleanField(initial=False) class Player(BasePlayer): is_dropout = models.BooleanField(initial=False) yes_and = models.BooleanField(initial=False) [o1, o2, o3, o4] = feedback_survey_overall() [co1, co2, co3, co4, co5] = feedback_survey_overall(constraints=True) [a, b] = get_quiz_questions() class Consent(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Instr0(Page): timeout_seconds = C.DROPOUT form_model = 'player' @staticmethod def before_next_page(player: Player, timeout_happened): if timeout_happened: player.is_dropout = True @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class StartWaitPage(WaitPage): group_by_arrival_time = True @staticmethod def after_all_players_arrive(group: Group): treatment = random.choice([True, False]) treatment = False for p in group.get_players(): p.participant.yes_and = treatment @staticmethod def is_displayed(player: Player): if player.round_number == 1: return True class Story1(Page): timeout_seconds = C.TIMEOUT form_model = 'group' @staticmethod def get_form_fields(player): if player.id_in_group == 1: return ['playerA_line'] else: return ['playerB_line'] @staticmethod def vars_for_template(group): messages = group.in_rounds(1, C.STORY1_ROUNDS) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number <= C.STORY1_ROUNDS): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number <= C.STORY1_ROUNDS): return True @staticmethod def before_next_page(player: Player, timeout_happened): count = 0 messages = player.in_previous_rounds()[-3:] for message in messages: if message.group.playerA_line == "": count += 1 if count > 2: player.is_dropout = True player.group.is_dropout = True player.participant.finished = True class Story2(Page): timeout_seconds = C.TIMEOUT form_model = 'group' @staticmethod def get_form_fields(player): if player.id_in_group == 1: return ['playerA_line'] else: return ['playerB_line'] @staticmethod def vars_for_template(group): messages = group.in_rounds(C.STORY1_ROUNDS + 1, C.STORY2_ROUNDS) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number >= C.STORY1_ROUNDS + 1) \ & (player.round_number <= C.STORY2_ROUNDS): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number >= C.STORY1_ROUNDS + 1)\ & (player.round_number <= C.STORY2_ROUNDS): return True class Feedback(Page): timeout_seconds = 30 form_model = 'player' form_fields = ['o1', 'o2', 'o3', 'o4'] @staticmethod def is_displayed(player: Player): if player.round_number == C.STORY2_ROUNDS: return True class Instr1(Page): timeout_seconds = 30 form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY2_ROUNDS) class GBATWaitPage(WaitPage): group_by_arrival_time = True @staticmethod def is_displayed(player: Player): """only do GBAT in the first round. this way, players stay in the same group for all rounds.""" return (player.round_number == C.STORY2_ROUNDS + 1) @staticmethod def after_all_players_arrive(group: Group): treatment = random.choice([True, False]) treatment = False for p in group.get_players(): # since we want the treatment to persist for all rounds, we need to assign it # in a participant field (which persists across rounds) # rather than a group field, which is specific to the round. p.participant.yes_and = treatment class YesAnd(Page): form_model = 'player' @staticmethod def get_form_fields(player): return [['a', 'b'][player.round_number - C.STORY2_ROUNDS - 1]] @staticmethod def vars_for_template(player: Player): fields = [get_quiz_data()[player.round_number - C.STORY2_ROUNDS - 1]] return dict(fields=fields, show_solutions=False) @staticmethod def is_displayed(player: Player): print((player.round_number >= C.STORY2_ROUNDS + 1) , (player.round_number <= C.QUIZ_ROUNDS ) , (player.participant.yes_and)) return (player.round_number >= C.STORY2_ROUNDS + 1) & (player.round_number <= C.QUIZ_ROUNDS ) & (player.participant.yes_and) class Results(Page): form_model = 'player' @staticmethod def get_form_fields(player): return [['a', 'b'][player.round_number - C.STORY2_ROUNDS - 1]] @staticmethod def vars_for_template(player: Player): fields = [get_quiz_data()[player.round_number - C.STORY2_ROUNDS - 1]] # we add an extra entry 'is_correct' (True/False) to each field for d in fields: d['is_correct'] = getattr(player, d['name']) == d['solution'] return dict(fields=fields, show_solutions=True) @staticmethod def is_displayed(player: Player): return (player.round_number >= C.STORY2_ROUNDS + 1) & (player.round_number <= C.QUIZ_ROUNDS) \ & (player.participant.yes_and) class PostQuizWaitPage(WaitPage): group_by_arrival_time = True @staticmethod def is_displayed(player: Player): """only do GBAT in the first round. this way, players stay in the same group for all rounds.""" return (player.round_number == C.QUIZ_ROUNDS) & (player.participant.yes_and) class NoQuizWaitPage(WaitPage): group_by_arrival_time = True @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY2_ROUNDS + 1) & (player.participant.yes_and == False) class Instr2(Page): timeout_seconds = 30 form_model = 'player' @staticmethod def is_displayed(player: Player): if player.participant.yes_and: return player.round_number == C.QUIZ_ROUNDS + 1 else: return player.round_number == C.STORY2_ROUNDS + 1 class StoryConstr2(Page): timeout_seconds = 30 form_model = 'player' @staticmethod def is_displayed(player: Player): if player.participant.yes_and: return player.round_number == C.QUIZ_ROUNDS + 1 else: return player.round_number == C.STORY2_ROUNDS + 1 class Story3(Page): timeout_seconds = C.TIMEOUT form_model = 'group' @staticmethod def get_form_fields(player): if player.id_in_group == 1: return ['playerA_line'] else: return ['playerB_line'] @staticmethod def vars_for_template(group): if group.participant.yes_and == False: messages = group.in_rounds(C.STORY2_ROUNDS + 1, C.STORY3_ROUNDS) else: messages = group.in_rounds(C.QUIZ_ROUNDS + 1, C.STORY3_ROUNDS_YA) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number >= C.STORY2_ROUNDS + 1) \ & (player.round_number <= C.STORY3_ROUNDS) & (player.participant.yes_and == False): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number >= C.STORY2_ROUNDS + 1)\ & (player.round_number <= C.STORY3_ROUNDS) & (player.participant.yes_and == False): return True if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number >= C.QUIZ_ROUNDS + 1) \ & (player.round_number <= C.STORY3_ROUNDS_YA) & (player.participant.yes_and): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number >= C.QUIZ_ROUNDS + 1)\ & (player.round_number <= C.STORY3_ROUNDS_YA) & (player.participant.yes_and): return True class Story4(Page): timeout_seconds = C.TIMEOUT form_model = 'group' @staticmethod def get_form_fields(player): if player.id_in_group == 1: return ['playerA_line'] else: return ['playerB_line'] @staticmethod def vars_for_template(group): if group.participant.yes_and == False: messages = group.in_rounds(C.STORY3_ROUNDS + 1, C.STORY4_ROUNDS) else: messages = group.in_rounds(C.STORY3_ROUNDS_YA + 1, C.STORY4_ROUNDS_YA) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number >= C.STORY3_ROUNDS + 1) \ & (player.round_number <= C.STORY4_ROUNDS) & (player.participant.yes_and == False): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number >= C.STORY3_ROUNDS + 1)\ & (player.round_number <= C.STORY4_ROUNDS) & (player.participant.yes_and == False): return True if (player.id_in_group == 1) & (player.round_number % 2 == 1) & (player.round_number >= C.STORY3_ROUNDS_YA + 1) \ & (player.round_number <= C.STORY4_ROUNDS_YA) & (player.participant.yes_and): return True if (player.id_in_group == 2) & (player.round_number % 2 == 0) & (player.round_number >= C.STORY3_ROUNDS_YA + 1)\ & (player.round_number <= C.STORY4_ROUNDS_YA) & (player.participant.yes_and): return True class EndPage(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): if player.participant.yes_and: return player.round_number == C.STORY4_ROUNDS else: return player.round_number == C.STORY4_ROUNDS class PlayerWaitPage(WaitPage): def is_displayed(player: Player): return (player.round_number <= C.STORY2_ROUNDS) class PlayerWaitPage2(WaitPage): @staticmethod def is_displayed(player: Player): if player.participant.yes_and: return player.round_number >= C.QUIZ_ROUNDS + 1 else: return player.round_number >= C.STORY2_ROUNDS + 1 pass class ByeDropout1(Page): @staticmethod def is_displayed(player: Player): return player.is_dropout @staticmethod def error_message(player: Player, values): return "Cannot proceed past this page" class ByeDropout2(Page): @staticmethod def is_displayed(player: Player): return player.group.is_dropout @staticmethod def error_message(player: Player, values): return "Cannot proceed past this page" page_sequence = [ #Consent, \ #Instr0, \ StartWaitPage, \ Story1, \ PlayerWaitPage, \ Story2, PlayerWaitPage, \ #Feedback, \ #ByeDropout1, \ #ByeDropout2, \ #Instr1, \ GBATWaitPage, \ YesAnd, \ Results, PostQuizWaitPage, \ NoQuizWaitPage, \ #Instr2, \ #StoryConstr2, \ Story3, \ PlayerWaitPage2, \ Story4, PlayerWaitPage2, \ #ByeDropout1, \ #ByeDropout2, \ #FeedbackEnd\ #EndPage, \ ]