from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) doc = """ Financial simulation for the gas station
Players set a price, and the lowest price makes the sale or in the case of a tie splits the profits
""" class Constants(BaseConstants): name_in_url = 'prisoners_dilemma' players_per_group = 2 num_rounds = 100 instructions_template = 'prisoners_dilemma/instructions.html' class Subsession(BaseSubsession): def creating_session(self): for g in self.get_groups(): g.num_customers = 1000 def get_sorted_players_by_opponent(self): result = [] players = self.get_players() seen = set() for player in players: if player.participant.id_in_session in seen: continue opponent = player.get_others_in_group()[0] result.append(player) result.append(opponent) seen.add(player.participant.id_in_session) seen.add(opponent.participant.id_in_session) return result def get_all_moves(self): bids = [] #2D array with one array of all bids per round payoffs = [] for player in self.get_sorted_players_by_opponent(): for round in range(self.session.config['rounds']): if len(bids) <= round: bids.append([player.participant.vars['bids'][round]]) payoffs.append([player.participant.vars['payoffs'][round]]) else: bids[round].append(player.participant.vars['bids'][round]) payoffs[round].append(player.participant.vars['payoffs'][round]) return dict(bids=bids, payoffs=payoffs) def vars_for_admin_report(self): participants = [] payoffs = [] bids = [] for player in self.get_sorted_players_by_opponent(): participant = {'name': '', 'payoffs': [], 'bids': [], 'accumulated_payoffs': [], 'opponent': '', 'opponent_bids': [], 'opponent_payoffs': []} if 'name' in player.participant.vars: participant['name'] = player.participant.vars['name'] if 'payoffs' in player.participant.vars: participant['payoffs'] = player.participant.vars['payoffs'] if 'bids' in player.participant.vars: participant['bids'] = player.participant.vars['bids'] if 'accumulated_payoffs' in player.participant.vars: participant['accumulated_payoffs'] = player.participant.vars['accumulated_payoffs'] try: participant['opponent'] = player.get_others_in_group()[0].participant.vars['name'] participant['opponent_bids'] = player.get_others_in_group()[0].participant.vars['bids'] participant['opponent_payoffs'] = player.get_others_in_group()[0].participant.vars['payoffs'] except: pass participants.append(participant) if ('payoffs' in player.participant.vars and self.round_number <= len(player.participant.vars['payoffs'])): payoffs.append(player.participant.vars['payoffs'][player.round_number - 1]) if ('bids' in player.participant.vars and self.round_number <= len(player.participant.vars['bids'])): bids.append(player.participant.vars['bids'][player.round_number - 1]) return dict(participants=participants, payoffs=payoffs, round_number=self.round_number, bids=bids) class Group(BaseGroup): num_customers = models.IntegerField( doc="""Number of cars""", ) def set_payoffs(self): for p in self.get_players(): p.set_payoff() class Player(BasePlayer): bid_amount = models.CurrencyField( min=0, doc="""Price set by the player""", ) opponent = models.CurrencyField( min=0, doc="""Price set by the player's opponent""", ) is_winner = models.BooleanField( initial=False, doc="""Indicates whether the player is the winner""" ) is_tie = models.BooleanField( initial=False, doc="""Indicates whether there was a tie""" ) def other_player(self): return self.get_others_in_group()[0] def set_payoff_for_gas_station_game(self): opponent = self.other_player().bid_amount if self.bid_amount < opponent and self.bid_amount < self.session.config['gas_station_max_price']: self.payoff = (self.bid_amount - self.session.config['gas_station_wholesale_price']) * self.group.num_customers * 10 self.is_winner = True elif self.bid_amount == opponent and self.bid_amount < self.session.config['gas_station_max_price']: self.payoff = (self.bid_amount - self.session.config['gas_station_wholesale_price']) * self.group.num_customers * 10 / 2 self.is_tie = True else: self.payoff = 0 if self.payoff < 0: self.payoff = 0 def set_payoff_for_dealership_game(self): from random import randint if (randint(0, 100) < 50) and self.session.config['dealership_50_percent_chance_of_no_payoff']: self.payoff = 0 return opponent = self.other_player().bid_amount if self.bid_amount < opponent and self.bid_amount < self.session.config['dealership_max_price']: self.payoff = (self.bid_amount - self.session.config['dealership_car_price']) self.is_winner = True elif self.bid_amount == opponent and self.bid_amount < self.session.config['dealership_max_price']: self.payoff = (self.bid_amount - self.session.config['dealership_car_price']) / 2 self.is_tie = True else: self.payoff = 0 if self.payoff < 0: self.payoff = 0 def set_payoff(self): # Compute payoff for chosen game game_name = self.session.config['game_name'] if game_name == "gas_station": self.set_payoff_for_gas_station_game() elif game_name == "dealership": print(f"Before: {self.payoff}") self.set_payoff_for_dealership_game() print(f"After: {self.payoff}") # Save bid amount if 'bids' in self.participant.vars: self.participant.vars['bids'].append(self.bid_amount) else: self.participant.vars['bids'] = [self.bid_amount] # Save opponent bid amount if 'opponent_bids' in self.participant.vars: self.participant.vars['opponent_bids'].append(self.other_player().bid_amount) else: self.participant.vars['opponent_bids'] = [self.other_player().bid_amount] # Save payoff value if 'payoffs' in self.participant.vars: self.participant.vars['payoffs'].append(self.payoff) else: self.participant.vars['payoffs'] = [self.payoff] # Updated accumulated payoff earnings if 'accumulated_payoffs' in self.participant.vars: new_payoff = self.participant.vars['accumulated_payoffs'][-1] + self.payoff self.participant.vars['accumulated_payoffs'].append(new_payoff) else: self.participant.vars['accumulated_payoffs'] = [self.payoff]