信頼ゲームを作ってみる
さて,それでは信頼ゲームを作ってみましょう.そしてoTreeについてもっと詳しく理解していきましょう.
でも,概要はこんな感じ.
はじめに,プレイヤー1が10ポイント受け取ります.そしてプレイヤー2は何も受け取りません.プレイヤー1はプレイヤー2に自身の持っているポイントの一部,もしくは全部を渡すことができます.ただし,プレイヤー2が受け取る前に,その渡したポイントは3倍になります.プレイヤー2が3倍になったポイントを受け取ったら,プレイヤー2はそのうちのいくらをプレイヤー1に渡すか決定することになります.
ここでは以下の工程を経て,信頼ゲームのアプリケーションを 作成していきます.
- アップグレード
- 初期アプリケーションの作成
- models.pyの定義
- templates.htmlとviews.pyの定義
- settings.pyの中のSESSION_CONFIGSの追加
- データベースのリセットと再起動の流れで行きます.
最新バージョンのoTreeを使うために,コマンドラインを開いて,以下のコードを実行しましょう
pip3 install -U otree-core
#再度インストールします.
otree resetdb
#インストールをした際にはデータベースをリセットしましょう.
cdコマンドを使って,"requirements_base.txt"のある,あなたが作ったoTreeプロジェクトフォルダに移動してください.
このディレクトリの中に,公共財ゲーム用のディレクトリを作ってあげます.
otree startapp my_trust
これによってoTreeプロジェクトフォルダの中に"my_trust"というフォルダができたことを確認してください.
最初に,アプリケーションにおけるモデルの定数を定義しましょう.初期保有額は10ポイントであり,支払額は3倍になります.
class Constants(BaseConstants):
name_in_url = 'my_trust'
players_per_group = 2
num_rounds = 1
endowment = c(10)
multiplication_factor = 3
続いて,プレイヤーフィールドとグループフィールドを追加しましょう.ここには2つの重要なデータを用意します."sent"としてプレイヤー1からプレイヤー2への支払額を定義し,"sent back"はプレイヤー2からプレイヤー1への支払額です.
直感的には,プレイヤーフィールドは以下のように定義するかと思われるかもしれません.
# Don't copy paste this...see below
class Player(BasePlayer):
sent_amount = models.CurrencyField()
sent_back_amount = models.CurrencyField()
しかし,このモデルには問題があります."sent_amount"はプレイヤー1だけに適用されなければならず,"sent_back_amount"はプレイヤー2だけに適用されなければなりません.そして,プレイヤー1は"sent_back_amount"を呼び出せなければなりません.どのようにすれば,データモデルはより適切になるでしょうか?
これらのフィールドは"Group"レベルで定義する必要があります.
class Group(BaseGroup):
sent_amount = models.CurrencyField()
sent_back_amount = models.CurrencyField()
そして,プレイヤー1の支払額の選択は,自由に数字を入力できる型式ではなく,ドロップダウンメニューで選べるようにしましょう.この機能を実現するために,"currency_range"関数とともに"choice"という引数を用います.
sent_amount = models.CurrencyField(
choices=currency_range(0, Constants.endowment, c(1)),
)
同様に,プレイヤー2の支払額の選択をドロップダウンメニューから選べるようにします.しかし,"choices"を特定することができません.なぜならば,プレイヤー1の支払額に応じてプレイヤー2の選択肢が変わるからです.後ほど,これにどのように対応するのかを示したいと思います.
それでは,Groupクラスに関数を定義しましょう.
def set_payoffs(self):
p1 = self.get_player_by_id(1)
p2 = self.get_player_by_id(2)
p1.payoff = Constants.endowment - self.sent_amount + self.sent_back_amount
p2.payoff = self.sent_amount * Constants.multiplication_factor - self.sent_back_amount
続いて,以下の3ページを定義する必要があります.
プレイヤー1の支払額を決める"Send"ページ プレイヤー2の支払額を決める"Send back"ページ 両プレイヤーが見られる"Result"ページ 各ページにゲームのインストラ クションが表示されるように設定すると,どのようにゲームを進めることができるのか確認できると思うので,そのようにしましょう.
各ページに表示するインストラクションを作るために,"instruction.html"を作りましょう.
{% load otree_tags staticfiles %}
<div class="instructions well well-lg">
<h3 class="panel-sub-heading">
インストラクション
</h3>
<p>
これは2人プレイヤーの信頼ゲームです.
</p>
<p>
はじめにプレイヤーAは {{ Constants.endowment }}を受け取ります.
プレイヤーBは何も受け取りません.
プレイヤーAは {{ Constants.endowment }} の中からいくらをプレイヤーBに渡すかを決めます.
プレイヤーBは,プレイヤーがAの支払額を3倍にしたポイントを受け取ります.
プレイヤーBが3倍になったポイントを受け取ったら,プレイヤーAにいくら渡すかを決めてください.
</p>
</div>
このページは今まで見てきたテンプレートと似ています.ただ,"
"を使うと,自動的に他のテンプレートを挿入することができます.
{% extends "global/Page.html" %}
{% load staticfiles otree_tags %}
{% block title %}
Trust Game: Your Choice
{% endblock %}
{% block content %}
{% include 'my_trust/Instructions.html' %}
<p>
あなたはプレイヤーAです.あなたは {{Constants.endowment}}を持っています.
</p>
{% formfield group.sent_amount with label="プレイヤーBに何ポイント渡しますか?" %}
{% next_button %}
{% endblock %}
続いて,"views.py"を定義します.
class Send(Page):
form_model = models.Group
form_fields = ['sent_amount']
def is_displayed(self):
return self.player.id_in_group == 1
テンプレート内の"
"はview.py内の"form_model"および"form_fields"と一致している必要があります.
また,"is.displayed()"を使って,"Send.html"がプレイヤー1のみに表示されるようにします.プレイヤー2は"Send.html"を表示しないようにする必要があります.
続いて,プレイヤー2はお金をプレイヤー1に支払う画面を用意します.以下がテ ンプレートです.
{% extends "global/Page.html" %}
{% load staticfiles otree_tags %}
{% block title %}
Trust Game: Your Choice
{% endblock %}
{% block content %}
{% include 'my_trust/Instructions.html' %}
<p>
あなたはプレイヤーBです. プレイヤーAはあなたに {{group.sent_amount}}を渡す決定をしました.
and you received {{tripled_amount}}.
</p>
{% formfield group.sent_back_amount with label="あなたはいくらをプレイヤーAに渡しますか?" %}
{% next_button %}
{% endblock %}
以下をviews.pyに記入しなけれ ばいけません.
3倍にしたポイント示す変数"tripled_amount"をテンプレートに通すために,"vars_for_template()"を使います.Djangoはテンプレート上では直接計算をすることはありません.したがって,この数値はPython上で計算をする必要があり,テンプレートに渡してあげる必要があります. プレイヤー1の決定にしたがって,ドロップダウンメニューに動的に変化させるために"sent_back_amount_choices"を定義します.これは"{field_name}_choices"と呼ばれるものです.
class SendBack(Page):
form_model = models.Group
form_fields = ['sent_back_amount']
def is_displayed(self):
return self.player.id_in_group == 2
def vars_for_template(self):
return {
'tripled_amount': self.group.sent_amount * Constants.multiplication_factor
}
def sent_back_amount_choices(self):
return currency_range(
c(0),
self.group.sent_amount * Constants.multiplication_factor,
c(1)
)
結果のページはプレイヤーAとプレイヤーBで少し違いがあります.そこで,今のプレイヤーの"id_in_group"によって条件わけをするために,Djangoで用いられている"
"文を使います.
{% extends "global/Page.html" %}
{% load staticfiles otree_tags %}
{% block title %}
Results
{% endblock %}
{% block content %}
{% if player.id_in_group == 1 %}
<p>
あなたはプレイヤーBに {{ group.sent_amount }}を渡しました.
プレイヤーBはあなたに {{group.sent_back_amount}}を渡しました.
</p>
{% else %}
<p>
プレイヤーAはあなたに {{ group.sent_amount }}を渡しました.
あなたはプレイヤーAに {{group.sent_back_amount}}を渡しました.
</p>
{% endif %}
<p>
したがって,あなたの利得は {{ player.payoff }}です.
</p>
{% include 'my_trust/Instructions.html' %}
{% endblock %}
views.pyでは,単純に以下のように定義します.
class Results(Page):
pass
このゲームでは,2つの待機画面が必要となります.
プレイヤー2はプレイヤー1が支払額を決めるのを待つ必要があります. プレイヤー1はプレイヤー2が支払額を決めるのを待つ必要があります. お互いに決定したあと,利得を計算する必要があります.したがって,"after_all_players_arrive"を使う必要があります.
そこで,これらのページを以下の通り定義します.
class WaitForP1(WaitPage):
pass
class ResultsWaitPage(WaitPage):
def after_all_players_arrive(self):
self.group.set_payoffs()
そして,ページ遷移を以下のように定義します.
page_sequence = [
Send,
WaitForP1,
SendBack,
ResultsWaitPage,
Results,
]
{
'name': 'my_trust',
'display_name': "My Trust Game (simple version from tutorial)",
'num_demo_participants': 2,
'app_sequence': ['my_trust'],
},
コマンドラインに以下の通り入力してデータベースをリセットします.
otree resetdb
otree runserver
起動したら,
http://127.0.0.1:8000
にアクセスしてください.resetdbは新しいアプリケーションを入れたり,models.pyに変更を加えた場合には必ず実施する必要があります.
これは,models.pyは新たにSQLデータベースを作り直す必要があるためです.
ただし,resetdbをするとデータベースが全てリセットされてしまうので,その前にデータを保存しておく必要があります.実用的なレベルで言えば,csvファイルでダウンロードしておくと良いでしょう.
本家本元のURL(このページを翻訳+αをしています):
Last modified 4yr ago