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]