from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) author = 'Your name here' doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'boston' players_per_group = 4 num_rounds = 8 outside_option = 0 # ∅ school_type = [1, 2, 3, 4] student_type = ['A', 'B', 'C', 'D'] school_id_label = [[1, 1], [2, 2], [3, 3], [4, 4], [0, '∅']] # 初期値がNoneなのでNoneの選択肢を作ると、そこが選択された状態になってしまう student_preference = {'A': [3, 4, 2, 1], 'B': [3, 4, 2, 1], 'C': [3, 4, 2, 1], 'D': [3, 4, 2, 1]} school_priority = {1: ['A', 'B', 'C', 'D'], 2: ['A', 'B', 'C', 'D'], 3: ['A', 'B', 'C', 'D'], 4: ['A', 'B', 'C', 'D']} class Subsession(BaseSubsession): def creating_session(self): print('creating session!') players = self.get_players() for p in players: p.set_type() class Group(BaseGroup): def boston(self): print('boston algorithm') preferences = [[0] * 5] * 4 players_in_group = self.get_players() for p in players_in_group: preferences[p.id_in_group - 1] = [p.sub1, p.sub2, p.sub3, p.sub4, p.sub5] flag = False for i, sc_id in enumerate(preferences[p.id_in_group - 1]): if (sc_id is 0) or (sc_id is None): flag = True if flag: preferences[p.id_in_group - 1][i] = 0 print(preferences) school_matching_partner = [0, 0, 0, 0] for step in range(5): # 0,1,2,3,4 print('step: ', step) for school_id in Constants.school_type: # [1, 2, 3, 4] school_index = school_id-1 # [0, 1, 2, 3] if school_matching_partner[school_index] is not 0: # 定員埋まっているので continue # まだ空いているので、同じstepでschool_idへapplyしている人たちで取り合い tmp_priority = 100 for student in players_in_group: student_id = student.id_in_group student_index = student_id-1 student_priority = Constants.school_priority[school_id].index(student.type) if (preferences[student_index][step] is school_id) \ and (student_priority < tmp_priority): school_matching_partner[school_index] = student_id tmp_priority = student_priority if tmp_priority is not 100: players_in_group.remove(self.get_player_by_id(school_matching_partner[school_index])) # matching が決定 for school_index, student_id in enumerate(school_matching_partner): if student_id is 0: continue student = self.get_player_by_id(student_id) student.matching_partner = school_index + 1 def da(self): print('DA algorithm') preferences = [[0] * 5] * 4 players_in_group = self.get_players() for p in players_in_group: preferences[p.id_in_group - 1] = [p.sub1, p.sub2, p.sub3, p.sub4, p.sub5] print(preferences) school_tmp_matching_partner = [0, 0, 0, 0] while len(players_in_group) > 0: student = players_in_group.pop() for school_id in preferences[student.id_in_group - 1]: print('school_id', school_id) if school_id is 0 or school_id is None: # outside option student.matching_partner = 0 print('outside option') break school_index = school_id - 1 rival_id = school_tmp_matching_partner[school_index] if rival_id != 0: student_rival = self.get_player_by_id(rival_id) if Constants.school_priority[school_id].index(student.type) \ < Constants.school_priority[school_id].index(student_rival.type): print(school_id, student.id_in_group, '新たな生徒のほうが好き') student.matching_partner = school_id school_tmp_matching_partner[school_index] = student.id_in_group players_in_group.append(student_rival) break else: # 保持している生徒のほうが好き print('変更無しで次へ') else: print(school_id, student.id_in_group, 'マッチしている生徒がいないので、仮マッチさせて終了') school_tmp_matching_partner[school_index] = student.id_in_group student.matching_partner = school_id break def set_payoff(self): players = self.get_players() for p in players: if p.matching_partner == 0: p.payoff = 0 else: p.payoff = c(5 - Constants.student_preference[p.type].index(p.matching_partner)) class Player(BasePlayer): # A,B,C,Dのいずれか type = models.StringField() # 1,2,3,4のいずれか matching_partner = models.IntegerField(initial=0) sub1 = models.IntegerField(choices=Constants.school_id_label, widget=widgets.RadioSelectHorizontal, label='第1志望', blank=True) # None sub2 = models.IntegerField(choices=Constants.school_id_label, widget=widgets.RadioSelectHorizontal, label='第2志望', blank=True) sub3 = models.IntegerField(choices=Constants.school_id_label, widget=widgets.RadioSelectHorizontal, label='第3志望', blank=True) sub4 = models.IntegerField(choices=Constants.school_id_label, widget=widgets.RadioSelectHorizontal, label='第4志望', blank=True) sub5 = models.IntegerField(choices=Constants.school_id_label, widget=widgets.RadioSelectHorizontal, label='第5志望', blank=True) def set_type(self): self.type = Constants.student_type[(self.id_in_group - self.round_number) % 4]