from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) from django.conf import settings author = 'HRM - uketr' doc = """ Designed after GiftExchange zTree program. This is a fix for the web site names. Participants of the experiment will be divided into groups of two. In each group there is a leader (Arbeitgeber) and a worker (Arbeitnehmer). The leader suggests a payment (salary offer, Gehaltsangebot) to the worker. He then decides if he wants to reject (Ablehnen) or accept (Annehmen) the offer. If he accepts he must choose a workload (Arbeitslesitung). The payments are calculated accordingly. """, class Constants(BaseConstants): name_in_url = 'giftExchangeFinal' # Change the players group. players_per_group = 2 # How often / rounds is played, i.e. periods. !!!!!!!!! hier nur eine liste der conf 0 erster eintrag num_rounds = 8 # settings.SESSION_CONFIGS[0].get('num_rounds') # settings.__sizeof__() # settings.configured # settings.configure(8) # settings.SESSION_CONFIGS[0].get('num_rounds') # Get index of giftExchangeFinal in the settings list giftExchange_index = next( (index for (index, d) in enumerate(settings.SESSION_CONFIGS) if d["name"] == "giftExchangeFinal"), None) # Endowment of the leader. Now in Subsession, configurable. # endowment = c(120) # min and max offer which the leader gives. min_salary = c(20) max_salary = c(120) # If the worker rejects the offer, these are the payments. reject_leader_pay = c(0) reject_worker_pay = c(0) # Costs for workload. COSTS_FOR_WORKLOAD = { None: 0, 1: 0, 2: 1, 3: 2, 4: 4, 5: 6, 6: 8, 7: 10, 8: 12, 9: 15, 10: 18 } # Travel costs for worker. travel_cost = c(20) def cost_for_workload(workload): return c(Constants.COSTS_FOR_WORKLOAD[workload]) class Subsession(BaseSubsession): pass class Group(BaseGroup): doc = """Here the group attributes are defined. offer_amount is the amount the leader offers the worker. worker_workload is the workload (Arbeitsleistung) which the worker selects if he accepts. offer_accepted is true if offer of the leader is accepted, flase if rejected. worker_costs is the representation of the cost for the worker given the workload. set_payoffs calculates the payoffs for leader and worker separate. if offer (Gehaltsangebot)accpeted: leader: payoff = (endowment - offer) * (workload / 10) worker: payoff = (offer - travel cost - cost for workload) payoff applies for the round. payoffSum for all rounds. payoffSum takes the payoffSum of the round before and adds it to the current payoff. Note that all group attributes are the same for both players. Leader will also have the attribute workload and so on """, offer_amount = models.CurrencyField(min=20, max=120) worker_workload = models.IntegerField( choices=range(1, 10+1), widget=widgets.RadioSelectHorizontal, blank=True # Change, the workload no longer has to be selected. # Problem: If accepted was selected and a workload too, but then rejected, the workload # which was selected before remains. ) worker_costs = models.CurrencyField() offer_accepted = models.BooleanField( widget=widgets.RadioSelect, choices=[ [True, 'Annehmen'], [False, 'Ablehnen'] ] ) def set_payoffs(self): leader = self.get_player_by_role('leader') worker = self.get_player_by_role('worker') if not self.offer_accepted: leader.payoff = Constants.reject_leader_pay worker.payoff = Constants.reject_worker_pay if self.round_number == 1: worker.payoffSum = worker.payoff leader.payoffSum = leader.payoff else: worker.payoffSum = (worker.in_round(self.round_number - 1).payoffSum + worker.payoff) leader.payoffSum = (leader.in_round(self.round_number - 1).payoffSum + leader.payoff) else: self.worker_costs = cost_for_workload(self.worker_workload) # hier falls wert eintragen wenn gewollt bei reject worker.payoff = self.offer_amount - Constants.travel_cost - self.worker_costs payoffControl = c(self.session.config['endowment']) - self.offer_amount print('Payoff leader 1 end - amount', c(self.session.config['endowment']) - self.offer_amount) print('Payoff leader 2 workload 10', self.worker_workload / 10) print('Payoff leader ', float(self.session.config['endowment'] - self.offer_amount) * (self.worker_workload / 10)) leader.payoff = c(float((self.session.config['endowment'] - self.offer_amount)) * self.worker_workload / 10) print('Var payoff leader', leader.payoff) if self.round_number == 1: worker.payoffSum = worker.payoff leader.payoffSum = leader.payoff else: worker.payoffSum = (worker.in_round(self.round_number - 1).payoffSum + worker.payoff) leader.payoffSum = (leader.in_round(self.round_number - 1).payoffSum + leader.payoff) # Ausprobiert: # worker.payoffSum = sum([worker.payoff for worker in self.player.in_all_rounds()]) # leader.payoffSum = leader.payoff class Player(BasePlayer): doc = """The player if the group id 1 is always the leader, the player with the group id 2 always worker. payoffSum is calculated accordingly for both players.""", payoffSum = models.CurrencyField() def role(self): if self.id_in_group == 1: return 'leader' if self.id_in_group == 2: return 'worker'