#1 by Rita (edited )
Hello everyone, I am conducting a trading experiment. The experiment assumes that there are 20 participants, 10 sellers, and 10 buyers. Sellers bid on products and buyers decide whether to purchase. In this experiment, I named sellers Seller 1, Seller 2..., Seller 10, and buyers Buyer 1, Buyer 2, Buyer 3..., Buyer 10. During the experiment, Seller 1 and Buyer 1 are grouped together, while Seller 2 and Buyer 2 are grouped together. In addition, if the buyer chooses to purchase this product during the experiment, then this buyer and their corresponding seller will not enter the next round of transactions. If the buyer chooses not to purchase this product, they can choose whether to enter the next round, and if they choose to enter the next round of transactions, they will be reassigned to a new seller (who also did not sell anything). How should I rewrite my code? Here is my current code.
If someone helps me, I would be very grateful.
from otree.api import *
class Constants(BaseConstants):
name_in_url = 'trading_experiment'
players_per_group = 2
num_rounds = 10
num_groups = 10
SELLER_ROLE = '卖家'
BUYER_ROLE = '买家'
room_name = 'room1'
cost = 10
quality_average = 65
class Subsession(BaseSubsession):
pass
def creating_session(subsession: Subsession):
players = [p for p in subsession.get_players() if p.active] # 仅包括活跃的玩家
n_players = len(players)
offset = subsession.round_number - 1 # 每一轮增加的偏移量
new_structure = make_matrix(n_players, offset)
subsession.set_group_matrix(new_structure)
for i, player in enumerate(players, start=1):
if i <= 3:
player.role_name = f'卖家{i}'
else:
player.role_name = f'买家{i - 10}'
print(f"Round {subsession.round_number} group matrix: {subsession.get_group_matrix()}")
for player in players:
print(f"Player {player.id_in_subsession}: {player.role_name}")
def make_matrix(n_players, offset):
p1s = list(range(1, n_players // 2 + 1))
p2s = list(range(n_players // 2 + 1, n_players + 1))
# Rotate p2s by the offset
return list(zip(p1s, p2s[offset:] + p2s[:offset]))
class Group(BaseGroup):
seller_decision_quality = models.IntegerField()
seller_decision_price = models.CurrencyField()
class Player(BasePlayer):
role_name = models.StringField()
quality = models.IntegerField(
label="商品的品质:",
min=60, max=70
)
price = models.CurrencyField(
label="商品的价格:",
min=0
)
quality_buyer = models.IntegerField(
label="买家实际收到商品的品质:",
min=-10, max=10
)
purchase_decision = models.BooleanField(
label="你是否购买这个商品?",
choices=[
[True, '购买'],
[False, '不购买']
],
widget=widgets.RadioSelect
)
active = models.BooleanField(initial=True) # 标记玩家是否在下一轮中参与
class Introduction(Page):
@staticmethod
def vars_for_template(player: Player):
group = player.group
seller = group.get_player_by_role(Constants.SELLER_ROLE)
buyer = group.get_player_by_role(Constants.BUYER_ROLE)
return {
'player_role_name': player.role_name,
'seller_role_name': seller.role_name if seller else 'N/A',
'buyer_role_name': buyer.role_name if buyer else 'N/A',
}
class SellerDecision(Page):
form_model = 'player'
form_fields = ['quality', 'price']
@staticmethod
def is_displayed(player):
return player.role == Constants.SELLER_ROLE
@staticmethod
def before_next_page(player: Player, timeout_happened):
group = player.group
group.seller_decision_quality = player.quality
group.seller_decision_price = player.price
class SellerWaitPage(WaitPage):
@staticmethod
def is_displayed(player):
return player.role == Constants.BUYER_ROLE
@staticmethod
def after_all_players_arrive(group: Group):
pass
class BuyerView(Page):
@staticmethod
def is_displayed(player):
return player.role == Constants.BUYER_ROLE and player.active
@staticmethod
def vars_for_template(player: Player):
current_group = player.group
all_rounds_data = []
if player.round_number > 1:
for previous_round in player.in_previous_rounds():
previous_round_group = previous_round.group
previous_round_player = previous_round
if previous_round_player.role == Constants.BUYER_ROLE:
previous_round_buyer = previous_round_player
previous_round_seller = previous_round_group.get_player_by_role(Constants.SELLER_ROLE)
else:
previous_round_buyer = previous_round_group.get_player_by_role(Constants.BUYER_ROLE)
previous_round_seller = previous_round_player
round_data = {
'round_number': previous_round.round_number,
'seller_quality': previous_round_group.seller_decision_quality,
'seller_price': previous_round_group.seller_decision_price,
'buyer_decision': '是' if previous_round_buyer.purchase_decision else '否',
'quality_buyer': previous_round_buyer.quality_buyer if previous_round_buyer.purchase_decision else '无',
}
all_rounds_data.append(round_data)
current_round_data = {
'quality': current_group.seller_decision_quality,
'price': current_group.seller_decision_price
}
return {
'quality': current_round_data['quality'],
'price': current_round_data['price'],
'all_rounds_data': all_rounds_data
}
class BuyerDecision(Page):
form_model = 'player'
form_fields = ['purchase_decision']
@staticmethod
def is_displayed(player):
return player.role == Constants.BUYER_ROLE and player.active
@staticmethod
def vars_for_template(player: Player):
group = player.group
return {
'quality': group.seller_decision_quality,
'price': group.seller_decision_price,
}
@staticmethod
def before_next_page(player: Player, timeout_happened):
if player.purchase_decision:
player.active = False
player.get_others_in_group()[0].active = False
class BuyerQuality(Page):
form_model = 'player'
form_fields = ['quality_buyer']
@staticmethod
def is_displayed(player: Player):
return player.role == Constants.BUYER_ROLE and player.purchase_decision
@staticmethod
def vars_for_template(player: Player):
group = player.group
return {
'seller_quality': group.seller_decision_quality,
'seller_price': group.seller_decision_price,
'player': player
}
class ResultsWaitPage(WaitPage):
def after_all_players_arrive(self):
pass
class SellerResults(Page):
@staticmethod
def is_displayed(player):
return player.role == Constants.SELLER_ROLE
@staticmethod
def vars_for_template(player: Player):
group = player.group
buyer = group.get_player_by_role(Constants.BUYER_ROLE)
return {
'quality': group.seller_decision_quality,
'price': group.seller_decision_price,
'buyer_decision': '是' if buyer.purchase_decision else '否',
'quality_buyer': buyer.quality_buyer if buyer.purchase_decision else '无'
}
class Results(Page):
@staticmethod
def vars_for_template(player: Player):
group = player.group
buyer = group.get_player_by_role(Constants.BUYER_ROLE)
seller = group.get_player_by_role(Constants.SELLER_ROLE)
if buyer.purchase_decision:
buyer_benefit = group.seller_decision_quality + buyer.quality_buyer - group.seller_decision_price
seller_benefit = group.seller_decision_price - Constants.cost
else:
buyer_benefit = 0
seller_benefit = 0
if player.round_number == 1:
all_rounds_data = [{
'round_number': player.round_number,
'seller_quality': group.seller_decision_quality,
'seller_price': group.seller_decision_price,
'buyer_decision': '是' if buyer.purchase_decision else '否',
'quality_buyer': buyer.quality_buyer if buyer.purchase_decision else '无',
}]
else:
all_rounds_data = []
for previous_round in player.in_all_rounds():
previous_round_group = previous_round.group
previous_round_buyer = previous_round_group.get_player_by_role(Constants.BUYER_ROLE)
previous_round_seller = previous_round_group.get_player_by_role(Constants.SELLER_ROLE)
round_data = {
'round_number': previous_round.round_number,
'seller_quality': previous_round_group.seller_decision_quality,
'seller_price': previous_round_group.seller_decision_price,
'buyer_decision': '是' if previous_round_buyer.purchase_decision else '否',
'quality_buyer': previous_round_buyer.quality_buyer if previous_round_buyer.purchase_decision else '无',
}
all_rounds_data.append(round_data)
return {
'seller_quality': group.seller_decision_quality,
'seller_price': group.seller_decision_price,
'buyer_decision': '是' if buyer.purchase_decision else '否',
'quality_buyer': buyer.quality_buyer if buyer.purchase_decision else '无',
'buyer_benefit': buyer_benefit,
'seller_benefit': seller_benefit,
'all_rounds_data': all_rounds_data
}
class GroupRearrangeWaitPage(WaitPage):
wait_for_all_groups = True
@staticmethod
def after_all_players_arrive(subsession: Subsession):
creating_session(subsession)
page_sequence = [
Introduction,
SellerDecision,
SellerWaitPage,
BuyerView,
BuyerDecision,
BuyerQuality,
ResultsWaitPage,
SellerResults,
Results,
GroupRearrangeWaitPage
]