#from asyncio import constants #gov_co2, from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, # gov_co2, ) import random # なにかコードについて質問がある場合は、長瀬までご連絡ください。 # メールアドレスは、odenshacho@icloud.comです class Constants(BaseConstants): # 実験appと同じ名前にする name_in_url = 'carbon_a' # 何人1組にするか設定 players_per_group = 4 # ラウンド数の設定 # なおターンという概念がotreeにないので、ラウンドごとに処理を分けて実質ターンを作れば良い。 num_rounds = 6 # 実験説明用にincludeするテンプレートファイルの場所を指定 # 通常は、実験appの名前/instructions.htmlとし、instructions.htmlというテンプレートファイルをつくる instructions_template = 'carbon_a/instructions.html' # 政府から配布される排出枠の上限 2022ver gov_co2 = [400,400,300,300,200,200] # 政府から配布される排出枠の上限 2022年度バージョン。最終的にはこっちを使いたい Jyogen_list = [400,400,300,300,200,200] #売り上げ生産能力 2022年度追加機能 2022ver Unit_price_list = [150,150,120,120] # 各入札者の資本金 shihonkin = 10000 # 技術導入に対する投資額 invest_price = 2000 # 生産における必要枠数それぞれ expand_need = 120 normal_need = 100 shrink_need = 80 non_need = 0 # 生産における必要枠数それぞれ(チケット使用時) expand_need_ticket = 84 normal_need_ticket = 70 shrink_need_ticket = 56 non_need_ticket = 0 # 辞書の指定した値のキーをリストとして取り出す関数 def get_keys_by_value(dict, value): return [key for key, val in dict.items() if val == value] class Subsession(BaseSubsession): game_app = models.StringField(initial="均一") Jyogen = models.IntegerField() def creating_session(self): self.Jyogen = Constants.Jyogen_list[self.round_number-1] import random Unit_list = random.sample(Constants.Unit_price_list, 4) for p in self.get_players(): if self.round_number == 1: p.unit_price_ability = Unit_list[p.id_in_group-1] else: p.unit_price_ability = p.in_round(1).unit_price_ability p.expand_profit = Constants.expand_need* p.unit_price_ability p.normal_profit = Constants.normal_need* p.unit_price_ability p.shrink_profit = Constants.shrink_need* p.unit_price_ability p.non_profit = 0 for g in self.get_groups(): g.current_gov_co2 = Constants.gov_co2[self.round_number-1] class Group(BaseGroup): # 1200枠超えてたらここをTrueに変える can_haibun = models.BooleanField(initial=False) # 全員で何枠入札してるか数えたやつ total_purchase_num = models.IntegerField(initial=0) # 政府から配布される排出枠の上限 current_gov_co2 = models.IntegerField() # 均衡価格 kinko_price = models.IntegerField() # 枠トレードが起こったかどうかフラグ waku_trade_flag = models.BooleanField(initial=False) # 企業ごとの初期配分量を決定するための処理 def do_shoki_haibun(self): # データベースからプレイヤーのデータを持ってくる players = self.get_players() # playersの中身[P1, P2, P3, P4] # 変数定義 purchase_price_lst = [] purchase_player_id = [] purchase_num_lst = [] # priceでまとめたpurchase_num辞書 purchase_priceSum_num_dict = {} for player in players: purchase_price_lst.append(player.purchase_price) purchase_player_id.append(player.id_in_group) purchase_num_lst.append(player.purchase_num) if player.purchase_price in purchase_priceSum_num_dict: purchase_priceSum_num_dict[player.purchase_price] += player.purchase_num else: purchase_priceSum_num_dict[player.purchase_price] = player.purchase_num # この時点でpurchase_num_lstの中身は、[P1の希望枠数,P2の希望枠数,P3の希望枠数,P4の希望枠数] # sum関数を使ってリストの要素をすべて足し合わせ、total_purchase_numに代入 self.total_purchase_num = sum(purchase_num_lst) # 1200枠以上あれば初期配分可能、そうじゃなかったらやり直し。 # pages.pyでcan_haibunがTrueのとき初期配分ページをすべてスキップするようにしている。 if self.total_purchase_num >= self.current_gov_co2: self.can_haibun = True else: # このFalseに特に意味はないのですが、こうするとこれ以下の関数の処理を強制的に行わないようにできる。 return False # 1200枠以上になってて配分が可能だったら下の処理が走る。 # price高い順でソート purchase_priceSum_num_takaijun_dict = dict(sorted(purchase_priceSum_num_dict.items(), key=lambda x:x[0], reverse=True)) # デバック用 print("do_shokihaibun関数") print("purchase_priceSum_num_takaijun_dict") print(purchase_priceSum_num_takaijun_dict) # 1200枠になったときの価格を調べる用変数定義 count = 0 self.kinko_price = 0 buyers_price_takaijun = [] # 均衡価格の計算 for price, num in purchase_priceSum_num_takaijun_dict.items(): count += num buyers_price_takaijun.append(price) if count >= self.current_gov_co2: self.kinko_price = price break print("buyers_price_takaijun") print(buyers_price_takaijun) # debug用 debug_count = 0 # 初期配分の計算 for price in buyers_price_takaijun: debug_count += 1 print(str(debug_count)+"週目") # 残り枠がない場合計算を抜ける if self.current_gov_co2 == 0: break # 同じ価格をつけている人がいるかいないかで場合分け if purchase_price_lst.count(price) == 1: idx = purchase_price_lst.index(price) player_id = purchase_player_id[idx] player = self.get_player_by_id(player_id) if self.current_gov_co2 >= player.purchase_num: player.shojikin -= self.kinko_price * player.purchase_num player.shoki_haibun = player.purchase_num self.current_gov_co2 -= player.purchase_num else: player.shojikin -= self.kinko_price * self.current_gov_co2 player.shoki_haibun = self.current_gov_co2 self.current_gov_co2 -= player.purchase_num print("player") print(player) else: buyers = [] buyers_total_purchase_num = 0 for idx, price2 in enumerate(purchase_price_lst): if price2 == price: player_id = purchase_player_id[idx] buyer = self.get_player_by_id(player_id) buyers.append(buyer) buyers_total_purchase_num += buyer.purchase_num if self.current_gov_co2 >= buyers_total_purchase_num: for player in buyers: player.shojikin -= self.kinko_price * player.purchase_num player.shoki_haibun = player.purchase_num self.current_gov_co2 -= player.purchase_num else: bunbo = buyers_total_purchase_num now_gov_waku = self.current_gov_co2 for player in buyers: true_purchase_num = now_gov_waku * player.purchase_num // bunbo player.shojikin -= self.kinko_price * true_purchase_num player.shoki_haibun = true_purchase_num self.current_gov_co2 -= true_purchase_num # 枠が余っていたらプレイヤーにランダムで余りを売らせる if self.current_gov_co2 > 0: p = random.choice(players) p.shoki_haibun += self.current_gov_co2 p.shojikin -= self.kinko_price * self.current_gov_co2 # 誰にランダムでいくつ余り割り振ったか保存 p.took_amari = self.current_gov_co2 self.current_gov_co2 = 0 # 初期配分量を現在の枠数のところに代入 for player in players: player.waku_num = player.shoki_haibun class Player(BasePlayer): # 資産(いわゆる最終の利得になる部分) shisan = models.IntegerField(initial=0) # 個人ごとの売り上げ生産能力 unit_price_ability = models.IntegerField() # 排出枠に対する入札量 purchase_num = models.IntegerField(label='') # 排出枠に対する入札価格 purchase_price = models.IntegerField(label='') # 初期配分量 shoki_haibun = models.IntegerField(initial=0) # 余りを受け取った人は余り枠数表示 took_amari = models.IntegerField(initial=0) # 各入札者の所持金 shojikin = models.IntegerField(initial=Constants.shihonkin) # 所持金枠トレード前 shojikin_before_trade=models.IntegerField() # 現在の枠数 waku_num = models.IntegerField() #売上金 expand_profit =models.IntegerField() normal_profit = models.IntegerField() shrink_profit = models.IntegerField() non_profit = models.IntegerField() #総資産 sou_shisan = models.IntegerField() def calc_B(self): self.sou_shisan = sum([p.shisan for p in self.in_all_rounds()]) '''枠トレード前の状態を保存するフィールド''' # 枠を買う量(保存用) desired_buy_num=models.IntegerField() # 枠を買う価格(保存用) desired_buy_price=models.IntegerField() # 枠を売る量(保存用) desired_sell_num=models.IntegerField() # 枠を売る価格(保存用) desired_sell_price=models.IntegerField() # 実際買った量 bought_num = models.IntegerField(initial=0) # 実際売った量 sold_num = models.IntegerField(initial=0) # 枠を買う量 buy_num=models.IntegerField(min=0,label='',) # 枠を買う価格 buy_price=models.IntegerField(min=0,label='',) # 枠を売る量 sell_num=models.IntegerField(min=0,label='',) # 枠を売る価格 sell_price=models.IntegerField(min=0,label='',) invest = models.StringField( choices=[['はい', 'はい'], ['いいえ', 'いいえ']], label='', widget=widgets.RadioSelectHorizontal, ) seisan = models.StringField( choices=[['拡大', '拡大生産'], ['通常', '通常生産'], ['縮小', '縮小生産'], ['しない', '生産しない']], label='', widget=widgets.RadioSelectHorizontal, ) emission = models.StringField( choices=[['買う', '排出枠を買う'], ['しない', '売買しない'], ['売る', '排出枠を売る'],], label='', widget=widgets.RadioSelectHorizontal, )