import random from otree.api import * doc = """ Your app description """ class C(BaseConstants): NAME_IN_URL = 'PC' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 16 FINE_PROB = .15 MANAGER_ROLE = 'Manager' FIRM1_ROLE = 'Firm1' FIRM2_ROLE = 'Firm2' AA = 'A and A' AB = 'A and B' BA = 'B and A' BB = 'B and B' MAA = cu(1250) MAB = cu(925) MBA = cu(1406) MBB = cu(1111) MFAA = cu(225) NOFINE = cu(0) # Need to set up payoffs for owners and managers # # Need to set up fine for owners and managers # class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: self.group_randomly() for g in self.get_groups(): for p in g.get_players(): if p.id_in_group == 1: p.firm = "1" elif p.id_in_group == 2: p.firm = "2" p.type = p.participant.vars['type'] else: self.group_like_round(1) class Group(BaseGroup): # TODO save whether there was a fine in the group pass class Player(BasePlayer): firm = models.StringField() type = models.StringField() earnings = models.CurrencyField() fine = models.CurrencyField() contract = models.StringField() dollars = models.FloatField() other_manager = models.StringField() manager_decision = models.BooleanField( choices=[[True, 'A'], [False, 'B']], label="What is your decision?", widget=widgets.RadioSelectHorizontal, ) # FUNCTIONS def custom_export(players): # header row yield ['session', 'participant_code', 'round_number', 'id_in_group', 'payoff'] for p in players: participant = p.participant session = p.session yield [session.code, participant.code, p.round_number, p.id_in_group, p.payoff] # Need to define payoffs according to owners' and managers' decisions # def competitor(player: Player): compete_players = player.get_others_in_group() for comp in compete_players: if comp.firm != player.firm: return comp def other_manager(player: Player): other_players = player.get_others_in_group() for other_player in other_players: if other_player.firm != player.firm: return other_player def set_managers_decision_combination(player: Player): managers_decision_combination_matrix = { (False, True): C.BA, (True, True): C.AA, (False, False): C.BB, (True, False): C.AB, } other_m = other_manager(player) player.decision = managers_decision_combination_matrix[(player.manager_decision, other_m.manager_decision)] def set_earnings(group: Group): players = group.get_players() should_fine_this_round = should_fine() for p in players: earnings = calculate_managerearnings(p) fine = calculate_managerfine(p) if should_fine_this_round else cu(0) # Save current round payoff in player model p.earnings = earnings p.fine = fine p.payoff = earnings - fine # Save history in participant p.participant.vars['earnings'] = p.participant.vars.get('earnings', list()) p.participant.vars['earnings'].append(earnings) p.participant.vars['fines'] = p.participant.vars.get('fines', list()) p.participant.vars['fines'].append(fine) def calculate_managerearnings(player: Player): managerearnings_matrix = { (True, True): C.MAA, (True, False): C.MAB, (False, True): C.MBA, (False, False): C.MBB, } other_m = other_manager(player) return managerearnings_matrix[(player.manager_decision, other_m.manager_decision)] def should_fine(): return random.random() < C.FINE_PROB def calculate_managerfine(player: Player): managerfine_matrix = { (True, True): C.MFAA, } other_m = other_manager(player) return managerfine_matrix[(player.manager_decision, other_m.manager_decision)] # PAGES class Instruction1(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class Instruction2(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 1 class MyWaitPage(WaitPage): @staticmethod def after_all_players_arrive(group: Group): pass class ResultsWaitPage(WaitPage): after_all_players_arrive = 'set_earnings' class Roundst(Page): @staticmethod def after_all_players_arrive(group: Group): pass class Chat(Page): timeout_seconds = 60 form_model = 'player' @staticmethod def is_displayed(player: Player): if player.id_in_group == 1: player.type = C.MANAGER_ROLE player.participant.vars['type'] = C.MANAGER_ROLE player.firm = "1" elif player.id_in_group == 2: player.type = C.MANAGER_ROLE player.participant.vars['type'] = C.MANAGER_ROLE player.firm = "2" return player.type == C.MANAGER_ROLE @staticmethod def vars_for_template(player: Player): player.firm = player.firm return dict(MFPPAA=C.MFAA, firm=player.firm ) class Stage2(Page): form_model = 'player' form_fields = ['manager_decision'] @staticmethod def is_displayed(player: Player): if player.id_in_group == 1: player.type = C.MANAGER_ROLE player.participant.vars['type'] = C.MANAGER_ROLE player.firm = "1" elif player.id_in_group == 2: player.type = C.MANAGER_ROLE player.participant.vars['type'] = C.MANAGER_ROLE player.firm = "2" return player.type == C.MANAGER_ROLE @staticmethod def vars_for_template(player: Player): player.firm = player.firm return dict( firm=player.firm ) class RoundResults(Page): @staticmethod def vars_for_template(player: Player): history = list() all_earnings = player.participant.vars['earnings'] all_fines = player.participant.vars['fines'] player.firm = player.firm compete = competitor(player) com_earning = compete.participant.vars['earnings'] com_fine = compete.participant.vars['fines'] for index, earnings in enumerate(all_earnings): fine = all_fines[index] com_earnings = com_earning[index] com_fines = com_fine[index] history.append(dict( round=index + 1, earnings=earnings, fine=fine, payoff=earnings-fine, com_earnings=com_earnings, com_fines=com_fines, com_payoffs=com_earnings-com_fines, )) return dict( history=history, total_payoff=player.participant.payoff, total_fine=sum(all_fines), total_earnings=sum(all_earnings), firm=player.firm, com_firm=compete.firm, total_com_payoffs=compete.participant.payoff, ) class FinalResults(Page): @staticmethod def is_displayed(player: Player): return player.round_number == 16 @staticmethod def vars_for_template(player: Player): reward_dollars = player.participant.payoff.to_real_world_currency(player.session) * 0.5 return dict( reward=reward_dollars, rewardandshowupfee=reward_dollars + 10 ) # Instruction1, Instruction2, page_sequence = [Instruction1, Instruction2, MyWaitPage, Roundst, MyWaitPage, Chat, MyWaitPage, Stage2, ResultsWaitPage, RoundResults, FinalResults]