import random from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer ) doc = """ In Cournot competition, firms simultaneously decide the units of products to manufacture. The unit selling price depends on the total units produced. In this implementation, there are 2 firms competing for 1 period. """ class Constants(BaseConstants): name_in_url = 'eleven_twenty' players_per_group = 2 num_rounds = 4 instructions_template = 'eleven_twenty/instructions.html' TotalResult_template = 'eleven_twenty/AdminReport.html' # Total production capacity of all players total_capacity = 100 max_units_per_player = total_capacity expenses = 10 class Subsession(BaseSubsession): def do_my_shuffle(self): newlist = [p for p in self.get_players() if p.is_alive()] leftlist = [p for p in self.get_players() if not p.is_alive()] pcount = len(newlist) nums = random.sample(range(pcount), pcount) shufflelist = [newlist[i] for i in nums]+leftlist gr_matrix = [shufflelist[i:i+Constants.players_per_group] for i in range(0, len(shufflelist), Constants.players_per_group)] self.set_group_matrix(gr_matrix) for g in self.get_groups(): sk = sum(p.is_alive() for p in g.get_players()) < Constants.players_per_group for p in g.get_players(): p.skip_round = sk def vars_for_admin_report(self): series = [] for player in self.get_players(): pl_id = player.participant.id_in_session name = player.participant.label p_in_rounds = player.in_all_rounds() num_rounds = len(p_in_rounds) pl_totalpay = sum(p.payoff for p in p_in_rounds) d = dict(ID=pl_id, Name=name, TotalPay=pl_totalpay) for i in range(11, 21): s = sum((p.units == i) for p in p_in_rounds) num_rounds = sum(p.is_played() for p in p_in_rounds) if (num_rounds < 1): num_rounds = 1 d['C{}'.format(i)] = round(100 * s / num_rounds, 1) series.append(d) cnt = len(series) if cnt > 0: d = dict(ID=0, Name='AVG') d['TotalPay'] = round(sum(s['TotalPay'] for s in series) / cnt, 0) for i in range(11, 21): ind = 'C{}'.format(i) s = sum(s[ind] for s in series) d[ind] = round(s / cnt, 1) series.insert(0, d) return dict(game_data=series) class Group(BaseGroup): def set_payoffs(self): players = self.get_players() for p in players: p.payoff = p.units + 20 if sum([p.units for p in players]) == 2*p.units + 1 else p.units class Player(BasePlayer): units = models.IntegerField( widget=widgets.RadioSelect, choices=range(11, 21, 1), initial=0) def other_player(self): return self.get_others_in_group()[0] skip_round = models.BooleanField(initial=False) def is_alive(self): return not ((self.participant.label is None) or (self.participant.label == "")) def is_played(self): return (not self.skip_round) and self.is_alive()