-
Notifications
You must be signed in to change notification settings - Fork 1
/
models.py
118 lines (97 loc) · 4.44 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from otree.api import (
models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer,
Currency as c, currency_range
)
from django.db import models as djmodels
doc = """
This is a one-period public goods game with 3 players.
"""
class Constants(BaseConstants):
name_in_url = 'classroom_pgg'
players_per_group = 3
num_others_per_group = players_per_group - 1
num_rounds = 100
instructions_template = 'classroom_pgg/instructions.html'
# """Amount allocated to each player"""
endowment = c(100)
punishment_endowment = 10
punishment_factor = 3
from django.db.models import Q, F
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 dict(
avg_contribution=sum(contributions) / len(contributions),
min_contribution=min(contributions),
max_contribution=max(contributions)
)
else:
return dict(
avg_contribution='(no data)',
min_contribution='(no data)',
max_contribution='(no data)'
)
def creating_session(self):
ps = []
for p in self.get_players():
for o in p.get_others_in_group():
ps.append(Punishment(sender=p, receiver=o, ))
Punishment.objects.bulk_create(ps)
class Group(BaseGroup):
total_contribution = models.CurrencyField()
average_contribution = models.CurrencyField()
reached_threshold = models.CurrencyField()
total_share = models.CurrencyField()
individual_share = models.CurrencyField()
def set_pd_payoffs(self):
self.total_contribution = sum([p.contribution for p in self.get_players()])
self.average_contribution = self.total_contribution / self.session.config["players_per_group"]
self.reached_threshold = self.total_contribution >= self.session.config["threshold"]
if self.reached_threshold:
self.total_share = self.total_contribution * self.session.config["efficiency_factor"]
else:
self.total_share = 0
self.individual_share = self.total_share / self.session.config["players_per_group"]
for p in self.get_players():
p.pd_payoff = sum([+ Constants.endowment,
- p.contribution,
+ self.individual_share,
])
p.set_punishment_endowment()
def set_punishments(self):
if self.session.config["punishment"]:
for p in self.get_players():
p.set_punishment()
for p in self.get_players():
p.set_payoff()
class Player(BasePlayer):
contribution = models.CurrencyField(
min=0, max=Constants.endowment,
doc="""The amount contributed by the player""",
label="How much will you contribute to the project (from 0 to {})?".format(Constants.endowment)
)
punishment_sent = models.IntegerField()
punishment_received = models.IntegerField()
pd_payoff = models.CurrencyField(doc='to store payoff from contribution stage')
punishment_endowment = models.IntegerField(initial=0, doc='punishment endowment')
def set_payoff(self):
if not self.session.config["punishment"]:
self.punishment_received = 0
self.punishment_sent = 0
self.payoff = self.pd_payoff - self.punishment_sent - self.punishment_received
def set_punishment_endowment(self):
assert self.pd_payoff is not None, 'You have to set pd_payoff before setting punishment endowment'
self.punishment_endowment = min(int(self.pd_payoff), Constants.punishment_endowment)
def set_punishment(self):
if None in [i.amount for i in self.punishments_sent.all()]:
self.punishment_sent = 0
self.punishment_received = 0
else:
self.punishment_sent = sum([i.amount for i in self.punishments_sent.all()])
self.punishment_received = sum(
[i.amount for i in self.punishments_received.all()]) * self.session.config["punishment_factor"]
class Punishment(djmodels.Model):
sender = djmodels.ForeignKey(to=Player, related_name='punishments_sent', on_delete=djmodels.CASCADE)
receiver = djmodels.ForeignKey(to=Player, related_name='punishments_received', on_delete=djmodels.CASCADE)
amount = models.IntegerField(min=0)