from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency ) from django.forms.widgets import NumberInput from random import randint author = 'Tommaso Batistoni - t.batistoni@ucl.ac.uk' doc = """ a.k.a. Keynesian beauty contest. Players all guess a number; whoever guesses closest to 2/3 of the average wins. See https://en.wikipedia.org/wiki/Guess_2/3_of_the_average """ class Constants(BaseConstants): players_per_group = None num_rounds = 4 name_in_url = 'taskgss' group_size = 4 max_seconds_waiting_for_partners = 1000 * 20 * 1 treatments = ['2/3', '1/2', '1/3'] jackpot = 6 guess_max = 100 seconds_for_summary = 60 class Subsession(BaseSubsession): pass class Group(BaseGroup): avg = models.FloatField() two_thirds_avg = models.FloatField() best_guess = models.FloatField() num_winners = models.IntegerField() def set_payoffs(self): players = self.get_players() if self.get_players()[0].participant.vars.get('unmatched'): guesses = [randint(0, 100) for _ in range(Constants.group_size-1)] else: guesses = [p.guess for p in players] treatment = players[0].participant.vars['guessing_treatment'] multiplier = int(treatment.split('/')[0]) / int(treatment.split('/')[1]) avg = sum(guesses) / Constants.group_size self.avg = round(avg, 1) two_thirds_avg = multiplier * avg self.two_thirds_avg = round(two_thirds_avg, 1) self.best_guess = min(guesses, key=lambda guess: abs(guess - self.two_thirds_avg)) if self.get_players()[0].participant.vars.get('unmatched'): if self.get_players()[0] == self.best_guess: self.get_players()[0].is_winner = True else: winners = [p for p in players if p.guess == self.best_guess] self.num_winners = len(winners) for p in winners: p.is_winner = True p.payoff = round(Constants.jackpot / self.num_winners, 2) def two_thirds_avg_history(self): return ', '.join(map(str, [g.two_thirds_avg for g in self.in_previous_rounds()])) class Player(BasePlayer): treatment = models.StringField() guess = models.FloatField(min=0, max=Constants.guess_max, widget=NumberInput(attrs={'step': 0.1})) is_winner = models.BooleanField(initial=False) timeout = models.BooleanField()