from otree.api import * import random import shared_constants from experiment_text import display_topic, option_label from session_utils import merge_t, get_language, texts_for doc = """ App 2: Room Composition + Guessing Game Participants are placed in a hypothetical room, decide on an action, and then immediately provide beliefs about that specific room. """ class C(BaseConstants): NAME_IN_URL = 'room_composition' PLAYERS_PER_GROUP = None ROOM_TYPES = shared_constants.ROOM_TYPES C_HIGH = shared_constants.C_HIGH_POINTS C_LOW = shared_constants.C_LOW_POINTS NUM_ROUNDS = len(ROOM_TYPES) class Subsession(BaseSubsession): pass def creating_session(subsession): if subsession.round_number == 1: lang = subsession.session.config.get('language', 'en') for p in subsession.get_players(): p.participant.vars['language'] = lang p.participant.session_language = lang my_rooms = C.ROOM_TYPES.copy() random.shuffle(my_rooms) p.participant.vars['room_schedule'] = my_rooms if 'topic_order' in p.participant.vars: p.participant.vars['app2_topic_schedule'] = p.participant.vars['topic_order'][: C.NUM_ROUNDS] else: fallback = shared_constants.TOPICS.copy() random.shuffle(fallback) p.participant.vars['app2_topic_schedule'] = fallback[: C.NUM_ROUNDS] for p in subsession.get_players(): round_idx = p.round_number - 1 room_config = p.participant.vars['room_schedule'][round_idx] topic = p.participant.vars['app2_topic_schedule'][round_idx] p.room_label = room_config['label'] p.cost_condition = str(room_config['cost_val']) p.majority_size = room_config['majority_n'] p.topic_label = topic class Group(BaseGroup): pass class Player(BasePlayer): room_label = models.StringField() cost_condition = models.StringField() majority_size = models.IntegerField() topic_label = models.StringField() true_opinion = models.StringField() majority_opinion = models.StringField() expressed_opinion = models.StringField( label="", widget=widgets.RadioSelect, ) belief_lying = models.IntegerField( min=0, max=10, label="", ) def expressed_opinion_choices(player): topic = player.topic_label user_data = player.participant.vars.get('topic_data', {}).get(topic) lang = get_language(player) if user_data: true_op = user_data['opinion'] else: true_op = 'A' other = 'B' if true_op == 'A' else 'A' return [ ['true', option_label(lang, true_op)], ['lie', option_label(lang, other)], ] class DecisionPage(Page): form_model = 'player' form_fields = ['expressed_opinion'] @staticmethod def vars_for_template(player): room_config = player.participant.vars['room_schedule'][player.round_number - 1] user_data = player.participant.vars.get('topic_data', {}).get(player.topic_label) lang = get_language(player) tx = texts_for(player) if user_data: true_op = user_data['opinion'] punish_willingness = user_data['punish'] else: true_op = 'A' punish_willingness = False true_op_code = true_op majority_op_code = 'A' if true_op_code == 'B' else 'B' true_opinion_label = option_label(lang, true_op_code) majority_opinion_label = option_label(lang, majority_op_code) current_c_val = room_config['cost_val'] cost_suffix = room_config['label'].split('-')[1] image_name = f"{room_config['majority_n']}A-{cost_suffix}.png" topic_display = display_topic(lang, player.topic_label) player.true_opinion = true_opinion_label player.majority_opinion = majority_opinion_label labeled_a = tx['labeled_as_a'] labeled_b = tx['labeled_as_b'] return merge_t( player, { 'topic': topic_display, 'topic_key': player.topic_label, 'true_opinion': true_opinion_label, 'majority_opinion': majority_opinion_label, 'punish_willingness': punish_willingness, 'room': room_config, 'current_c_val': current_c_val, 'image_path': 'room_composition/' + image_name, 'page_title': tx['room_decision_title'].format(topic=topic_display), 'decision_p1': tx['room_decision_p1'].format( maj=room_config['majority_n'], minr=room_config['minority_n'], maj_op=majority_opinion_label, true_op=true_opinion_label, topic=topic_display, labeled_a=labeled_a, labeled_b=labeled_b, ), 'decision_p2': tx['room_decision_p2'].format(cost=current_c_val), }, ) class BeliefsPage(Page): form_model = 'player' form_fields = ['belief_lying'] @staticmethod def vars_for_template(player): room_config = player.participant.vars['room_schedule'][player.round_number - 1] lang = get_language(player) tx = texts_for(player) cost_suffix = room_config['label'].split('-')[1] image_name = f"{room_config['majority_n']}A-{cost_suffix}.png" topic_display = display_topic(lang, player.topic_label) my_op = player.true_opinion maj_op = player.majority_opinion return merge_t( player, { 'room': room_config, 'topic': topic_display, 'my_true_opinion': my_op, 'majority_opinion': maj_op, 'current_c_val': room_config['cost_val'], 'image_path': 'room_composition/' + image_name, 'beliefs_li1': tx['beliefs_li1'].format(op=my_op, topic=topic_display), 'beliefs_li2': tx['beliefs_li2'].format( maj=room_config['majority_n'], minr=room_config['minority_n'], maj_op=maj_op, my_op=my_op, opt_a=tx['paren_option_a'], opt_b=tx['paren_option_b'], ), 'beliefs_li3': tx['beliefs_li3'].format(cost=room_config['cost_val']), 'beliefs_prompt': tx['beliefs_prompt'].format(op=my_op), }, ) class FinalPage(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player): return merge_t(player) page_sequence = [DecisionPage, BeliefsPage, FinalPage]