#models.py file contains the game's data models (player, group, subsession) and contast parameters #Any code that is not inside a method is basically global and will only be executed once – when the server starts. #main purpose of models.py: to define the columns of your database tables from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random doc = """ This is a one-period public goods game with 4 players. """ #constats class - define our constants and parameters (things that are the same for all players in all games) class Constants(BaseConstants): name_in_url = 'public_goods_V2_2' #required constant: the name used to identify your app in the participant's URL players_per_group = 4 #set the group size num_rounds = 10 punishment_amount = 10 reward_amount = 10 instructions_template = 'public_goods_V2_2/Instructions.html' # """Amount allocated to each player""" endowment = c(100) multiplier = 2 #TO WRITE A COMMENT WHAT's HAPPENING HERE #a player is part of a group, a group is part of a subsession class Subsession(BaseSubsession): def vars_for_admin_report(self): contributions = [p.contribution for p in self.get_players() if p.contribution != None] if contributions: return { 'avg_contribution': sum(contributions)/len(contributions), 'min_contribution': min(contributions), 'max_contribution': max(contributions), } else: return { 'avg_contribution': '(no data)', 'min_contribution': '(no data)', 'max_contribution': '(no data)', } #TO WRITE A COMMENT WHAT's HAPPENING HERE #to know how much each person contributes, define a field contribution #we are interested in knowing the total contributions to the group, and the individual share returned to each player #so we define those 2 fields class Group(BaseGroup): total_contribution = models.CurrencyField() individual_share = models.CurrencyField() total_payoff = models.CurrencyField() #to set the payoffs: the common pool is multiplying the contribution w 2 and is equally diving according to how many players are playing #define a method that calculates the payoff (and other fields like total_contribution and individual_share - that's set_payoffs def set_payoffs(self): self.total_contribution = sum([p.contribution for p in self.get_players()]) self.individual_share = self.total_contribution * Constants.multiplier / Constants.players_per_group self.total_payoff = self.total_contribution * Constants.multiplier for p in self.get_players(): playerID = p.id_in_group totalPunishment = 0 totalReward = 0 for otherPlayers in self.get_players(): if playerID == 1: if otherPlayers.punish_1: totalPunishment += Constants.punishment_amount elif playerID == 2: if otherPlayers.punish_2: totalPunishment += Constants.punishment_amount elif playerID == 3: if otherPlayers.punish_3: totalPunishment += Constants.punishment_amount elif playerID == 4: if otherPlayers.punish_4: totalPunishment += Constants.punishment_amount for otherPlayers in self.get_players(): if playerID == 1: if otherPlayers.punish_1: totalReward += Constants.reward_amount elif playerID == 2: if otherPlayers.punish_2: totalReward += Constants.reward_amount elif playerID == 3: if otherPlayers.punish_3: totalReward += Constants.reward_amount elif playerID == 4: if otherPlayers.punish_4: totalReward += Constants.reward_amount p.payoff = (Constants.endowment - p.contribution) + self.individual_share - totalPunishment + totalReward class Player(BasePlayer): contribution = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", ) punish_1 = models.BooleanField(blank=True) punish_2 = models.BooleanField(blank=True) punish_3 = models.BooleanField(blank=True) punish_4 = models.BooleanField(blank=True) reward_1 = models.BooleanField(blank=True) reward_2 = models.BooleanField(blank=True) reward_3 = models.BooleanField(blank=True) reward_4 = models.BooleanField(blank=True)