from otree.api import * from random import randrange import time c = Currency doc = """ Your app description """ # Note: As an app, using "app_after_this_page" gives an error if the entered value is more than 5 dollars # This app runs properly when combined with another app class Constants(BaseConstants): name_in_url = 'dotActivity' players_per_group = None num_rounds = 100 payment_per_correct_answer = cu(1) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): dot_guess_number = models.IntegerField( # guessed number of dots label = "How many dots do you count?" ) real_dot_number = models.IntegerField() # actual number of dots user_answer = models.IntegerField( choices=[38,39,40,41,42], widget=widgets.RadioSelect, label="Guess how many dots there are!" ) # Ask the participant for the number of dollars he/she is willing to value user_payment = models.IntegerField(label="How much do you value this activity in terms of dollars?") # PAGES class dotInstructions(Page): # only shows instructions on the first round @staticmethod def is_displayed(player: Player): return player.round_number == 1 class CounterOfferPage(Page): form_model = "player" form_fields = ["user_payment"] # @staticmethod # def is_displayed(player: Player): # return player.round_number == 1 # only shows counteroffer on the first round @staticmethod def is_displayed(player: Player): return player.round_number == 1 # skips the entire app if the user puts an amount greater than 5 dollars def app_after_this_page(player, upcoming_apps): if player.user_payment > 5: return upcoming_apps[0] # When this page "ends", a session timer will start @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant import time participant.expiry = time.time() + 1*15 # 1*60sec class dotActivity(Page): form_model = "player" form_fields = ["user_answer"] # everytime the page is refreshed/generated, # make sure the number of dots generated (generated_dot_count) is assigned to "real_dot_number" @staticmethod def vars_for_template(player: Player): generated_dot_count = randrange(38,42) # generated number of dots player.real_dot_number = generated_dot_count # store generated dot number into "real_dot_number" return { "generated_dot_count": generated_dot_count # HTML variable } # before the next page loads, compare the participants entered guess (dot_guess_number) with the "real_dot_number" # if the guessed number equals the actual number, then add a payment to participants payoff def before_next_page(player: Player, timeout_happened): if player.real_dot_number == player.user_answer: player.payoff = Constants.payment_per_correct_answer # literrly change the timer text timer_text = 'Time left to complete this section:' # everytime another round is generated, carry over the remaining time from the previous page def get_timeout_seconds(player): participant = player.participant import time return participant.expiry - time.time() # remember to add 'expiry' to PARTICIPANT_FIELDS in settings.py # # Display this page only if paricipant payment is less than or equal to 5. # @staticmethod # def is_displayed(player): # if player.round_number == 1: # if player.user_payment <= 5: # return True # else: # return False # when the time is less that two seconds, quit the current round and skip to the "Results" page @staticmethod def is_displayed(player): participant = player.participant import time time_remaining = participant.expiry - time.time() return time_remaining > 2 class Results(Page): # # Display this page only if paricipant payment is less than or equal to 5. # @staticmethod # def is_displayed(player): # if player.round_number == 1: # if player.user_payment <= 5: # return True # else: # return False # this page will only appear when the number of rounds are complete @staticmethod def is_displayed(player: Player): return player.round_number == Constants.num_rounds # add the number of correct answer payments from the previous rounds @staticmethod def vars_for_template(player: Player): all_players = player.in_all_rounds() combined_payoff = 0 for temp_player in all_players: combined_payoff += temp_player.payoff return { "combined_payoff": combined_payoff } class Disagree(Page): # # Display this page only if paricipant payment is greater than 5. # @staticmethod # def is_displayed(player): # if player.round_number == 1: # if player.user_payment > 5: # return True # else: # return False pass page_sequence = [dotInstructions, CounterOfferPage, dotActivity, Results]