from otree.api import * doc = """ Your app description """ ########## 外生的に決めるパラメータを定義するクラス ########## ########## Class to define externally given variables ########## class Constants(BaseConstants): name_in_url = 'resource_reproduction_2021_four' players_per_group = 4 num_rounds = 50 # number of rounds per game pool_start = 40 # resources in pool at the start of game exploitation_min = 0 # minimum amount of resources players can exploit exploitation_max = 4 # maximum amount of resources players can exploit reproduction_rate = 2 # multiplier to resources in pool when reproduced reproduction_interval = 2 # interval of reproduction between recovery ########## サブセッション=セッションを構成する各ゲームの集合のクラス(グループ分け,条件設定等) ########## ########## Class of a set of games consisting a session (group assignment etc) ########## class Subsession(BaseSubsession): pass ########## グループ変数を定義するクラス ########## ########## Class to define group valiables ########## class Group(BaseGroup): total_exploitation = models.IntegerField(initial=0) current_pool = models.IntegerField(initial=0) resource_outage = models.BooleanField(initial=False) timeout = models.BooleanField(initial=False) ########## プレイヤー変数・メソッドを定義するクラス ########## ########## Class to define player valiables ########## class Player(BasePlayer): exploitation = models.IntegerField( initial=0, min = Constants.exploitation_min, max = Constants.exploitation_max, ) resource = models.IntegerField(initial = 0) ########## 関数(ResultWaitPageで使用する関数は,クラスの外に書く) ########## ########## Functions(Functions used in ResultWaitPage need to be written outside class) ########## # 前ラウンドの変数をコピーする(最初のラウンドの場合は初期値を代入する) # Copy the values in the previous round or initialize these values in the 1st round def data_update(group): players = group.get_players() # Get list of players if group.round_number != 1: group.total_exploitation = group.in_round(group.round_number - 1).total_exploitation group.current_pool = group.in_round(group.round_number-1).current_pool for p in players: p.exploitation = p.in_round(group.round_number - 1).exploitation p.resource = p.in_round(group.round_number - 1).resource else: group.current_pool = Constants.pool_start resource_check = [p.resource for p in players] # for debug print('players is', players) # デバッグ用 print('total_exploitation is', group.total_exploitation) # for debug print('current_pool is', group.current_pool) # for debug print('resource_check is', resource_check) # for debug # 共有プールの資源量をプレイヤーの行動に基づいて更新する # Update the amount of resources in pool based on players' decisions def resource_update(group): # Get list of players players = group.get_players() # Calculate total exploitation by all players exploitations = [p.exploitation for p in players] group.total_exploitation = sum(exploitations) # Check the outage of common pool if group.total_exploitation >= group.current_pool: group.resource_outage = True # update the common pool group.current_pool = group.current_pool-group.total_exploitation # If not outage, # (1) update the common pool if it is the time else: if group.round_number%Constants.reproduction_interval==0: group.current_pool = (group.current_pool-group.total_exploitation)*Constants.reproduction_rate if group.current_pool > Constants.pool_start: group.current_pool = Constants.pool_start else: group.current_pool = group.current_pool-group.total_exploitation # (2) update the resources of players for p in players: p.resource = p.resource + p.exploitation # (3) check timeout if group.round_number == Constants.num_rounds: group.timeout = True ########## ページを定義するクラス ########## ########## Class to define pages ########## class Introduction(Page): @staticmethod def is_displayed(self): return self.round_number == 1 class Update_data(WaitPage): after_all_players_arrive = data_update class Exploit(Page): form_model = 'player' form_fields = ['exploitation'] timeout_seconds = 60 @staticmethod def vars_for_template(self): # group = Player.group if self.round_number == 1: common_pool = Constants.pool_start else: common_pool = self.group.in_round(self.round_number - 1).current_pool return dict( round_number = self.round_number, common_pool = common_pool, ) @staticmethod def js_vars(self): ## 配列の作成に必要な定数をローカルに作成 round_number = self.round_number # 現在のラウンド数 players = self.group.get_players() # すべてのプレイヤーのリスト if self.round_number == 1: pass else: ## resource を出力する List を作成 List_resource = [] for p in players: # リストに含まれるプレイヤーについて id = p.id_in_group # id を取得 pname = 'Player' + str(id) # プレイヤー名の文字列 pdata = [] # データ格納用のリスト for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(p.in_round(j+1).resource) # pdata リストに値を追加 pdict = {'name':pname,'data':pdata} # プレイヤー毎のリストを作成 List_resource.append(pdict) ## current_pool を出力する List を作成 pname = 'current_pool' # プレイヤー名の文字列 pdata = [] # データ格納用のリスト for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(self.group.in_round(j+1).current_pool) # pdata リストに値を追加 List_current_pool = [{'name':pname,'data':pdata}] # プレイヤー毎のリストを作成 print('List_resource is', List_resource) # デバッグ用 print('List_current_pool is', List_current_pool) # デバッグ用 return dict( # num_rounds = self.session.config['num_rounds'], # round_number = self.round_number, List_resource=List_resource, List_current_pool=List_current_pool, ) class Update_resources(WaitPage): after_all_players_arrive = resource_update class GameOver(Page): @staticmethod def is_displayed(self): # group = Player.group return self.group.resource_outage == True or self.group.timeout == True @staticmethod def js_vars(self): # Result クラスの同名の関数とは微妙に違うので注意 # group = Player.group ## 配列の作成に必要な定数をローカルに作成 round_number = self.round_number # 現在のラウンド数 players = self.group.get_players() # すべてのプレイヤーのリスト ## exploitation を出力する List を作成 List_exploitation = [] for p in players: # リストに含まれるプレイヤーについて id = p.id_in_group # id を取得 pname = 'Player' + str(id) # プレイヤー名の文字列 pdata = [] # データ格納用のリスト if round_number > 1: for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(p.in_round(j+1).exploitation) # pdata リストに値を追加 pdata.append(p.exploitation) # 現在のラウンドについて pdata リストに値を追加 pdict = {'name':pname,'data':pdata} # プレイヤー毎のリストを作成 List_exploitation.append(pdict) ## resource を出力する List を作成 List_resource = [] for p in players: # リストに含まれるプレイヤーについて id = p.id_in_group # id を取得 pname = 'Player' + str(id) # プレイヤー名の文字列 pdata = [] # データ格納用のリスト if round_number > 1: for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(p.in_round(j+1).resource) # pdata リストに値を追加 pdata.append(p.resource) # 現在のラウンドについて pdata リストに値を追加 pdict = {'name':pname,'data':pdata} # プレイヤー毎のリストを作成 List_resource.append(pdict) ## total_exploitation を出力する List を作成 pname = 'total_exploitation' # プレイヤー名の文字列 pdata = [] # データ格納用のリスト if round_number >1: for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(self.group.in_round(j+1).total_exploitation) # pdata リストに値を追加 pdata.append(self.group.total_exploitation) # 現在のラウンドについて pdata リストに値を追加 List_total_exploitation = [{'name':pname,'data':pdata}] # プレイヤー毎のリストを作成 ## current_pool を出力する List を作成 pname = 'current_pool' # プレイヤー名の文字列 pdata = [] # データ格納用のリスト if round_number >1: for j in range(round_number-1): # 1ラウンド目から直前のラウンドまでについて pdata.append(self.group.in_round(j+1).current_pool) # pdata リストに値を追加 pdata.append(self.group.current_pool) # 現在のラウンドについて pdata リストに値を追加 List_current_pool = [{'name':pname,'data':pdata}] # プレイヤー毎のリストを作成 return dict( num_rounds = Constants.num_rounds, List_exploitation=List_exploitation, List_resource=List_resource, List_total_exploitation=List_total_exploitation, List_current_pool=List_current_pool, ) page_sequence = [ Introduction, # ゲームの説明 (Explanation of game) Update_data, # 前ラウンドの変数のコピー (Copy of variables in previous round) Exploit, # プレイヤーの入力 (Input from players) Update_resources, # 資源量の更新 (Update resources) GameOver # ゲーム終了 (End of game) ]