from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import random doc = """実験をする部分""" class Constants(BaseConstants): # この辺はただの設定 name_in_url = 'cooperative_game_t' # 1グループに何人入れるのか players_per_group = None # 実験の方法のインストラクションページ instructions_template = 'cooperative_game_t/instructions.html' #パラメーター(初期値) ***************************************** # いじるなら,この囲われた中にして # 実験を繰り返す回数 num_rounds = 10 # 参加者数(ここの設定変えるなら,setting.py の "num_demo_participants" も同じ数に変更) num_members = 4 # 各プレーヤーへの初期金額の割り当て init_fund = 10000 # マスクの購入枚数上限(全ての試行全を通して) mask_max_num = 64 # 各プレイヤーに各試行時に配るマスクの枚数 # ここ1なら各ターンに各人に1枚ずつマスクが配布される. # ここ0なら各ターンに配布はされない. mask_each_round = 0 # マスクの価格 mask_price = 100 # 治療費 treatment_costs = 3000 # 感染率の上限 infection_rate_max = 20 # 感染率の調節に使う値 (マスク使用者の人数×(値)の部分の値 ) infection_rate_par= 5 # 最終決算時のマスクの価値 mask_value = 300 # ここまで #パラメーター(初期値) ***************************************** # 各試行で購入可能なマスクの枚数を決める部分です # 変更するなら注意して行なってください # 自分で書く試行に提示するマスクを決めたい場合は,したの”#”を外して [ ] の中の数字をいじってください. # 今は10回試行で合計が44になるように調節してます. # (数字の数が試行の数(num_roundst と合わせる)) # 各数字が,マスクの枚数を表す.合計がmask_max_num と合うように調節しないと変なことなりますよ. # マスクの購入在庫 回分(1回の試行で使える分)自分で決める # 外す "#" はこの下のやつ # mask_stock = [4,5,6,6,7,5,3,4,2,2] # マスクの購入在庫 回分(1回の試行で使える分)自動で割り振る # 何もいじらなくても勝手に指定した試行数(num_roundst)で合計が枚数が mask_max_num になるように # 自動で割り振ってくれます.(こっちにしとくこと推奨) mask_stock = [0] * num_rounds buffer = mask_max_num while 0 < buffer : for num in range( 0 , num_rounds ) : if random.random() < 0.5 and 0 < buffer : mask_stock[ num ] = mask_stock[ num ] + 1 buffer = buffer -1 # ***************************************** # 根本的な仕様変更変更をしない限り,ここ以下の部分は変更しないでください # プログラムが壊れます. # ***************************************** class Subsession(BaseSubsession): pass #ここで全員揃った後の処理(各試行で初期化される) class Group(BaseGroup): # あとで買えた人の情報を保存 #ここで全員揃った後の処理(前のラウンド値読み出し) def setdata(self): # 販売されたマスク数を取得 round_num = self.round_number #今回は前回の試行のデータを継承 for each_player in self.get_players(): each_player.budget = Constants.mask_stock[round_num - 1] if round_num > 1 : previous_data = each_player.in_previous_rounds() previous_data = previous_data[-1] each_player.fund = previous_data.fund each_player.mask_num = each_player.mask_num + previous_data.mask_num #ここで全員揃った後の処理(マスクの購入) def purchase(self): # 変えるマスクの最大数を取得 round_num = self.round_number mask_stock_num = Constants.mask_stock[round_num - 1] # 購入する順番を決める number_list = [] for num in range( 0, Constants.num_members ) : number_list.append( num ) random.shuffle( number_list ) buy_num = 1 # 実際の購入処理 for player_id in number_list : # 購入者のオブジェクト each_player = self.get_player_by_id(player_id+1) # 購入順保存 each_player.buy_number = buy_num buy_num = buy_num + 1 # マスクの在庫がある if mask_stock_num > 0 : # ユーザーが買いたい分全部買える if mask_stock_num >= each_player.desire_mask_num : each_player.new_mask_num = each_player.desire_mask_num mask_stock_num = mask_stock_num - each_player.new_mask_num each_player.mask_num = each_player.mask_num + each_player.new_mask_num # 変えるけど買いたいけど全部は買えない else : each_player.new_mask_num = mask_stock_num mask_stock_num = 0 each_player.mask_num = each_player.mask_num + each_player.new_mask_num # マスクが買えなかった else : each_player.new_mask_num = 0 #ここで全員揃った後の処理(1回の試行での決算) def set_payoffs(self): for each_player in self.get_players(): # マスクを使うかう場合枚数を減らす. if each_player.sent_mask_use != None : if each_player.sent_mask_use != 0 : each_player.mask_num = each_player.mask_num - 1 #マスク使用者人数算出用(自分以外の人) other_players_list = each_player.get_others_in_group() for other_player in other_players_list: if other_player.sent_mask_use != None : if other_player.sent_mask_use != 0 : each_player.mask_use_user = each_player.mask_use_user + 1 #感染率決定(各人) each_player.disese_probability = Constants.infection_rate_max - \ Constants.infection_rate_par * each_player.mask_use_user # 各試行での損失計算 if random.uniform(0,100) < each_player.disese_probability : # 感染の場合の計算 each_player.infection_frag = 1 each_player.fund = each_player.fund - Constants.mask_price * each_player.new_mask_num - Constants.treatment_costs else : # 感染しなかった場合の損失計算 each_player.infection_frag = 0 each_player.fund = each_player.fund - Constants.mask_price * each_player.new_mask_num #ここで全員揃った後の処理(最終決算) def summary(self): # ここで最終決算 for each_player in self.get_players() : each_player.fund = each_player.fund + \ Constants.mask_value * each_player.mask_num # 各プレーヤーごとに使う情報(各試行で初期化される) class Player(BasePlayer): # 現在持っている所持金 fund = models.IntegerField(initial=Constants.init_fund) # 感染したかどうかを保存 infection_frag = models.IntegerField(initial=0) # 現在持っているマスクの総数 mask_num = models.IntegerField(initial=Constants.mask_each_round) # 今回の試行で買えたマスクの枚数 new_mask_num = models.IntegerField(initial=0) # 購入の順番を保存 buy_number = models.IntegerField(initial=0) mask_use_user = models.IntegerField(initial=0) disese_probability = models.IntegerField(initial=Constants.infection_rate_max) # フォームの表示に使う情報(マスクの枚数) desire_mask_num = models.IntegerField( min=0, label="【記入欄】", ) # フォームの表示に使う情報(マスクの使用) sent_mask_use = models.IntegerField( choices=[[1, '使用'], [0, '使用しない']], label="【使用するor使用しない】", widget=widgets.RadioSelect, ) # マスクの購入数最大数設定(動的) def desire_mask_num_max(self): return self.budget budget = models.IntegerField(initial=0)