from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random author = 'Franziska Heinicke' doc = """ Bargaining with a nuclear option """ class Constants(BaseConstants): name_in_url = 'BaNu_base' players_per_group = 2 num_rounds = 11 paying_round = 2 endowmentsA = [[30, 50, 60, 50, 30, 40, 60, 60, 40, 60, 30], [30, 60, 40, 60, 60, 40, 30, 50, 60, 50, 30], [40, 60, 60, 40, 60, 30, 30, 50, 60, 50, 30], [30, 60, 30, 60, 40, 30, 50, 50, 40, 60, 60]] endowmentsB = [[30, 60, 30, 50, 60, 30, 40, 60, 60, 50, 40], [40, 50, 60, 60, 40, 30, 60, 50, 30, 60, 30], [30, 40, 60, 60, 50, 40, 30, 60, 30, 50, 60], [30, 30, 60, 40, 60, 40, 60, 50, 30, 60, 50]] matching_size = 2 max_waiting = 5 class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: for p in self.get_players(): if (p.id_in_group % 2) == 0: p.participant.vars['type'] = 'B' else: p.participant.vars['type'] = 'A' def group_by_arrival_time_method(self, waiting_players): from collections import defaultdict d = defaultdict(list) if self.round_number == 1: a_players = [p for p in waiting_players if p.participant.vars['type'] == 'A'] b_players = [p for p in waiting_players if p.participant.vars['type'] == 'B'] for p in a_players: if p.matching_group == 0: a_players_matching = [p.matching_group for p in self.get_players() if p.participant.vars['type'] == 'A'] max_a = max(a_players_matching) if max_a == 0: p.participant.vars['matching'] = 1 p.matching_group = p.participant.vars['matching'] else: a_current_match = [p for p in self.get_players() if p.matching_group == max_a and p.participant.vars['type'] == 'A'] if len(a_current_match) == Constants.matching_size: p.participant.vars['matching'] = max_a + 1 p.matching_group = p.participant.vars['matching'] else: p.participant.vars['matching'] = max_a p.matching_group = p.participant.vars['matching'] for p in b_players: b_players_matching = [p.matching_group for p in self.get_players() if p.participant.vars['type'] == 'B'] if p.matching_group == 0: max_b = max(b_players_matching) if max_b == 0: p.participant.vars['matching'] = 1 p.matching_group = p.participant.vars['matching'] else: b_current_match = [p for p in self.get_players() if p.matching_group == max_b and p.participant.vars['type'] == 'B'] if len(b_current_match) == Constants.matching_size: p.participant.vars['matching'] = max_b + 1 p.matching_group = p.participant.vars['matching'] else: p.participant.vars['matching'] = max_b p.matching_group = p.participant.vars['matching'] for p in waiting_players: if p.matching_group != 0: matching_number = p.participant.vars['matching'] players_in_this_matching = d[matching_number] players_in_this_matching.append(p) a_players_this_matching = [p for p in players_in_this_matching if p.participant.vars['type'] == 'A'] b_players_this_matching = [p for p in players_in_this_matching if p.participant.vars['type'] == 'B'] a_players_total = [p for p in self.get_players() if p.matching_group == matching_number and p.participant.vars['type'] == 'A'] b_players_total = [p for p in self.get_players() if p.matching_group == matching_number and p.participant.vars['type'] == 'B'] if len(a_players_this_matching) >= 1 and len(b_players_this_matching) >= 1 and len(a_players_total) == Constants.matching_size and len(b_players_total) == Constants.matching_size: return [a_players_this_matching[0], b_players_this_matching[0]] else: d = defaultdict(list) import time for p in waiting_players: if time.time() - p.participant.vars['wait_page_arrival'] > Constants.max_waiting * 60: p.active = False return [p] else: p.matching_group = p.participant.vars['matching'] matching_number = p.participant.vars['matching'] players_in_this_matching = d[matching_number] players_in_this_matching.append(p) a_players = [p for p in players_in_this_matching if p.participant.vars['type'] == 'A'] b_players = [p for p in players_in_this_matching if p.participant.vars['type'] == 'B'] if len(a_players) >= 1 and len(b_players) >= 1 and a_players[0].in_round(self.round_number-1).group.id_in_subsession != b_players[0].in_round(self.round_number-1).group.id_in_subsession: return [a_players[0], b_players[0]] else: random.shuffle(b_players) #if len(a_players) >= 1 and len(b_players) >= 1: #print('about to create a group') #return [a_players[0], b_players[0]] #print('not enough players to create a group') class Group(BaseGroup): endowA = models.IntegerField() endowB = models.IntegerField() currentA = models.IntegerField(initial=100) historyA = models.CharField(initial="") currentB = models.IntegerField(initial=100) historyB = models.CharField(initial="") nuclear = models.BooleanField() #firstpage_done = models.BooleanField(initial=False) final_offer = models.IntegerField(initial=0) time_final = models.CharField() failed = models.BooleanField(initial=False) def set_payoffs(self): playerA = self.get_player_by_role('A') playerB = self.get_player_by_role('B') if Constants.paying_round == self.round_number: if not self.failed: playerA.payoff = self.final_offer playerB.payoff = 100-self.final_offer if self.failed and self.nuclear: playerA.payoff = 0 playerB.payoff = 9 if self.failed and not self.nuclear: playerA.payoff = self.endowA playerB.payoff = 100 - self.endowB else: playerA.payoff = 0 playerB.payoff = 0 class Player(BasePlayer): matching_group = models.IntegerField(initial=0) active = models.BooleanField(initial=True) def role(self): if self.participant.vars['type'] == 'A': return 'A' else: return 'B'