from statistics import median from xml.parsers.expat import model from otree.api import * import random import numpy as np import matplotlib from matplotlib import pyplot as plt from matplotlib.font_manager import FontProperties import os doc = """ BCG_demo 0405 """ class C(BaseConstants): NAME_IN_URL = 'BCG_demo' PLAYERS_PER_GROUP = None # testing NUM_ROUNDS = 10 # testing TOTAL_EXP_TIME = 30 SHOWUPFEE = 100 NUM_PLAYERS = 24 p_value = 2/3 # p-BCG初始設定 timeout_sec = 60 # 每一回合的決策時間 timer_sec = 59 # 出現timer的剩餘時間 alert_sec = 10 # 出現提醒字樣的剩餘時間 timeoutsec = 30 # 結果頁面 每一回合的決策時間 timersec = 29 # 結果頁面 出現timer的剩餘時間 min_number = 0 max_number = 100 winning_prize = 100 consolation_prize = 0 ''' def creating_session(subsession): import itertools information = itertools.cycle([True, False]) for player in subsession.get_players(): player.full_information = next(information) print(player) ''' class Subsession(BaseSubsession): pass class Group(BaseGroup): closest_num = models.IntegerField(initial=101) # 獲勝數字 class Player(BasePlayer): guess_num = models.IntegerField(min=C.min_number, max=C.max_number, label='請輸入您所選擇的整數:') is_winner = models.BooleanField(initial=False) decision_duration = models.FloatField(initial=0) # 決策時間 is_no_decision = models.BooleanField(initial=False) # 是否有進行決策 pmean = models.FloatField(initial=0) distance = models.FloatField() full_information = models.BooleanField(initial=False) all_no_decision = models.BooleanField(initial=False) # 全都沒有決策的話,html需顯示「勝利數字不存在」 #Q1 = models.IntegerField(choices=[[1, 'A'], [2, 'B'], [3, 'C'], [4, 'D']], widget=widgets.RadioSelect) #Q2 = models.IntegerField(choices=[[1, 'A'], [2, 'B'], [3, 'C'], [4, 'D']], widget=widgets.RadioSelect) # 問卷選項 gender = models.StringField(choices = [['male', '男'], ['female', '女']], widget = widgets.RadioSelect, label='一、請問您的性別是?') country = models.StringField(choices = [['local', '臺灣本地生'], ['not_local', '非臺灣本地生(例如外籍交換學生、僑生等)']], widget = widgets.RadioSelect, label='二、請問您是否為臺灣本地生?') major = models.StringField(choices = [['economic', '經濟系學生'], ['management', '管理學院學生'],['othermajor', '其他院系學生']], widget = widgets.RadioSelect, label='三、請問您是否為經濟系或管理學院學生?') course = models.IntegerField(choices = [[0, '0門'],[1, '1門'], [2, '2門'], [3, '3門'], [4, '4門'], [5, '5門'], [6, '超過5門']], widget = widgets.RadioSelect, label='四、請問您修過多少門經濟學的課程?') grade = models.StringField(choices = [['grade_1', '大學部一年級'], ['grade_2', '大學部二年級'], ['grade_3', '大學部三年級'], ['grade_4', '大學部四年級'], ['grade_5', '大學部五年級以上'], ['MS', '碩士班學生']], widget = widgets.RadioSelect, label='五、請問您的年級是?') purpose = models.StringField(label='六、請您猜測本實驗的目的為何') # FUNCTIONS def creating_session(subsession): import itertools information = itertools.cycle([True, False]) for player in subsession.get_players(): player.full_information = next(information) #print(player) def calculate_result(list): guess_players_dict = {} # {guess_num: players} to_calculate_dict = {} # {distance: players} 誰最接近 total = 0 submit_cnt = 0 p_mean = 0 no_submit = 0 for p in list: total += p.guess_num if p.is_no_decision == False: submit_cnt += 1 else: no_submit += 1 p_mean = C.p_value * (total/submit_cnt) # 獲勝數字 #print(p_mean) # 將所有受試者的數字以 dictionary 形式存下來 for p in list: if p.guess_num in guess_players_dict: players = guess_players_dict[p.guess_num] else: players = [] players.append(p) guess_players_dict[p.guess_num] = players for p in list: tmp_distance = p.guess_num - p_mean distance = abs(tmp_distance) p.distance = distance if p.is_no_decision == False: if p.distance in to_calculate_dict: players = to_calculate_dict[p.distance] else: players = [] players.append(p) to_calculate_dict[p.distance] = players # distance(key)-players(value) winner = None print(to_calculate_dict) for p in list: p.pmean = p_mean p.payoff = C.consolation_prize # 判斷獲勝的受試者,並給予對應的報酬 for num, players in sorted(to_calculate_dict.items()): print("123") if (winner is None) and (players[0].is_no_decision == False): print(players) winner = random.choice(players) winner.payoff = C.winning_prize winner.is_winner = True print(winner) #winner.closest_num = winner.guess_num #def chart(group: Group): def set_payoffs(group: Group): # 判斷是否全員都無決策 no_decision_cnt_con = 0 # 控制組沒有決策的人數 no_decision_cnt_treat = 0 # 實驗組沒有決策的人數 con_cnt = 0 # 對照組總人數 treat_cnt = 0 # 實驗組總人數 player_treat = [] # 存放實驗組受試者的list player_con = [] # 存放控制組受試者的list for p in group.get_players(): # 計算實驗組的「無決策」人數 if p.full_information == True: treat_cnt += 1 # 實驗組總人數 player_treat.append(p) if p.is_no_decision == True: no_decision_cnt_treat += 1 # 計算對照組的「無決策」人數 else: con_cnt += 1 # 對照組總人數 player_con.append(p) if p.is_no_decision == True: no_decision_cnt_con += 1 # 先處理實驗組 if no_decision_cnt_treat == treat_cnt: # 全員都無決策 for p in player_treat: p.all_no_decision = True # 全員都無決策的話,html要顯示「勝利數字不存在」 # 全員都有決策才需要計算獲勝數字或顯示圖表 else: calculate_result(player_treat) # 再處理對照組 if no_decision_cnt_con == con_cnt: # 全員都無決策 for p in player_con: p.all_no_decision = True # 全員都無決策的話,html要顯示「勝利數字不存在」 # 全員都有決策才需要計算獲勝數字 else: calculate_result(player_con) # 顯示「其他受試者選擇數字」之圖表 number = [] count = [] no_submit_count = 0 guess_players_dict = {} for p in group.get_players(): if p.full_information == True: if p.guess_num in guess_players_dict: players = guess_players_dict[p.guess_num] else: players = [] players.append(p) guess_players_dict[p.guess_num] = players for p in group.get_players(): if p.full_information == True: if p.is_no_decision == True: no_submit_count += 1 for i in range(0, 101): number.append(i) if i in guess_players_dict: count.append(len(guess_players_dict[i])) else: count.append(0) count[0] -= no_submit_count plt.figure(figsize = (15, 5)) x = np.arange(len(number)) plt.bar(x, count) plt.xticks(x, number) plt.xticks(fontsize = 5) plt.xlabel('Number') plt.ylabel('Count') path = os.path.dirname(os.path.abspath(".")) app_path = os.path.join(path, 'April_BCG_coedit', '_static') plt.savefig("{}/plot{}.jpg".format(app_path, p.round_number)) # PAGES class Intro(Page): @staticmethod def is_displayed(player): # built-in methods return player.round_number == 1 # 只有 round 1 要有實驗說明 class Instru(Page): @staticmethod def is_displayed(player): # built-in methods return player.round_number == 1 # 只有 round 1 要有實驗說明 class DecisionPage(Page): form_model = 'player' form_fields = ['guess_num', 'decision_duration'] timeout_seconds = C.timeout_sec # built-in guess_num = models.IntegerField(min=0,max=100) # 驗證受試者輸入之內容是否符合要求 timer_text = '作答剩餘時間為:' @staticmethod def before_next_page(player, timeout_happened): # built-in methods if timeout_happened: player.is_no_decision = True # 若回合時間到,將 player 設定為沒有做決策 class ResultsWaitPage(WaitPage): after_all_players_arrive = set_payoffs # built-in methods,所有受試者都離開決策頁後,執行 set_payoffs # after_all_players_arrive = chart April_BCG_coedit_name = "BCG_demo/ResultsWaitPage.html" title_text = "等待頁面" body_text = "請稍等其他參與者做出決策,我們將儘速提供本回合結果之相關資訊。" class Results(Page): timer_text = '頁面停留剩餘時間:' timeout_seconds = C.timeoutsec # built-in @staticmethod def vars_for_template(player): return { "image_path":'plot{}.jpg'.format(player.round_number), "vic_num": float("{:.2f}".format(player.pmean)) } #@staticmethod #def vars_for_template(player): #return { #"vic_num": float("{:.2f}".format(player.pmean)) #} class Finish(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player: Player): # built-in methods,將 total_payoff 的值傳到 html 頁面 return { "total_payoff": sum([p.payoff for p in player.in_all_rounds()]) } # 問卷 class Survey(Page): form_model = 'player' form_fields = ['gender', 'country', 'major', 'course', 'grade', 'purpose'] # 最後一輪再顯示 @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS #goole.survey class googlesurvey(Page): # 最後一輪再顯示 @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player: Player): # built-in methods,將 total_payoff 的值傳到 html 頁面 return { "random_code": player.participant.code } page_sequence = [Intro, Instru, DecisionPage, ResultsWaitPage, Results, Finish, Survey, googlesurvey]