import random from otree.api import * import numpy as np from otree.models import player, subsession doc = """ A decision-making task with and without feedback""" class C(BaseConstants): NAME_IN_URL = 'decision_making_experiment' PLAYERS_PER_GROUP = None NUM_ROUNDS = 50 # participants_num = 10 groups = [1, 2] # 1 - With feedback, 2 - Without feedback conditions = [2, 2] # 1 - Gain domain, 2 - Loss domain environment = [0, 1] # 0 - Target Gambles, 1 - Surroundings Gambles positions = [0, 1] # 0 - Risk on the right, Safe on the left, 1 - Risk on the left, Safe on the right base_payment = Currency(0.5) risk = 1 safe = 0 high_low = [0, 1] ### 0 = Low, 1 = High risk_list = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] mixed_risk_chance = [1, -1] # Equals chanced to either gain or lose # pos_risk_chance = [1, 1, 1, -1, -1] # 60% gain, 40% lose # neg_risk_chance = [1, 1, -1, -1, -1] #40% gain, 60% lose safe_list = [0, 16, -16] attention_scores = [5, 0, 12, -12] attention_lables = ["A", "B", "C", "D"] bonus = 0.5 completion_code = ["CGJ4MTRO", "C1HV7N2R"] # Completion_code from settings. 0 - success, 1 - failure class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): age = models.IntegerField(min=15, max=90) gender = models.StringField(choices=['Male', 'Female', 'Other']) connect_id = models.StringField() choice_val = models.IntegerField() choice_credit = models.IntegerField() forgone_credit = models.IntegerField() risk_val = models.IntegerField() safe_val = models.IntegerField() high_risk_val = models.IntegerField() low_risk_val = models.IntegerField() pos_risk_val = models.IntegerField() # same as risk val but always positive pos_high_risk_val = models.IntegerField() pos_low_risk_val = models.IntegerField() group_info = models.IntegerField() # With or without feedback condition_info = models.IntegerField() #Pos or Neg condition environment_info = models.IntegerField() #Target vs Surroundings - Gain/Loss environment con_env_info = models.IntegerField() position = models.IntegerField() # Buttons position env_balanced_counter = models.IntegerField() # Count the number of times the Target env appeared env_pos_neg_counter = models.IntegerField() # Count the number of times the Surroundings env appeared attention_choice = models.StringField() attention_result = models.BooleanField() current_round = models.IntegerField() current_points = models.FloatField() total_points = models.FloatField() luck_level_1 = models.FloatField() luck_level_2 = models.FloatField() bonus = models.StringField() submission_code = models.StringField() high_low_info = models.IntegerField() risk_ev = models.IntegerField() def creating_session(subsession): # Random allocation for conditions for player in subsession.get_players(): player.payoff = C.base_payment if subsession.round_number <= 1: player.total_points = 0 player.current_round = 1 player.luck_level_1 = round(random.uniform(0, 800), 3) #for Gain condition (1) player.luck_level_2 = round(random.uniform(-800, 0), 3) #for Loss condition (2) player.high_low_info = random.choice(C.high_low) player.env_balanced_counter = 0 # Make sure each environment appears 25 times. player.env_pos_neg_counter = 1 # Make sure each environment appears 25 times. player.position = random.choice(C.positions) # Allocate to buttons position player.group_info = random.choice(C.groups) # Allocates to group player.environment_info = 1 # Allocates to environment player.condition_info = random.choice(C.conditions) # Allocates to condition player.con_env_info = player.condition_info * player.environment_info # 50% - 0, 25% - 1, 25% - 2 if player.con_env_info == 0: ### MIXED player.risk_val = random.choice(C.risk_list) * random.choice(C.mixed_risk_chance) #Mixed player.safe_val = C.safe_list[0] # Make sure I have a positive form of the risk_val (pos_risk_val) if player.risk_val > 0: player.pos_risk_val = player.risk_val elif player.risk_val < 0: player.pos_risk_val = player.risk_val * -1 elif player.con_env_info == 1: ### GAIN player.safe_val = C.safe_list[1] player.risk_ev = random.choice(C.risk_list) if player.high_low_info == 0: player.risk_val = player.safe_val - player.risk_ev player.low_risk_val = player.risk_val player.high_risk_val = player.low_risk_val + (player.risk_ev * 2) elif player.high_low_info == 1: player.risk_val = player.safe_val + player.risk_ev player.high_risk_val = player.risk_val player.low_risk_val = player.high_risk_val - (player.risk_ev * 2) elif player.con_env_info == 2: ### LOSS player.safe_val = C.safe_list[2] player.risk_ev = random.choice(C.risk_list) if player.high_low_info == 0: player.risk_val = player.safe_val - player.risk_ev player.low_risk_val = player.risk_val player.high_risk_val = player.low_risk_val + (player.risk_ev * 2) player.pos_high_risk_val = player.high_risk_val * -1 player.pos_low_risk_val = player.low_risk_val * -1 elif player.high_low_info == 1: player.risk_val = player.safe_val + player.risk_ev player.high_risk_val = player.risk_val player.low_risk_val = player.high_risk_val - (player.risk_ev * 2) player.pos_high_risk_val = player.high_risk_val * -1 player.pos_low_risk_val = player.low_risk_val * -1 else: player.total_points = player.in_round(player.round_number - 1).total_points player.current_round = player.in_round(player.round_number - 1).current_round + 1 player.luck_level_1 = player.in_round(player.round_number - 1).luck_level_1 player.luck_level_2 = player.in_round(player.round_number - 1).luck_level_2 player.position = player.in_round(player.round_number - 1).position player.group_info = player.in_round(player.round_number - 1).group_info # Keeps the Group value player.env_balanced_counter = player.in_round(player.round_number - 1).env_balanced_counter player.env_pos_neg_counter = player.in_round(player.round_number - 1).env_pos_neg_counter player.environment_info = player.in_round(player.round_number - 1).environment_info player.high_low_info = random.choice(C.high_low) if player.environment_info == 0: player.env_balanced_counter += 1 else: player.env_pos_neg_counter += 1 if player.env_balanced_counter == 25: # Make sure each environment appears 25 times. player.environment_info = 1 elif player.env_pos_neg_counter == 25: # Make sure each environment appears 25 times. player.environment_info = 0 else: player.environment_info = random.choice(C.environment) player.condition_info = player.in_round(player.round_number - 1).condition_info # Keeps the Condition value player.con_env_info = player.condition_info * player.environment_info if player.con_env_info == 0: ### MIXED player.risk_val = random.choice(C.risk_list) * random.choice(C.mixed_risk_chance) # Mixed player.safe_val = C.safe_list[0] # Make sure I have a positive form of the risk_val (pos_risk_val) if player.risk_val > 0: player.pos_risk_val = player.risk_val elif player.risk_val < 0: player.pos_risk_val = player.risk_val * -1 elif player.con_env_info == 1: ### GAIN player.safe_val = C.safe_list[1] player.risk_ev = random.choice(C.risk_list) if player.high_low_info == 0: player.risk_val = player.safe_val - player.risk_ev player.low_risk_val = player.risk_val player.high_risk_val = player.low_risk_val + (player.risk_ev * 2) elif player.high_low_info == 1: player.risk_val = player.safe_val + player.risk_ev player.high_risk_val = player.risk_val player.low_risk_val = player.high_risk_val - (player.risk_ev * 2) elif player.con_env_info == 2: ### LOSS player.safe_val = C.safe_list[2] player.risk_ev = random.choice(C.risk_list) if player.high_low_info == 0: player.risk_val = player.safe_val - player.risk_ev player.low_risk_val = player.risk_val player.high_risk_val = player.low_risk_val + (player.risk_ev * 2) player.pos_high_risk_val = player.high_risk_val * -1 player.pos_low_risk_val = player.low_risk_val * -1 elif player.high_low_info == 1: player.risk_val = player.safe_val + player.risk_ev player.high_risk_val = player.risk_val player.low_risk_val = player.high_risk_val - (player.risk_ev * 2) player.pos_high_risk_val = player.high_risk_val * -1 player.pos_low_risk_val = player.low_risk_val * -1 # PAGES HTML class Intro(Page): form_model = "player" form_fields = ["gender", "age", "connect_id"] def is_displayed(player: Player): # Appears only in round 1. return player.round_number == 1 class Exp_Decision(Page): form_model = "player" form_fields = ["choice_val"] def before_next_page(player: Player, timeout_happened): # Calculate participants' payoffs parameter = 1 if player.choice_val == C.risk: player.choice_credit = player.risk_val player.forgone_credit = player.safe_val else: player.choice_credit = player.safe_val player.forgone_credit = player.risk_val player.current_points = player.choice_credit while parameter <= player.current_round: # Sums up the accumulated points player.total_points += player.in_round(parameter).current_points parameter += 1 class Exp_Results(Page): form_model = "player" def vars_for_template(player: Player): pass def before_next_page(player: Player, timeout_happened): pass # class ResultsWaitPage(WaitPage): # pass class Attention_check(Page): form_model = "player" form_fields = ["attention_choice"] def before_next_page(player: Player, timeout_happened): # return variables to be used in template if player.attention_choice == "C": player.attention_result = True return{ "completion_code": "Passed", "attention_result": "True" } else: player.attention_result = False return{ "completion_code": "Failed", "attention_result": "False" } def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS class Results(Page): form_model = "player" def vars_for_template(player: Player): if player.attention_result == True: if player.condition_info == 1 and player.total_points > player.luck_level_1: player.bonus = "Yes" final_payoff = C.base_payment + C.bonus player.payoff = final_payoff player.submission_code = C.completion_code[0] return {"final_payoff": player.payoff, "completion_code": player.submission_code} elif player.condition_info == 2 and player.total_points > player.luck_level_2: player.bonus = "Yes" final_payoff = C.base_payment + C.bonus player.payoff = final_payoff player.submission_code = C.completion_code[0] return {"final_payoff": player.payoff, "completion_code": player.submission_code} else: player.bonus = "No" final_payoff = C.base_payment player.payoff = final_payoff player.submission_code = C.completion_code[1] return {"final_payoff": player.payoff, "completion_code": player.submission_code} else: player.bonus = "No" final_payoff = C.base_payment player.payoff = final_payoff player.submission_code = C.completion_code[1] return {"final_payoff": player.payoff, "completion_code": player.submission_code} def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS page_sequence = [Intro, Exp_Decision, Exp_Results, Attention_check, Results]