from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) doc = """ Public goods game to avoid probablistic disaster """ class Constants(BaseConstants): name_in_url = 'maingame_updownstream' players_per_group = 4 num_rounds = 5 instruction_summary = '../_templates/Instruction_Summary.html' endowment = 120 disaster_damage = 80 cost_A = 1 num_trash = 30 max_trash = 120 #alpha = 2 #beta = 1 trash = [0, 10, 50, 100] rate = 30 participation_fee = 500 class Subsession(BaseSubsession): info = models.BooleanField() F_Form = models.FloatField() initial_trash = models.IntegerField() def creating_session(self): import random for g in self.get_groups(): g.disaster_threshold = random.uniform(0,1) if self.round_number == 1: self.session.vars['trash_list'] = random.sample(Constants.trash,4)+random.sample(Constants.trash,4)+random.sample(Constants.trash,4) self.initial_trash = self.session.vars['trash_list'][self.round_number - 1] def get_game(self): self.info = self.session.config['info'] self.F_Form = self.session.config['F_Form'] class Group(BaseGroup): total_contribution = models.IntegerField() total_trash_B = models.IntegerField() disaster_threshold = models.FloatField() disaster_probability = models.FloatField() disaster = models.BooleanField() rebate = models.FloatField() def set_payoffs(self): self.total_contribution = sum([p.contribution for p in self.get_players()]) self.total_trash_B = sum([p.trash_B for p in self.get_players()]) + self.subsession.initial_trash def calc_disaster(self): if self.total_trash_B <= 0: self.disaster_probability = 0 self.rebate = - self.total_trash_B / 4 else: """Use the next three lines if there is a need to implement other beta functions. Line 78 is the beta function for the case of alpha = 2 and beta = 1""" # import random # from scipy import stats # self.disaster_probability = stats.beta.cdf(self.total_trash_B/Constants.max_trash,Constants.alpha,Constants.beta,loc=0,scale=1) self.disaster_probability = (self.total_trash_B / Constants.max_trash) ** 2 self.rebate = 0 if self.disaster_probability >= self.disaster_threshold: self.disaster = 1 else: self.disaster = 0 for p in self.get_players(): import math p.payoff = (Constants.endowment - p.contribution) - self.disaster * Constants.disaster_damage + math.ceil(self.rebate) p.Payoff_int = (Constants.endowment - p.contribution) - self.disaster * Constants.disaster_damage + math.ceil(self.rebate) p.Total_trash_B = self.total_trash_B p.Disaster = self.disaster class Player(BasePlayer): contribution = models.IntegerField(label='', min=0) trash_B = models.IntegerField() Total_trash_B = models.IntegerField() Payoff_int = models.IntegerField() Disaster = models.BooleanField() def contribution_max(self): return Constants.max_trash def calc_B(self): self.trash_B = Constants.num_trash - self.contribution def store_results(self): if self.round_number == Constants.num_rounds: prev_player = self.in_all_rounds() self.participant.vars['Cont_hist'] = [p.contribution for p in prev_player] self.participant.vars['Payoff_hist'] = [p.Payoff_int for p in prev_player] self.participant.vars['TrashB_hist'] = [p.Total_trash_B for p in prev_player] self.participant.vars['Disaster_hist'] = [p.Disaster for p in prev_player] print('vars is', self.participant.vars)