from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range ) import random import numpy as np doc = """ Аукцион по второй цене """ class Constants(BaseConstants): name_in_url = 'auction_max2' players_per_group = 2 # здесь может быть любое количество игроков, чтобы играли все в одной группе данной переменной надо присвоить None num_rounds = 5 instructions_template = 'auction_max2/instructions.html' TotalResult_template = 'auction_max2/AdminReport.html' # """Amount allocated to each player""" endowment = 100 multiplier = 2 class Subsession(BaseSubsession): def get_active_players(self): return [p for p in self.get_players() if p.is_alive()] def do_my_shuffle(self): newlist = [p for p in self.get_players() if p.is_alive()] leftlist = [p for p in self.get_players() if not p.is_alive()] pcount = len(newlist) num_to_add = Constants.players_per_group - pcount % Constants.players_per_group if num_to_add < Constants.players_per_group: newlist += leftlist[:num_to_add] leftlist = leftlist[num_to_add:] pcount = len(newlist) nums = random.SystemRandom().sample(range(pcount), pcount) shufflelist = [newlist[i] for i in nums]+leftlist gr_matrix = [shufflelist[i:i+Constants.players_per_group] for i in range(0, len(shufflelist), Constants.players_per_group)] self.set_group_matrix(gr_matrix) def vars_for_admin_report(self): subs_avg = [] for subs in self.in_all_rounds(): pl_bid = sum(p.bid for p in subs.get_players())/len(subs.get_players()) #pl_coop_num = sum(p.decision == "Cooperate" for p in subs.get_players()) #pl_defect_num = sum(p.decision == "Defect" for p in subs.get_players()) #subs_avg.append(round(100*pl_coop_num/(pl_coop_num+pl_defect_num),1) if pl_coop_num+pl_defect_num>0 else float('nan')) subs_avg.append(round(pl_bid,1)) series = [] for player in self.get_players(): pl_id = player.participant.id_in_session name = player.participant.label pl_totalpay = sum(p.float_payoff for p in player.in_all_rounds()) pl_bid = sum(p.bid for p in player.in_all_rounds())/len(player.in_all_rounds()) pl_item_value = sum(p.item_value for p in player.in_all_rounds())/len(player.in_all_rounds()) series.append(dict ( ID = pl_id, Name = name, TotalPay = round(pl_totalpay,2), Bid = round(pl_bid,2), Item_value = round(pl_item_value,2))) cnt = len(series) if cnt>0: av = dict (ID = 0, Name = 'AVG', TotalPay = round(sum(s['TotalPay'] for s in series)/cnt,0), Bid = round(sum(s['Bid'] for s in series)/cnt,1), Item_value = round(sum(s['Item_value'] for s in series)/cnt,1)) series.insert(0, av) return dict( game_data=series, period_data = subs_avg, round_numbers=list(range(1, len(subs_avg) + 1))) class Group(BaseGroup): max_bid = models.FloatField(default=0) max2_bid = models.FloatField(default=0) def set_winner(self): players = self.get_players() self.max_bid = max([p.bid for p in players]) players_with_highest_bid = [p for p in players if p.bid == self.max_bid] winner = random.choice( players_with_highest_bid) # if tie, winner is chosen at random winner.is_winner = True def max2(self): players = self.get_players() x = np.array([p.bid for p in players], np.float32) vals, counts = np.unique(x, return_counts=True) self.max2_bid = vals[-2] if len(vals) > 1 else self.max_bid return self.max2_bid class Player(BasePlayer): item_value = models.FloatField(initial=None) bid = models.FloatField( min=0, max=Constants.endowment, doc="""The amount contributed by the player""", default=0 ) is_winner = models.BooleanField( initial=False, doc="""Indicates whether the player is the winner""" ) float_payoff = models.FloatField( min=0) def bid_max(self): return self.item_value def fx(self): if self.item_value == None: self.item_value = random.randint(0, Constants.endowment*100)/100 return self.item_value def is_alive(self): return not ((self.participant.label is None) or (self.participant.label == "")) def set_payoff(self): if self.is_winner: self.payoff = self.item_value - self.group.max2() else: self.payoff = 0 def f_payoff(self): if self.is_winner: self.float_payoff = self.item_value - self.group.max2() else: self.float_payoff = 0