import sys sys.path.append("improv_ctrl") from stories import * from feedback import * from otree.api import * import random random.seed(10) import time def waiting_too_long(player): participant = player.participant # assumes you set wait_page_arrival in PARTICIPANT_FIELDS. return (time.time() - participant.wait_page_arrival) > 5*60 class C(BaseConstants): NAME_IN_URL = 'improv_ctrl' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 60 TIMEOUT = 30 STORY_INTRO = 30 FEEDBACK = 30 STORY1_ROUNDS = 12 STORY2_ROUNDS = 30 STORY3_ROUNDS = 42 STORY4_ROUNDS = 60 STORY1_OPENING = get_story1_opening() STORY2_OPENING = get_story2_opening() STORY3_OPENING = get_story3_opening() STORY4_OPENING = get_story4_opening() STORY2_WORDS = get_story2_words() STORY4_WORDS = get_story4_words() FORM_TEMPLATE = __name__ + '/form.html' class Subsession(BaseSubsession): pass 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) [o1, o2, o3, o4] = feedback_survey_overall() [co1, co2, co3, co4, co5] = feedback_survey_overall(constraints=True) class Consent(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Instr0(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == 1) class Waiting(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == 1) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.wait_page_arrival = time.time() class StartWaitPage(WaitPage): group_by_arrival_time = True @staticmethod def is_displayed(player: Player): if (player.round_number == 1) & (not waiting_too_long(player)): return True class StoryIntro1(Page): timeout_seconds = C.STORY_INTRO form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == 1) 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 before_next_page(player: Player, timeout_happened): count = 0 messages = player.in_rounds(1, player.round_number - 1)[-6:] for message in messages: if (message.id_in_group == 1) & (message.group.round_number % 2 == 1 ): if message.group.playerA_line == "": count += 1 elif (message.id_in_group == 2) & (message.group.round_number % 2 == 0 ): if message.group.playerB_line == "": count += 1 print(player.round_number, count) if count > 2: player.is_dropout = True player.group.is_dropout = True player.participant.finished = True @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 class Feedback1(Page): timeout_seconds = C.FEEDBACK form_model = 'player' form_fields = ['o1', 'o2', 'o3', 'o4'] @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.round_number == C.STORY1_ROUNDS: return True class Constraints(Page): timeout_seconds = 25 form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY1_ROUNDS) class StoryIntro2(Page): timeout_seconds = C.STORY_INTRO form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY1_ROUNDS) 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 before_next_page(player: Player, timeout_happened): count = 0 messages = player.in_rounds(C.STORY1_ROUNDS + 1, player.round_number - 1)[-6:] for message in messages: if (message.id_in_group == 1) & (message.group.round_number % 2 == 1 ): if message.group.playerA_line == "": count += 1 elif (message.id_in_group == 2) & (message.group.round_number % 2 == 0 ): if message.group.playerB_line == "": count += 1 print(player.round_number, count) if count > 2: player.is_dropout = True player.group.is_dropout = True player.participant.finished = True @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 Feedback2(Page): timeout_seconds = C.FEEDBACK form_model = 'player' form_fields = ['o1', 'o2', 'o3', 'o4'] @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.round_number == C.STORY2_ROUNDS: return True class StoryIntro3(Page): timeout_seconds = C.STORY_INTRO form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY2_ROUNDS) 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): messages = group.in_rounds(C.STORY2_ROUNDS + 1, C.STORY3_ROUNDS) return dict( messages = messages ) @staticmethod def before_next_page(player: Player, timeout_happened): count = 0 messages = player.in_rounds(C.STORY2_ROUNDS + 1, player.round_number - 1)[-6:] for message in messages: if (message.id_in_group == 1) & (message.group.round_number % 2 == 1 ): if message.group.playerA_line == "": count += 1 elif (message.id_in_group == 2) & (message.group.round_number % 2 == 0 ): if message.group.playerB_line == "": count += 1 print(player.round_number, count) if count > 2: player.is_dropout = True player.group.is_dropout = True player.participant.finished = True @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) : 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) : return True class Feedback3(Page): timeout_seconds = C.FEEDBACK form_model = 'player' form_fields = ['o1', 'o2', 'o3', 'o4'] @staticmethod def vars_for_template(group): messages = group.in_rounds(C.STORY2_ROUNDS + 1, C.STORY3_ROUNDS) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if player.round_number == C.STORY3_ROUNDS: return True class StoryIntro4(Page): timeout_seconds = C.STORY_INTRO form_model = 'player' @staticmethod def is_displayed(player: Player): return (player.round_number == C.STORY3_ROUNDS) 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 before_next_page(player: Player, timeout_happened): count = 0 messages = player.in_rounds(C.STORY3_ROUNDS + 1, player.round_number - 1)[-6:] for message in messages: if (message.id_in_group == 1) & (message.group.round_number % 2 == 1 ): if message.group.playerA_line == "": count += 1 elif (message.id_in_group == 2) & (message.group.round_number % 2 == 0 ): if message.group.playerB_line == "": count += 1 print(player.round_number, count) if count > 2: player.is_dropout = True player.group.is_dropout = True player.participant.finished = True @staticmethod def vars_for_template(group): messages = group.in_rounds(C.STORY3_ROUNDS + 1, C.STORY4_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.STORY3_ROUNDS + 1) \ & (player.round_number <= C.STORY4_ROUNDS) : 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) : return True class Feedback4(Page): timeout_seconds = C.FEEDBACK form_model = 'player' form_fields = ['o1', 'o2', 'o3', 'o4'] @staticmethod def vars_for_template(group): messages = group.in_rounds(C.STORY3_ROUNDS + 1, C.STORY4_ROUNDS) return dict( messages = messages ) @staticmethod def is_displayed(player: Player): if player.round_number == C.STORY4_ROUNDS: return True class EndPage(Page): form_model = 'player' @staticmethod def is_displayed(player: Player): return player.round_number == C.STORY4_ROUNDS class PlayerWaitPage1(WaitPage): def is_displayed(player: Player): return (player.round_number <= C.STORY2_ROUNDS) class PlayerWaitPage2(WaitPage): @staticmethod def is_displayed(player: Player): return (player.round_number >= C.STORY1_ROUNDS + 1) & (player.round_number <= C.STORY2_ROUNDS) class PlayerWaitPage3(WaitPage): def is_displayed(player: Player): return (player.round_number >= C.STORY2_ROUNDS + 1) & (player.round_number <= C.STORY3_ROUNDS) class PlayerWaitPage4(WaitPage): def is_displayed(player: Player): return (player.round_number >= C.STORY3_ROUNDS + 1) & (player.round_number <= C.STORY4_ROUNDS) class ByeDropout1(Page): @staticmethod def is_displayed(player: Player): if player.is_dropout: player.participant.finished = True return True @staticmethod def error_message(player: Player, values): return "Cannot proceed past this page" class ByeDropout2(Page): @staticmethod def is_displayed(player: Player): if player.group.is_dropout: player.participant.finished = True return True @staticmethod def error_message(player: Player, values): return "Cannot proceed past this page" page_sequence = [ Consent, \ Instr0, \ Waiting, \ StartWaitPage, \ ByeDropout2, \ StoryIntro1, \ Story1, \ PlayerWaitPage1, \ Feedback1, \ Constraints, \ StoryIntro2, \ Story2, PlayerWaitPage2, \ Feedback2, \ StoryIntro3, \ Story3, \ PlayerWaitPage3, \ Feedback3, \ StoryIntro4, \ Story4, PlayerWaitPage4, \ Feedback4, \ ByeDropout1, \ ByeDropout2, \ EndPage, \ ]