oTreeとは
oTreeは、オンライン上で経済実験を行うためのツールで、フリーで利用することができます。oTreeの導入や基本についてはこちらの記事が非常にわかりやすく参考になります。
監視のジレンマつき公共財ゲーム
今回は、oTreeを使って、公共財(グループ)への貢献をする・しないの二択のゲームを4人で行うシンプルな公共財ゲームに、「4人のうちの誰かひとりでも『監視』をすれば公共財に貢献しなかった人全員が罰せられるが、『監視』をした人はもれなくコストを負う」という要素を付け足したゲームを作ってみました。




作り方
Models
まずはmodels.pyから作ります。
class Constants(BaseConstants):
name_in_url = 'publicgoods_punishment'
players_per_group = 4 #グループ人数
num_rounds = 2 #繰り返しの回数
endowment = c(20) #初期保有額(公共財への投資にかかるコスト)
multiplier = 1.6 #係数
punishment = c(30) #罰の大きさ
punishment_endowment = c(10) #監視にかかるコスト
class Subsession(BaseSubsession):
pass
class Group(BaseGroup):
total_contribution = models.CurrencyField()
group_inspection = models.CurrencyField()
individual_share = models.CurrencyField()
def compute(self):
contributions = [p.contribution for p in self.get_players()]
self.total_contribution = sum(contributions)
self.individual_share = self.total_contribution * Constants.multiplier / Constants.players_per_group
inspections = [p.inspection for p in self.get_players()]
self.group_inspection = sum(inspections)
##誰かひとりでも監視をすれば貢献しなかった人全員に罰を与えることができるが、誰も監視をしなければ貢献しなかった人を罰せられない
if sum(inspections) >= Constants.punishment_endowment:
self.group_inspection = Constants.punishment
else: self.group_inspection = c(0)
for p in self.get_players():
if p.contribution == c(0):
p.individual_punishment = self.group_inspection
else:
p.individual_punishment = c(0)
p.payoff = Constants.endowment - p.contribution + self.individual_share - Constants.punishment_endowment - p.individual_punishment
p.payoff = Constants.endowment - p.contribution + self.individual_share - Constants.punishment_endowment - p.individual_punishment
class Player(BasePlayer):
contribution = models.CurrencyField(
choices=[
[c(Constants.endowment),'貢献する'],
[c(0), '貢献しない']
],
label="グループに貢献しますか?",
widget = widgets.RadioSelect
)
inspection = models.CurrencyField(
choices=[
[c(Constants.punishment_endowment),'監視する'],
[c(0), '監視しない']
],
label="監視しますか?",
widget = widgets.RadioSelect
)
individual_punishment = models.CurrencyField()
Templates
今回は、
Page1…公共財に貢献するかどうか選ぶページ
Page2…監視を行うかどうかを選ぶページ
Page3…参加者全員が回答するまで待つページ
Page4…結果を表示するページ
の4つを作ります。
Page1
{% extends "global/Page.html" %}
{% load otree static %}
{% block title %}
説明&貢献額の決定
{% endblock %}
{% block content %}
<p>
これは{{ Constants.players_per_group }} 人プレイヤーによる公共財ゲームです。<br>
初期保有ポイントは{{ Constants.endowment }}であり、皆さんが貢献したポイントは実験者側で{{ Constants.multiplier }}倍されます。<br>
すなわち、 {{ Constants.players_per_group }} 人の貢献ポイントの合計を{{ Constants.multiplier }}倍したポイントを{{ Constants.players_per_group }}で割ったポイントが一人ひとりに返されます。
<br><br>
</p>
{% formfields player.contribution %}
{% next_button %}
{% endblock %}
Page2
{% extends "global/Page.html" %}
{% load otree static %}
{% block title %}
監視の決定
{% endblock %}
{% block content %}
<p>
また、このゲームには監視制度があります。<br>
監視には{{ Constants.punishment_endowment }} かかりますが、<br>
誰かが監視をすれば、<br>
貢献しなかった人のポイントを{{ Constants.punishment }} 引くことができます。<br>
</p>
{% formfields player.inspection %}
{% next_button %}
{% endblock %}
Page3
oTreeに用意されているテンプレートを使うので、自分では書きません。
Page4
{% extends "global/Page.html" %}
{% load otree static %}
{% block title %}
結果の確認
{% endblock %}
{% block content %}
<p>
あなたは初期保有ポイントとして<strong>{{ Constants.endowment }}</strong>を持っていました。<br>
{% if player.contribution == Constants.endowment %}
あなたは、その<strong>{{ Constants.endowment }}</strong>をグループに貢献しました。<br>
{% else %}
あなたは、その<strong>{{ Constants.endowment }}</strong>をグループに貢献せず、手元に残しました。<br>
{% endif %}
あなたのグループでは合計<strong>{{ group.total_contribution }}</strong>が貢献されていました。<br>
その結果、一人あたりには<strong>{{ group.individual_share }}</strong>が返されました。<br>
監視コストとして、あなたは<strong>{{ player.inspection }}</strong>払いました。<br>
{% if group.group_inspection >= Constants.punishment %}
あなたのグループでは、監視が行われました。<br>
あなたは監視により<strong>{{player.individual_punishment }}</strong>を失いました。<br>
{% else %}
あなたのグループでは誰も監視を行いませんでした。<br>
{% endif %}
</p>
<p>
<strong>{{ Constants.endowment }}-{{ player.contribution }}+{{ group.individual_share }}-{{ Constants.punishment_endowment }}-{{ player.individual_punishment}}={{ player.payoff }}</strong>
</p>
<p>
したがって,あなたはこのラウンドで<strong>{{ player.payoff }}</strong>を受け取りました.
</p>
{% next_button %}
{% endblock %}
Pages
最後に、Pages.pyでページ遷移や関数の実行を指示します。
class page1(Page):
timeout_seconds = 60
form_model = 'player'
form_fields = ['contribution']
class page2(Page):
timeout_seconds = 60
form_model = 'player'
form_fields = ['inspection']
class page3(WaitPage):
def after_all_players_arrive(self):
self.group.compute()
class page4(Page):
pass
page_sequence = [page1,
page2,
page3,
page4]