from otree.api import * import time doc = """ Reach a consensus with your group before your payoffs shrink to 0. Similar to the "Endgame" segment of the British game show "Divided": https://www.youtube.com/watch?v=8k8ETko16tQ """ class Constants(BaseConstants): name_in_url = 'fast_consensus' players_per_group = 3 num_rounds = 1 ranks = [ dict(number=1, payoff=cu(800), label="Gold"), dict(number=2, payoff=cu(300), label="Silver"), dict(number=3, payoff=cu(100), label="Bronze"), ] timeout_seconds = 60 * 2 class Subsession(BaseSubsession): pass class Group(BaseGroup): deadline = models.FloatField() reached_consensus = models.BooleanField(initial=False) fraction_of_original = models.FloatField() def seconds_left(group: Group): return group.deadline - time.time() class Player(BasePlayer): proposed_rank = models.IntegerField() final_rank = models.IntegerField() rank_label = models.StringField() # PAGES class WaitToStart(WaitPage): @staticmethod def after_all_players_arrive(group: Group): group.deadline = time.time() + Constants.timeout_seconds class Negotiate(Page): @staticmethod def live_method(player: Player, data): group = player.group players = group.get_players() if group.reached_consensus: return {0: dict(finished=True)} if 'proposed_rank' in data: rank = data['proposed_rank'] player.proposed_rank = rank if set(p.field_maybe_none('proposed_rank') for p in players) == set( d['number'] for d in Constants.ranks ): payoffs = {d['number']: d['payoff'] for d in Constants.ranks} labels = {d['number']: d['label'] for d in Constants.ranks} fraction_of_original = round(seconds_left(group) / Constants.timeout_seconds, 4) group.fraction_of_original = fraction_of_original group.reached_consensus = True for p in players: p.final_rank = p.proposed_rank p.rank_label = labels[p.final_rank] p.payoff = payoffs[p.final_rank] * fraction_of_original return {0: dict(finished=True)} return { 0: dict(ranks=[[p.id_in_group, p.field_maybe_none('proposed_rank')] for p in players]) } @staticmethod def js_vars(player: Player): group = player.group return dict( my_id=player.id_in_group, deadline=group.deadline, RANKS=Constants.ranks, TIMEOUT_SECONDS=Constants.timeout_seconds, ) @staticmethod def get_timeout_seconds(player: Player): import time group = player.group return group.deadline - time.time() class ResultsWaitPage(WaitPage): pass class Results(Page): pass page_sequence = [WaitToStart, Negotiate, ResultsWaitPage, Results]