class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> def highest_bid(self): return max([p.bid_amount for p in self.get_players()]) def set_winner(self): players_with_highest_bid = [p for p in self.get_players() if p.bid_amount == self.highest_bid()] winner = random.choice(players_with_highest_bid) # if tie, winner is chosen at random winner.is_winner = True item_value = models.CurrencyField( initial=lambda: round(random.uniform(Constants.min_allowable_bid, Constants.max_allowable_bid), 1), doc="""Common value of the item to be auctioned, random for treatment""" ) def generate_value_estimate(self): minimum = self.item_value - Constants.estimate_error_margin maximum = self.item_value + Constants.estimate_error_margin estimate = round(random.uniform(minimum, maximum), 1) if estimate < Constants.min_allowable_bid: estimate = Constants.min_allowable_bid if estimate > Constants.max_allowable_bid: estimate = Constants.max_allowable_bid return estimate def other_players_count(self): return len(self.other_players_count()-1)
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> players_per_group = 2
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> choice = models.CharField(default=None, doc="""Either A or B""", widget=widgets.RadioSelect()) def choice_choices(self): return ['A', 'B'] def other_player(self): """Returns other player in group""" return self.other_players_in_group()[0]
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_question_1 = models.CharField(max_length=100, null=True, verbose_name='', widget=widgets.RadioSelect()) def training_question_1_choices(self): return ['Alice gets 300 points, Bob gets 0 points', 'Alice gets 200 points, Bob gets 200 points', 'Alice gets 0 points, Bob gets 300 points', 'Alice gets 100 points, Bob gets 100 points'] def is_training_question_1_correct(self): return self.training_question_1 == self.subsession.training_1_correct points_earned = models.PositiveIntegerField( default=0, doc="""Points earned""" ) decision = models.CharField( default=None, doc="""This player's decision""", widget=widgets.RadioSelect() ) def decision_choices(self): return ['Cooperate', 'Defect'] def other_player(self): return self.other_players_in_group()[0] def set_points(self): points_matrix = {'Cooperate': {'Cooperate': self.subsession.cooperate_amount, 'Defect': self.subsession.cooperate_defect_amount}, 'Defect': {'Cooperate': self.subsession.defect_cooperate_amount, 'Defect': self.subsession.defect_amount}} self.points_earned = (points_matrix[self.decision] [self.other_player().decision]) def set_payoff(self): self.payoff = 0
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> penny_side = models.CharField(choices=['Heads', 'Tails'], widget=widgets.RadioSelect()) is_winner = models.BooleanField() def role(self): if self.id_in_group == 1: return 'Mismatcher' if self.id_in_group == 2: return 'Matcher'
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> def set_payoff(self): """Calculate payoff, which is zero for the survey""" self.payoff = 0 def q_gender_choices(self): return ['Female', 'Male', 'Other', 'I prefer not to say'] q_gender = models.CharField(verbose_name='Please indicate your gender:', widget=widgets.RadioSelect())
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> contribution = models.CurrencyField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", ) question = models.CurrencyField() def question_correct(self): return self.question == Constants.question_correct
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> players_per_group = 2 total_return = models.MoneyField( doc="""Total return from agent's effort = [Return for single unit of agent's work effort] * [Agent's work effort]""" ) agent_fixed_pay = models.MoneyField( doc="""Amount offered as fixed pay to agent""" ) agent_return_share = models.FloatField( doc="""Agent's share of total return""", ) agent_work_effort = models.PositiveIntegerField( doc="""Agent's work effort, [1, 10]""", ) agent_work_cost = models.MoneyField( doc="""Agent's cost of work effort""" ) contract_accepted = models.NullBooleanField( doc="""Whether agent accepts proposal""", widget=widgets.RadioSelect(), ) # choices def agent_fixed_pay_choices(self): return money_range(-Constants.max_fixed_payment, Constants.max_fixed_payment, 0.50) def agent_work_effort_choices(self): return range(1, 10+1) def agent_return_share_choices(self): return Constants.agent_return_share_choices def set_payoffs(self): principal = self.get_player_by_role('principal') agent = self.get_player_by_role('agent') if not self.contract_accepted: principal.payoff = Constants.reject_principal_pay agent.payoff = Constants.reject_agent_pay else: self.agent_work_cost = cost_from_effort(self.agent_work_effort) self.total_return = return_from_effort(self.agent_work_effort) money_to_agent = self.agent_return_share*self.total_return + self.agent_fixed_pay agent.payoff = money_to_agent - self.agent_work_cost principal.payoff = self.total_return - money_to_agent
class Player(otree.models.BasePlayer): BONUS = 10 # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_answer_mine = models.PositiveIntegerField( null=True, verbose_name='My compensation would be') training_answer_others = models.PositiveIntegerField( null=True, verbose_name="The other traveler's compensation would be") # claim by player claim = models.PositiveIntegerField( doc=""" Each player's claim """, verbose_name='Please enter a number from 2 to 100' ) feedback = models.PositiveIntegerField( choices=( (5, 'Very well'), (4, 'Well'), (3, 'OK'), (2, 'Badly'), (1, 'Very badly')), widget=widgets.RadioSelectHorizontal(), verbose_name='') def claim_error_message(self, value): if not Constants.min_amount\ <= value <= Constants.max_amount: return 'Your entry is invalid.' def other_player(self): return self.get_others_in_group()[0] def set_payoff(self): other = self.other_player().claim if self.claim < other: self.payoff = self.BONUS + self.claim + Constants.reward elif self.claim > other: self.payoff = self.BONUS + other - Constants.penalty else: self.payoff = self.BONUS + self.claim
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> request_amount = models.CurrencyField(doc=""" Amount requested by this player. """, bounds=[0, Constants.amount_shared]) training_amount_mine = models.CurrencyField(verbose_name='You would get') training_amount_other = models.CurrencyField( verbose_name='The other participant would get') def other_player(self): """Returns the opponent of the current player""" return self.get_others_in_group()[0]
def _ensure_required_fields(cls): """ Every ``Group`` model requires a foreign key to the ``Subsession`` model of the same app. """ subsession_model = '{app_label}.Subsession'.format( app_label=cls._meta.app_label) subsession_field = models.ForeignKey(subsession_model) ensure_field(cls, 'subsession', subsession_field)
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> price = models.CurrencyField( doc="""Unit price: P = T - Q1 - Q2, where T is total capacity and Q_i are the units produced by the players""" )
class Treatment(otree.models.BaseTreatment): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> match_payoff = models.MoneyField( default=200, doc="payoff if answer matches most common answer" )
def _ensure_required_fields(cls): """ Every ``Player`` model requires a foreign key to the ``Subsession`` and ``Group`` model of the same app. """ subsession_model = '{app_label}.Subsession'.format( app_label=cls._meta.app_label) subsession_field = models.ForeignKey(subsession_model, on_delete=models.CASCADE) ensure_field(cls, 'subsession', subsession_field) group_model = '{app_label}.Group'.format(app_label=cls._meta.app_label) group_field = models.ForeignKey(group_model, null=True, on_delete=models.CASCADE) ensure_field(cls, 'group', group_field) add_field_tracker(cls)
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_question_1 = models.CharField(max_length=100, null=True, verbose_name='', widget=widgets.RadioSelect()) def training_question_1_choices(self): return [ 'Player 1 gets 0 points, Player 2 gets 0 points', 'Player 1 gets 100 points, Player 2 gets 100 points', 'Player 1 gets 100 points, Player 2 gets 0 points', 'Player 1 gets 0 points, Player 2 gets 100 points' ] def is_training_question_1_correct(self): return self.training_question_1 == Constants.training_1_correct points_earned = models.PositiveIntegerField(default=0, doc="""Points earned""") penny_side = models.CharField(choices=['Heads', 'Tails'], doc="""Heads or tails""", widget=widgets.RadioSelect()) is_winner = models.NullBooleanField(doc="""Whether player won the round""") def other_player(self): """Returns the opponent of the current player""" return self.get_others_in_group()[0] def role(self): if self.id_in_group == 1: return 'Player 1' if self.id_in_group == 2: return 'Player 2' def set_payoff(self): self.payoff = 0
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> total_return = models.CurrencyField( doc="""Total return from agent's effort = [Return for single unit of agent's work effort] * [Agent's work effort]""") agent_fixed_pay = models.CurrencyField( doc="""Amount offered as fixed pay to agent""", bounds=[Constants.min_fixed_payment, Constants.max_fixed_payment], verbose_name='Fixed Payment (from %i to %i)' % (Constants.min_fixed_payment, Constants.max_fixed_payment)) agent_return_share = models.FloatField( choices=Constants.agent_return_share_choices, doc="""Agent's share of total return""", verbose_name='Return Share', widget=widgets.RadioSelectHorizontal()) agent_work_effort = models.PositiveIntegerField( choices=range(1, 10 + 1), doc="""Agent's work effort, [1, 10]""", widget=widgets.RadioSelectHorizontal(), ) agent_work_cost = models.CurrencyField( doc="""Agent's cost of work effort""") contract_accepted = models.NullBooleanField( doc="""Whether agent accepts proposal""", widget=widgets.RadioSelect(), choices=( (True, 'Accept'), (False, 'Reject'), )) def set_payoffs(self): principal = self.get_player_by_role('principal') agent = self.get_player_by_role('agent') if not self.contract_accepted: principal.payoff = Constants.reject_principal_pay agent.payoff = Constants.reject_agent_pay else: self.agent_work_cost = cost_from_effort(self.agent_work_effort) self.total_return = return_from_effort(self.agent_work_effort) money_to_agent = self.agent_return_share * \ self.total_return + self.agent_fixed_pay agent.payoff = money_to_agent - self.agent_work_cost principal.payoff = self.total_return - money_to_agent principal.payoff += Constants.bonus agent.payoff += Constants.bonus
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> # transaction fields transaction_price = models.CurrencyField(doc="""Given by 0.5*(BP+SP)""") shares_traded = models.PositiveIntegerField(initial=0) # dividend fields dividend_per_share = models.CurrencyField() is_dividend = models.BooleanField(initial=False, doc="""Indicates whether dividend is issued""") # method to set cash and shares to balance in previous round def set_assets_to_previous(self): for p in self.get_players(): p.cash = p.in_previous_rounds()[-1].cash p.shares = p.in_previous_rounds()[-1].shares def trade(self): buyers = [p for p in self.get_players() if p.order_type == 'Buy'] sellers = [p for p in self.get_players() if p.order_type == 'Sell'] # both lists must have exactly 1 element if not (buyers and sellers): return buyer = buyers[0] seller = sellers[0] if seller.sp >= buyer.bp or (buyer.bn * buyer.bp == 0) or (seller.sn * seller.sp == 0): return # average of buy & sell price self.transaction_price = 0.5*(buyer.bp+seller.sp) self.shares_traded = min(buyer.bn, seller.sn) # adjust shares and cash amount = self.transaction_price * self.shares_traded if amount > buyer.cash: return buyer.shares += self.shares_traded buyer.cash -= amount seller.shares -= self.shares_traded seller.cash += amount def set_dividend(self): self.dividend_per_share = randint(1,2) self.is_dividend = True # adjust cash for p in self.get_players(): p.cash += ( p.shares * self.dividend_per_share if p.shares != 0 else p.cash )
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> def set_payoffs(self): for p in self.get_players(): p.payoff = 50 in_all_groups_wait_page = models.FloatField(initial=0)
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_question_1_my_payoff = models.CurrencyField( bounds=[0, Constants.training_1_maximun_offered_points]) training_question_1_other_payoff = models.CurrencyField( bounds=[0, Constants.training_1_maximun_offered_points]) decision = models.CharField(choices=['Stag', 'Hare'], doc="""The player's choice""", widget=widgets.RadioSelect()) def is_training_question_1_my_payoff_correct(self): return (self.training_question_1_my_payoff == Constants.training_question_1_my_payoff_correct) def is_training_question_1_other_payoff_correct(self): return (self.training_question_1_other_payoff == Constants.training_question_1_other_payoff_correct) def other_player(self): """Returns other player in group""" return self.get_others_in_group()[0] def set_payoff(self): payoff_matrix = { 'Stag': { 'Stag': Constants.stag_stag_amount, 'Hare': Constants.stag_hare_amount, }, 'Hare': { 'Stag': Constants.hare_stag_amount, 'Hare': Constants.hare_hare_amount, } } self.payoff = payoff_matrix[self.decision][ self.other_player().decision]
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> is_winner = models.BooleanField(default=False, doc=""" True if player had the winning guess """) guess_value = models.PositiveIntegerField(default=None, doc=""" Each player guess: between 0-100 """) def guess_value_choices(self): return range(0, 101)
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_answer_x = models.PositiveIntegerField( null=True, verbose_name='Participant A would have') training_answer_y = models.PositiveIntegerField( null=True, verbose_name='Participant B would have') points = models.PositiveIntegerField() feedback = models.PositiveIntegerField( choices=((5, 'Very well'), (4, 'Well'), (3, 'OK'), (2, 'Badly'), (1, 'Very badly')), widget=widgets.RadioSelectHorizontal(), verbose_name='') def role(self): return {1: 'A', 2: 'B'}[self.id_in_group]
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> request_amount = models.MoneyField(default=None, doc=""" Amount requested by this player. """) def request_amount_choices(self): """Range of allowed request amount""" return money_range(0, self.subsession.amount_shared, 0.05) def other_player(self): """Returns the opponent of the current player""" return self.other_players_in_group()[0]
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_question_1 = models.CurrencyField() def is_training_question_1_correct(self): return self.training_question_1 == Constants.training_1_correct units = models.PositiveIntegerField(initial=None, min=0, max=Constants.max_units_per_player, doc="""Quantity of units to produce""") def other_player(self): return self.get_others_in_group()[0]
class Player(otree.models.BasePlayer): # <built-in> subsession = models.ForeignKey(Subsession) group = models.ForeignKey(Group, null = True) # </built-in> # initial shares and cash cash = models.MoneyField(default=20) shares = models.PositiveIntegerField(default=5) # order fields order_type = models.CharField(max_length=10, choices=['Buy Order', 'Sell Order', 'None'], widget=widgets.RadioSelect()) bp = models.MoneyField(default=0.00, doc="""maximum buying price per share""") bn = models.PositiveIntegerField(default=0, doc="""number of shares willing to buy""") sp = models.MoneyField(default=0.00, doc="""minimum selling price per share""") sn = models.PositiveIntegerField(default=0, doc="""number of shares willing to sell.""") def other_player(self): """Returns other player in group. Only valid for 2-player groupes.""" return self.other_players_in_group()[0] QUESTION_1_CHOICES = ['P=3, N=2','P=2, N=3','P=2.5, N=3','P=2.5, N=2','No transaction will take place',] QUESTION_2_CHOICES = ['$8, $12', '$12, $8', '$8, $8', '$12, $12', '$10, $10'] understanding_question_1 = models.CharField(max_length=100, null=True, choices=QUESTION_1_CHOICES, verbose_name='', widget=widgets.RadioSelect()) understanding_question_2 = models.CharField(max_length=100, null=True, choices=QUESTION_2_CHOICES, verbose_name='', widget=widgets.RadioSelect()) # check correct answers def is_understanding_question_1_correct(self): return self.understanding_question_1 == self.subsession.understanding_1_correct def is_understanding_question_2_correct(self): return self.understanding_question_2 == self.subsession.understanding_2_correct def my_field_error_message(self, value): if not 0 <= value <= 10: return 'Value is not in allowed range' def role(self): # you can make this depend of self.id_in_group return ''
class BasePlayer(SaveTheChange, models.Model): """ Base class for all players. """ class Meta: abstract = True index_together = ['participant', 'round_number'] ordering = ['pk'] _index_in_game_pages = models.PositiveIntegerField( default=0, doc='Index in the list of pages views_module.page_sequence') session = models.ForeignKey(Session, related_name='%(app_label)s_%(class)s') round_number = models.PositiveIntegerField(db_index=True) # it's _name instead of name because people might define # their own name field def _name(self): return self.participant.__unicode__() def role(self): # you can make this depend of self.id_in_group return '' def in_round(self, round_number): return type(self).objects.get(participant=self.participant, round_number=round_number) def in_rounds(self, first, last): qs = type(self).objects.filter( participant=self.participant, round_number__gte=first, round_number__lte=last, ).order_by('round_number') return list(qs) def in_previous_rounds(self): return self.in_rounds(1, self.round_number - 1) def in_all_rounds(self): return self.in_previous_rounds() + [self] def __unicode__(self): return self._name() def _GroupClass(self): return self._meta.get_field('group').rel.to @property def _Constants(self): return get_models_module(self._meta.app_config.name).Constants
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> # training training_buyer_earnings = models.CurrencyField( verbose_name="Buyer's period payoff would be") training_seller1_earnings = models.CurrencyField( verbose_name="Seller 1's period payoff would be") training_seller2_earnings = models.CurrencyField( verbose_name="Seller 2's period payoff would be") # seller price = models.CurrencyField( min=0, max=Constants.INITIAL, verbose_name='Please indicate a price (from 0 to %i) you want to sell' % Constants.INITIAL) quality = models.CurrencyField(choices=[ (30, 'High'), (20, 'Medium'), (10, 'Low')], verbose_name='Please select a quality grade you want to produce', widget=widgets.RadioSelectHorizontal()) # buyer choice = models.PositiveIntegerField( choices=[(i, 'Buy from seller %i' % i) for i in range(1, Constants.players_per_group)] + [(0, 'Buy nothing')], blank=True, widget=widgets.RadioSelect(), verbose_name='And you will') # seller index def role(self): if self.id_in_group == 1: return 'buyer' return 'seller %i' % (self.id_in_group - 1)
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> # randomly assigned above in subsession team = models.PositiveIntegerField() # a team name to display to the user def team_name(self): if self.team == 1: return 'Alpha' else: return 'Beta' # randomly assigned above in subsession role = models.PositiveIntegerField() # a role name to display to the user def role_name(self): if self.role == 1: return 'Leader' else: return 'Advisor' # Bargain 1 advice and final offer advice_1 = models.PositiveIntegerField( choices=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100], initial=None, blank=True) offer_1 = models.PositiveIntegerField( choices=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100], initial=None, blank=True) offer_1_retry_1 = models.PositiveIntegerField( choices=[10, 20, 30, 40, 50, 60, 70, 80, 90, 100], initial=None, blank=True)
class Player(otree.models.BasePlayer): # <built-in> group = models.ForeignKey(Group, null=True) subsession = models.ForeignKey(Subsession) # </built-in> training_my_profit = models.CurrencyField( verbose_name='My profit would be') price = models.CurrencyField( min=0, max=Constants.maximum_price, doc="""Price player chooses to sell product for""") quality = models.CurrencyField( min=0, max=Constants.maximum_price, doc="""Price player chooses to produce with quality equal to""") share = models.FloatField(min=0, max=1)
class Group(otree.models.BaseGroup): # <built-in> subsession = models.ForeignKey(Subsession) # </built-in> group_type = models.CharField(max_length=20, choices=[Constants.gadd, Constants.gmul]) subgroup_type = models.IntegerField( choices=[Constants.sg1, Constants.sg2, Constants.sg3, Constants.sg4])
class Player(otree.models.BasePlayer): # <built-in> subsession = models.ForeignKey(Subsession) group = models.ForeignKey(Group, null=True) # </built-in> def other_player(self): """Returns other player in group. Only valid for 2-player groups.""" return self.get_others_in_group()[0] from_other_player = models.PositiveIntegerField() is_winner = models.BooleanField(initial=False) in_all_groups_wait_page = models.FloatField(initial=0) group_id_before_p1_switch = models.PositiveIntegerField() def role(self): # you can make this depend of self.id_in_group return ''