from otree.api import * c = cu doc = '' #Class Creation class C(BaseConstants): NAME_IN_URL = 'RET' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 5 TOTAL_EARNINGS_WIN = 35 TOTAL_EARNINGS_LOSE = 25 #Set task parameters sliders_task_pms = dict( time_in_seconds=10, num=120, columns=3, max=100, min=0, target=50, default='min', # Sliders default value when the task begin ret_score=0, bonus_per_slider=cu(1), bonus=cu(0) ) class Subsession(BaseSubsession): pass class Group(BaseGroup): highest_score = models.IntegerField() class Player(BasePlayer): ret_score = models.IntegerField(initial=0) is_winner = models.IntegerField(initial=0) #Function Building def creating_session(subsession: Subsession): import random config = subsession.session.config session = subsession.session session.bonus_win = C.TOTAL_EARNINGS_WIN - config['participation_fee'] session.bonus_lose = C.TOTAL_EARNINGS_LOSE - config['participation_fee'] session.round_for_pay = random.randint(1, C.NUM_ROUNDS) players = subsession.get_players() for p in players: p.is_winner = 0 def set_groups(subsession: Subsession): session = subsession.session from random import shuffle players = subsession.get_players() unmatched = [] shuffle(players) n, r = divmod(len(players), C.PLAYERS_PER_GROUP) while r: p = players.pop() p.participant.unmatched = True unmatched.append(p) r -= 1 group_matrix = [players[n: n + C.PLAYERS_PER_GROUP] for n in range(0, len(players), C.PLAYERS_PER_GROUP)] if unmatched: group_matrix.append(unmatched) subsession.set_group_matrix(group_matrix) def set_chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] def set_sliders_task(const: C): from random import randint, choice # Copy task parameters from C (which therefore will remain unchanged) task = const.sliders_task_pms.copy() # Set random value for left margin of sliders in each row offsets = [randint(0, 10) for _ in range(task['num'] // task['columns'])] # Set default values of sliders: either to "min" or to random values if task['default'] == 'min': m = task['min'] curr_values = [m for _ in range(task['num'])] else: input_range = list(range(task['min'], task['max'])) input_range.remove(task['target']) curr_values = [choice(input_range) for _ in range(task['num'])] # Set list of rows containing the sliders: each row contains 3 sliders and the left margin for that row sliders = list(zip(set_chunks(curr_values, task['columns']), offsets)) # Flag task as set task_set = True # Update dictionary containing task parameters task.update(offsets=offsets, curr_values=curr_values, sliders=sliders) return task_set, task def set_winner(group: Group): import random players = group.get_players() session = group.session group.highest_score = max([p.ret_score for p in players]) players_with_highest_score = [p for p in players if p.ret_score == group.highest_score] winner = random.choice(players_with_highest_score) winner.is_winner = 1 for p in players: if p.is_winner: p.payoff = session.bonus_win else: p.payoff = session.bonus_lose #Pages class Round1(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class GroupingWait(WaitPage): wait_for_all_groups = True after_all_players_arrive = set_groups class RET(Page): timeout_seconds = C.sliders_task_pms['time_in_seconds'] timer_text = 'Remaining time: ' @staticmethod def vars_for_template(player: Player): pvars = player.participant.vars pvars['sliders_task_set'], pvars['sliders_task'] = set_sliders_task(C) # Returns the dictionary containing the task parameters as variables for the template return pvars['sliders_task'] @staticmethod def js_vars(player: Player): return player.participant.vars['sliders_task'] @staticmethod def live_method(player: Player, data): participant = player.participant # Get task parameters task = participant.vars['sliders_task'] # Get updated number of centered sliders player.ret_score = len([v for v in data if v == task['target']]) # Update task parameters based on: current values of the sliders, number of centered sliders, bonus accumulated task.update( sliders=list(zip(set_chunks(data, task['columns']), task['offsets'])), ret_score=player.ret_score, bonus=player.ret_score * task['bonus_per_slider'] ) # Send updated task's parameters to the webpage return {player.id_in_group: dict(ret_score=player.ret_score, bonus=task['bonus'])} # Set participant field with number of centered sliders @staticmethod def before_next_page(player: Player, timeout_happened): player.ret_score = player.participant.vars['sliders_task']['ret_score'] class WinnerWait(WaitPage): after_all_players_arrive = set_winner class Results(Page): form_model = 'player' @staticmethod def before_next_page(player: Player, timeout_happened): participant = player.participant session = player.session if player.round_number == session.round_for_pay: participant.bonus_earned = player.payoff participant.is_winner = player.is_winner page_sequence = [ Round1, GroupingWait, RET, WinnerWait, Results, ]