#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 ]