# Models
from otree.api import *
import random
import settings
import time
author = 'Patricia Zauchner (zauchner@uni-bremen.de)'
doc = """
Redistribution: Redistribution game contains arguments before chat, the chat to find a common decision and
the voting procedure after the chat. This app is the minimal requirement for the experiment.
"""
# Models
class C(BaseConstants):
NAME_IN_URL = 'redistribution'
PLAYERS_PER_GROUP = 5
NUM_ROUNDS = 1
NEEDS = settings.Needs
USUAL_CONSUMPTION = 0.9 # 90% of the income will be consumed
ROUNDS = 5
# New TokenAdd
TOKEN_ADD_TOTAL = settings.TokenAddTotal
TOKEN_ADD_1D_NAME = settings.TokenAdd_1dName # [30 / 5, 30 / 5, 30 / 5, 30 / 5, 30 / 5]
TokenAdd_1dArticle = settings.TokenAdd_1dArticle
TokenAdd_1dArticle2 = settings.TokenAdd_1dArticle2
# Arguments
ARG_MIN_LENGHT = 10
ARG_MAX_LENGHT = 250
# ARG_BEST_TOKEN = 2 # Not used in this experiment.
ARG_TIME = 5
# Time (in minutes)
CHAT_TIME_ACK = settings.minutes_for_chatack
CHAT_TIME_ACK_SEC = CHAT_TIME_ACK * 60
# Graphs
CHAT_HEIGHT = 600 # px
class Subsession(BaseSubsession):
...
def creating_session(subsession: Subsession):
"""" create ID, StartToken, Wealth, and Treatments """
#
try:
subsession.session.vars["StartToken"] = subsession.session.config["StartToken"]
# print("Redistribution ... StartToken taken from session config")
except KeyError:
subsession.session.vars["StartToken"] = settings.StartToken
# print("Redistribution ... StartToken taken from settings")
try:
subsession.session.vars["Taxes"] = subsession.session.config["Taxes"]
# print("Redistribution ... Taxes taken from session config")
except KeyError:
subsession.session.vars["Taxes"] = settings.Taxes
# print("Redistribution ... Taxes taken from settings")
subsession.session.vars["StartTokenPT"] = [] # StartToken --> Brutto Pretaxes
for i in range(0, 5):
subsession.session.vars["StartTokenPT"].append(subsession.session.vars["StartToken"][i] + subsession.session.vars["Taxes"][i])
# Assign Session TokenAdd
# Main Distribution: Gleichverteilung
try:
subsession.session.vars["TokenAdd_1d"] = subsession.session.config["TokenAdd_1d"]
# print("Redistribution ... TokenAdd_1d taken from session config.")
except KeyError:
subsession.session.vars["TokenAdd_1d"] = settings.TokenAdd_1d
# print("Redistribution ... TokenAdd_1d taken from settings.")
#
#
# Copy the group and player id structure of the first app
if "id_matrix" in subsession.session.vars:
subsession.set_group_matrix(subsession.session.vars['id_matrix'])
else:
subsession.group_randomly() # oTree function
subsession.session.vars['id_matrix'] = subsession.get_group_matrix()
print("ID Matrix created in app redistribution", subsession.session.vars['id_matrix'])
#
#
# Take care, here, we also have the group variable "effort" besides the session var "do_effort_task"
# The same code looks a bit different in the other apps
try:
subsession.session.vars["do_effort_task"] = subsession.session.config["do_effort_task"]
except KeyError:
subsession.session.vars["do_effort_task"] = getattr(settings, "do_effort_task", True)
for g in subsession.get_groups():
g.Effort = int(subsession.session.vars["do_effort_task"]) # convert boolean into integer
#
# # Whether arguments should be made
try:
subsession.session.vars["do_arguments_redistribution"] = subsession.session.config["do_arguments_redistribution"]
except KeyError:
subsession.session.vars["do_arguments_redistribution"] = getattr(settings, "do_arguments_redistribution", True)
#
#
try:
subsession.session.vars['do_acceptance'] = subsession.session.config["do_acceptance"]
except KeyError:
subsession.session.vars["do_acceptance"] = getattr(settings, "do_acceptance", False) # If not specified default is False
#
class Group(BaseGroup):
# Treatments
REDIS = models.IntegerField(initial=1) # 0 = DIS, 1 = REDIS ---> FIS: From now on always redis
Effort = models.IntegerField(
doc="Whether initial endowments are assigned based on effort",
initial=1) # 0 = Lottery, 1 = Effort ---> FIS: From now on always effort for core group members
# Chat
Channel_Ack = models.TextField(
doc="Channel name of the chat on the acceptance of the suggested procedure",
initial=-99)
# Election - Acknowledgement
NumElegibleToVoteForAck = models.IntegerField(
doc="Number of group members eligible to vote for acceptance or rejection?",
initial=5
)
nGroupAnerkennung = models.IntegerField(
doc="Number of group members voting for acceptance?",
initial=0
)
GroupAcknowledgement = models.IntegerField(doc="Whether group accepted suggested distribution or not.")
# Arguments
# Number of votes for best argument
BVote_nArgBest_1 = models.IntegerField(doc="Number of group members stating that Player 1s argument was best")
BVote_nArgBest_2 = models.IntegerField(doc="Number of group members stating that Player 2s argument was best")
BVote_nArgBest_3 = models.IntegerField(doc="Number of group members stating that Player 3s argument was best")
BVote_nArgBest_4 = models.IntegerField(doc="Number of group members stating that Player 4s argument was best")
BVote_nArgBest_5 = models.IntegerField(doc="Number of group members stating that Player 5s argument was best")
# Acceptance of arguments - Not used in this experiment
# BVote_nArgAkz_1 = models.IntegerField()
# BVote_nArgAkz_2 = models.IntegerField()
# BVote_nArgAkz_3 = models.IntegerField()
# BVote_nArgAkz_4 = models.IntegerField()
# BVote_nArgAkz_5 = models.IntegerField()
# BVote_nArgAkzNo_1 = models.IntegerField()
# BVote_nArgAkzNo_2 = models.IntegerField()
# BVote_nArgAkzNo_3 = models.IntegerField()
# BVote_nArgAkzNo_4 = models.IntegerField()
# BVote_nArgAkzNo_5 = models.IntegerField()
# Group Functions
def random_grouprank(group: Group):
"""
If Effort = 0, the individuals in the group are assigned random IDs.
This method is called by the Intro-WaitPage.
I won't need this for the experiment, but it's good for pretesting.
"""
randomnumber = random.sample(list(range(1, 6)), 5)
for p in group.get_players():
p.GroupRank = randomnumber[p.id_in_group - 1]
p.participant.vars["GroupRank"] = p.GroupRank
def effort_grouprank(group: Group):
"""
Create GroupRank based on prior effort.
If Effort = 1, the individuals in the group are assigned IDs according to their effort.
This method is called by the intro_paper_instruction-WaitPage.
"""
all_group_effort_new = []
for p in group.get_players():
all_group_effort_new.append(p.Effort_points - (p.Minus_points * 0.0001) - (p.id_in_group * 0.000001))
rankgroupeffort = [sorted(all_group_effort_new).index(x) for x in all_group_effort_new]
# Old command: rankdata(all_group_effort_new) from scipy.stats import rankdata
for p in group.get_players():
p.GroupRank = int(rankgroupeffort[p.id_in_group - 1]) + 1
# Calculated differently, because rankdata started with 1, this however, with 0
p.participant.vars["GroupRank"] = p.GroupRank
def define_start_token(group: Group):
""" Get start token based on group ranks """
for p in group.get_players():
# For specific positions
p.StartToken = group.session.vars["StartToken"][p.GroupRank - 1]
p.StartTokenPT = group.session.vars["StartTokenPT"][p.GroupRank - 1]
p.Taxes = group.session.vars["Taxes"][p.GroupRank - 1]
p.TokenAdd_1d = group.session.vars["TokenAdd_1d"][p.GroupRank - 1]
# For all
p.SumRoundIncome_1d = p.StartToken + p.TokenAdd_1d
def nickname(group: Group):
""" Create nicknames for chat. """
group.Channel_Ack = str(group.id_in_subsession) + "_Ack"
rand = random.sample(list(range(0, 5)), 5)
for p in group.get_players():
p.Nickname = "Player " + str(p.GroupRank)
p.participant.vars["randomnicknamecolors"] = rand
# Calc Arguments
# Count acceptance (not used in this experiment)
# def calc_acc_arg(group: Group, argpart):
# if group.session.vars['do_acceptance']:
# # argpart are either a_vote, redistribution, etc.
# group_acc_base = argpart + "_nArgAkz_"
# group_accNo_base = argpart + "_nArgAkzNo_"
# ind_acc_base = argpart + "_ArgAkz_"
# ind_accNo_base = argpart + "_ArgAkzNo_"
#
# for i in range(1, 6):
# group_acc_mod = group_acc_base + str(i)
# group_accNo_mod = group_accNo_base + str(i)
# ind_acc_mod = ind_acc_base + str(i)
# ind_accNo_mod = ind_accNo_base + str(i)
# # Calculations
# setattr(group, group_acc_mod,
# sum((vars(p)[ind_acc_mod]) for p in group.get_players() if vars(p)[ind_acc_mod] is not None))
# setattr(group, group_accNo_mod, 5 - vars(group)[group_acc_mod])
def calc_best_arg(group: Group, argpart):
""" Calculate the best argument.
'argpart' is either "AVote", "BVote", "Rej" or "Acc" """
group_best_base = argpart + "_nArgBest_"
ind_best_base = argpart + "_ArgBest_"
for i in range(1, 6):
group_best_mod = group_best_base + str(i)
ind_best_mod = ind_best_base + str(i)
# Calculations
setattr(group, group_best_mod, sum((vars(p)[ind_best_mod]) for p in group.get_players()))
# print(sum((vars(p)[ind_best_mod]) for p in group.get_players()))
# Assign count of best argument to subjects.
listofbest = [] # Für Übersicht
for p in group.get_players():
setattr(p, argpart + "_nArgBest", vars(group)[group_best_base + str(p.GroupRank)])
listofbest.append(vars(p)[argpart + "_nArgBest"])
# Who won best argument?
winners = [i for i, j in enumerate(listofbest) if j == max(listofbest)]
for p in group.get_players():
# If winner
if (p.GroupRank - 1) in winners and len(winners) <= 2: # There are max 2 winners.
setattr(p, argpart + "_ArgBest", 1)
# setattr(p, argpart + "_ArgToken", C.ARG_BEST_TOKEN) # Not used in this experiment.
if len(winners) == 1:
setattr(p, argpart + "_ArgBestSingle", 1)
else:
setattr(p, argpart + "_ArgBestSingle", 2)
# If not winner
else:
setattr(p, argpart + "_ArgBest", 0)
# setattr(p, argpart + "_ArgToken", 0)
setattr(p, argpart + "_ArgBestSingle", 0)
# p.participant.vars[argpart + "_ArgToken"] = getattr(p, argpart + "_ArgToken")
# Initial/Suggested redistribution: (graphs und wealth)
def calc_wealthSugg(group: Group):
""" Calculate wealth for suggested distribution.
No graphs, only numbers. """
for p in group.get_players():
# For Start - No Redistribution
if (p.StartTokenPT * C.USUAL_CONSUMPTION) <= C.NEEDS:
p.ConsumptionNoDis = C.NEEDS
p.WealthNoDis_1R = p.StartTokenPT - C.NEEDS
else:
p.ConsumptionNoDis = p.StartTokenPT * C.USUAL_CONSUMPTION
p.WealthNoDis_1R = p.StartTokenPT * (1-C.USUAL_CONSUMPTION)
p.WealthNoDis_5R = p.WealthNoDis_1R * 5
# For Equality
if ((p.StartToken + p.TokenAdd_1d) * C.USUAL_CONSUMPTION) <= C.NEEDS:
p.Consumption_1d = C.NEEDS
p.Wealth_1d_1R = p.StartToken - C.NEEDS + p.TokenAdd_1d
else:
p.Consumption_1d = (p.StartToken + p.TokenAdd_1d) * C.USUAL_CONSUMPTION
p.Wealth_1d_1R = (p.StartToken + p.TokenAdd_1d) * (1-C.USUAL_CONSUMPTION)
p.Wealth_1d_5R = p.Wealth_1d_1R * 5
def results_graph_no_dis(group: Group):
""" Make numbers for graph if there was no distribution. """
series_Start_PT = []
series_Cumulative = []
series_highest_lowest = []
series_WealthAt1 = []
series_WealthAt5 = []
wealth_min = 0
wealth_max = 0
for p in group.get_players():
series_Start_PT.append({
"name": p.GroupRank,
"y": p.StartTokenPT})
# min/max Runde 1
if p.WealthNoDis_1R < wealth_min:
wealth_min = p.WealthNoDis_1R
if p.WealthNoDis_1R > wealth_max:
wealth_max = p.WealthNoDis_1R
# min/max Rund e5
if p.WealthNoDis_5R < wealth_min:
wealth_min = p.WealthNoDis_5R
if p.WealthNoDis_5R > wealth_max:
wealth_max = p.WealthNoDis_5R
# Wealth
series_WealthAt1.append({
"name": p.GroupRank,
"y": p.WealthNoDis_1R})
series_WealthAt5.append({
"name": p.GroupRank,
"y": p.WealthNoDis_1R * 5})
# Others
cumulativedata = [0,
p.WealthNoDis_1R * 1,
p.WealthNoDis_1R * 2,
p.WealthNoDis_1R * 3,
p.WealthNoDis_1R * 4,
p.WealthNoDis_1R * 5]
series_Cumulative.append({
"name": p.GroupRank,
"data": cumulativedata})
series_highest_lowest.append(p.WealthNoDis_5R)
return {
"series_StartToken_PT": series_Start_PT,
'highcharts_series': series_Cumulative,
"MinValue": min_max_graph(series_highest_lowest)[0],
"MaxValue": min_max_graph(series_highest_lowest)[1],
# Wealth
"WealthAt1": series_WealthAt1,
"WealthAt5": series_WealthAt5,
"wealth_min": wealth_min,
"wealth_max": wealth_max,
}
def results_graph_1d(group: Group):
""" Make numbers for graph for suggested distribution. """
series_Start_PT = []
series_Start = []
series_Taxes = []
series_TokenAdd = []
series_Income = []
series_Cumulative = []
series_WealthAt1 = []
series_WealthAt5 = []
series_highest_lowest = []
wealth_min = 0
wealth_max = 0
for p in group.get_players():
series_Start_PT.append(p.StartTokenPT)
series_TokenAdd.append({
"name": p.GroupRank,
"y": p.TokenAdd_1d})
series_Start.append({
"name": p.GroupRank,
"y": p.StartToken})
series_Taxes.append({
"name": p.GroupRank,
"y": p.Taxes})
# Wealth
series_WealthAt1.append({
"name": p.GroupRank,
"y": p.Wealth_1d_1R})
series_WealthAt5.append({
"name": p.GroupRank,
"y": p.Wealth_1d_1R * 5})
cumulativedata = [0,
p.Wealth_1d_1R * 1,
p.Wealth_1d_1R * 2,
p.Wealth_1d_1R * 3,
p.Wealth_1d_1R * 4,
p.Wealth_1d_1R * 5
]
if p.Wealth_1d_1R < wealth_min:
wealth_min = p.Wealth_1d_1R
if p.Wealth_1d_1R > wealth_max:
wealth_max = p.Wealth_1d_1R
if p.Wealth_1d_5R < wealth_min:
wealth_min = p.Wealth_1d_5R
if p.Wealth_1d_5R > wealth_max:
wealth_max = p.Wealth_1d_5R
series_Cumulative.append({
"name": p.GroupRank,
"data": cumulativedata})
series_highest_lowest.append(p.Wealth_1d_1R * 5)
series_Income.append(p.StartToken + p.TokenAdd_1d)
return {
"series_StartToken_PT": series_Start_PT,
"StartToken": series_Start,
"Taxes": series_Taxes,
"TokenAdd": series_TokenAdd,
"Cumulative": series_Cumulative,
"WealthAt1": series_WealthAt1,
"WealthAt5": series_WealthAt5,
"MinValue_B": min_max_graph(series_highest_lowest)[0],
"MaxValue_B": min_max_graph(series_highest_lowest)[1],
"MinValue_A": 0,
"MaxValue_A": min_max_graph(series_Income)[1],
"wealth_min": wealth_min,
"wealth_max": wealth_max,
}
def calc_ack_result(group: Group):
""" Calculate the voting results for acceptance of the suggested distribution. """
group.nGroupAnerkennung = 0
for p in group.get_players():
if p.AckVote == 1:
group.nGroupAnerkennung += 1
if group.nGroupAnerkennung == group.NumElegibleToVoteForAck:
group.GroupAcknowledgement = 1
else:
group.GroupAcknowledgement = 0
for p in group.get_players():
p.participant.vars["GroupAcknowledgement"] = p.group.GroupAcknowledgement
def min_max_graph(list_):
""" Calculate the minimun and maximum values for the graph. """
if min(list_) >= 0:
minlist = -5
maxlist = max(list_) + 3
else:
minlist = min(list_) - 5
maxlist = max(list_) + 3
return minlist, maxlist
def calc_points(player):
try:
# Note. Here we don't work with participant.vars, in order to have the points also in the data set.
# Points
player.countingpoints = player.participant.vars.get("countingpoints", 0)
player.addpoints = player.participant.vars.get("addpoints", 0)
player.subpoints = player.participant.vars.get("subpoints", 0)
player.trivialpoints = player.participant.vars.get("trivialpoints", 0)
player.sliderpoints = player.participant.vars.get("sliderpoints", 0)
# Mistakes
player.addmistakes = player.participant.vars.get("addmistakes", 0)
player.sub2mistakes = player.participant.vars.get("sub2mistakes", 0)
player.countingmistakes = player.participant.vars.get("countingmistakes", 0)
# Sum
player.Effort_points = player.countingpoints + player.subpoints + player.addpoints + player.trivialpoints + player.sliderpoints
player.Minus_points = player.sub2mistakes + player.addmistakes + player.countingmistakes
except KeyError:
# Calculate points for testing the app
player.countingpoints = 99
player.subpoints = 99
player.addpoints = 99
player.trivialpoints = 99
player.sliderpoints = 99
print("Attention: Effort variables are not here although it is an effort treatment.")
player.Effort_points = random.randrange(200000)
player.Minus_points = random.randrange(200000)
class Player(BasePlayer):
GroupRank = models.IntegerField(doc="GV: Rank in group")
Effort_points = models.FloatField(doc="Points in the effort task")
Minus_points = models.FloatField(doc="Minus points in the effort task")
# Initial endowments and taxes
StartToken = models.FloatField(doc="StartToken after deduction of taxes")
StartTokenPT = models.FloatField(doc="StartToken pre taxes; formally coded as StartTokenAlt")
Taxes = models.FloatField(doc="Taxes to be deducted from StartTokenPT")
# Token and wealth in suggested distributions
TokenAdd_1d = models.FloatField(
doc="TokenAdd as suggested by Experimenter")
ConsumptionNoDis = models.FloatField(
doc="Initial Consumption = no Redistribution")
Consumption_1d = models.FloatField(
doc="Initial Consumption = with TokenAdd as suggested by Experimenter")
SumRoundIncome_1d = models.FloatField(
doc="Total Income Token minus Taxes but with TokenAdd as suggested by Experimenter")
WealthNoDis_1R = models.FloatField(
doc="Wealth for 1 Round - No Redistribution")
WealthNoDis_5R = models.FloatField(
doc="Wealth for 5 Rounds - No Redistribution")
Wealth_1d_1R = models.FloatField(
doc="Wealth for 1 Round - Suggested Distribution")
Wealth_1d_5R = models.FloatField(
doc="Wealth for 5 Rounds - Suggested Distribution")
# Election results for best argument for acceptance/rejection - winners and tokens
BVote_nArgBest = models.IntegerField(doc="Number of votes for best vote")
BVote_ArgBest = models.IntegerField(doc="Whether participant is one of the best-vote winners.")
# BVote_ArgToken = models.IntegerField(initial=0, doc="Token für the argument.") # Not used in this experiment
BVote_ArgBestSingle = models.IntegerField(doc="Whether participant is the only best-vote winner.")
# Votes for acceptance of the procedures
AckVote = models.IntegerField(
doc="Vote for acceptance or rejection of the distribution procedure. Former name: iAnerkennungVerfahren",
choices=[
[1, C.TOKEN_ADD_1D_NAME + ' soll anerkannt werden'],
[0, C.TOKEN_ADD_1D_NAME + ' soll nicht anerkannt werden'], ],
widget=widgets.RadioSelect,
)
# Arguments and choice of the best argument
# Individual arguments
BVote_YesNo = models.IntegerField(
doc="Acceptance or rejection of suggested procedure. Will define first part of the argument. "
"Former variable name: AnerkennungPrivat."
"Take care, this variable is recoded to boolean in py",
choices=[
[1, 'Ich erkenne' + C.TokenAdd_1dArticle + ' an'],
[2, 'Ich erkenne' + C.TokenAdd_1dArticle + ' nicht an'], ],
widget=widgets.RadioSelect
)
BVote_YesNoString = models.TextField(
doc="Specified start of the argument"
)
YesNoArg_BVote = models.TextField(
doc="Argument for Acceptance/Rejection of the suggested distribution. Former variable name: Argument",
label="",
initial="",
max_length=250
)
# BVote --> Accept arguments - Private arguments at the beginning (not used in this experiment)
# BVote_ArgAkz_1 = models.IntegerField(
# choices=[
# [1, "Ich akzeptiere das Argument"],
# [0, "Ich akzeptiere das Argument nicht"],
# ],
# widget=widgets.RadioSelect,
#
# )
# BVote_ArgAkz_2 = models.IntegerField(
# choices=[
# [1, "Ich akzeptiere das Argument"],
# [0, "Ich akzeptiere das Argument nicht"],
# ],
# widget=widgets.RadioSelect,
#
# )
# BVote_ArgAkz_3 = models.IntegerField(
# choices=[
# [1, "Ich akzeptiere das Argument"],
# [0, "Ich akzeptiere das Argument nicht"],
# ],
# widget=widgets.RadioSelect,
#
# )
# BVote_ArgAkz_4 = models.IntegerField(
# choices=[
# [1, "Ich akzeptiere das Argument"],
# [0, "Ich akzeptiere das Argument nicht"],
# ],
# widget=widgets.RadioSelect,
#
# )
# BVote_ArgAkz_5 = models.IntegerField(
# choices=[
# [1, "Ich akzeptiere das Argument"],
# [0, "Ich akzeptiere das Argument nicht"],
# ],
# widget=widgets.RadioSelect,
#
# )
# Vote for best argument
BVote_ArgBest_1 = models.BooleanField(
doc="Individual votes for best argument - for player 1",
blank=True, initial=False)
BVote_ArgBest_2 = models.BooleanField(
doc="Individual votes for best argument - for player 2",
blank=True, initial=False)
BVote_ArgBest_3 = models.BooleanField(
doc="Individual votes for best argument - for player 3",
blank=True, initial=False)
BVote_ArgBest_4 = models.BooleanField(
doc="Individual votes for best argument - for player 4",
blank=True, initial=False)
BVote_ArgBest_5 = models.BooleanField(
doc="Individual votes for best argument - for player 5",
blank=True, initial=False)
# Helping variables - chat
BVote_ChatStart = models.IntegerField(
doc="Start of redistribution chat. Since epoch, in UTC",
null=True, default=-99)
Nickname = models.TextField(doc="Nickname in chat")
# Points in effort task
countingpoints = models.FloatField(doc="Achieved points in the counting task")
subpoints = models.FloatField(doc="Achieved points in the subtraction task")
addpoints = models.FloatField(doc="Achieved points in the addition task")
trivialpoints = models.FloatField(doc="Achieved points in the questions task")
sliderpoints = models.FloatField(doc="Achieved points in the slider task")
sub2mistakes = models.FloatField(doc="")
addmistakes = models.FloatField(doc="")
countingmistakes = models.FloatField(doc="")
# Functions
# Variables for admin report
def vars_for_admin_report(subsession):
# Treatment info
groupnumberlist = []
for g in subsession.get_groups():
groupnumberlist.append(g)
# Detailed player-treatment info
list_of_groupmembership = []
for p in subsession.get_players():
group = "Group: " + str(p.group.id_in_subsession)
name = " - Participant: " + str(p.participant.label)
list_of_groupmembership.append(group + name)
list_of_groupmembership = sorted(list_of_groupmembership)
# Decisions and treatments in game
# Group acceptance
listofgroupack = []
for g in subsession.get_groups():
try:
listofgroupack.append(g.GroupAcknowledgement)
except:
pass
return {
"participantsinlist": list_of_groupmembership,
"groupnumberlist": groupnumberlist,
"groupAcknowledgement": listofgroupack,
}
# Pages
class BeforeAppStartWP(WaitPage):
""" Wait for all and assign start token """
# Assign Start Token
@staticmethod
def after_all_players_arrive(group: Group):
print(
"------------------------------------- Start Redistribution App ------------------------------------------------")
group.get_players()
if group.Effort == 0:
random_grouprank(group)
define_start_token(group) # Calculate StartToken, Taxes, etc.
calc_wealthSugg(group) # Calculate wealth for suggested distribution
nickname(group) # Create nicknames for chat
elif group.Effort == 1: # Alles gleich wie bei = 0 nur dass random id durch Leistungstestergebnisse ersetzt wird.
# Calculate Personal Effort Points
for p in group.get_players():
calc_points(p)
effort_grouprank(group)
define_start_token(group) # Calculate startToken, taxes, etc.
calc_wealthSugg(group) # Calculate wealth for suggested distribution
nickname(group) # Create nicknames for chat
# Change id_in_group to GroupRank
for p in group.get_players():
p.id_in_group = p.GroupRank
class AppIntro(Page):
""" Intro-Page that is only shown if the effort task was activated """
@staticmethod
def is_displayed(player):
return player.session.vars["do_effort_task"]
@staticmethod
def vars_for_template(player):
return {
"countingpointsThere": "countingpoints" in player.participant.vars,
"subpointsThere": "subpoints" in player.participant.vars,
"addpointsThere": "addpoints" in player.participant.vars,
"trivialpointsThere": "trivialpoints" in player.participant.vars,
"sliderpointsThere": "sliderpoints" in player.participant.vars
}
# Info at the beginning and rounds
class Infografiken1(Page):
""" Show initial distribution of endowments """
template_name = 'redistribution/DisInfos/Infografiken1.html'
@staticmethod
def vars_for_template(player):
return results_graph_no_dis(player.group)
class Infografiken2(Page):
""" Show initial distribution of endowments and the needs threshold """
template_name = 'redistribution/DisInfos/Infografiken2.html'
@staticmethod
def vars_for_template(player):
return results_graph_no_dis(player.group)
class Infografiken3(Page):
""" Show wealth after round 1 and round 5 """
template_name = 'redistribution/DisInfos/Infografiken3.html'
@staticmethod
def vars_for_template(player):
dictionary = results_graph_no_dis(player.group)
return dictionary
class Infografiken4_RD(Page):
""" Show how much each group member must contribute to the common pot """
template_name = 'redistribution/DisInfos/Infografiken4_RD.html'
@staticmethod
def vars_for_template(player):
return results_graph_1d(player.group)
class Infografiken5(Page):
""" Show how much each group member gets from the common pot if the suggested distribution were played """
template_name = 'redistribution/DisInfos/Infografiken5.html'
@staticmethod
def vars_for_template(player):
return results_graph_1d(player.group)
class Rounds6d1(Page):
""" Show detailed calculation of the suggested distribution scenario and graph for one round """
template_name = 'redistribution/DisInfos/Rounds6d1.html'
@staticmethod
def vars_for_template(player):
return results_graph_1d(player.group)
class Rounds6d2(Page):
""" Show detailed calculation of the suggested distribution scenario and graph for five rounds """
template_name = 'redistribution/DisInfos/Rounds6d2.html'
# @staticmethod
# def vars_for_template(player):
# return results_graph_1d(player.group)
@staticmethod
def vars_for_template(player):
# print("WealthNoDis_1R", player.Wealth_1d_1R)
# print("WealthNoDis_5R", player.Wealth_1d_5R)
dictionary = results_graph_1d(player.group)
dictionary["own5Rounds"] = player.Wealth_1d_1R*5
dictionary["own1Rounds"] = player.Wealth_1d_1R
return dictionary
# B Vote - > Private arguments at the beginning and chat
class BVote_Arg(Page):
""" Enter the argument for acceptance/rejection of the suggested distribution """
template_name = 'redistribution/BVote/BVote_Arg.html'
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"]
form_model = "player"
form_fields = ["BVote_YesNo", "YesNoArg_BVote"]
# Timeout for arguments
timer_text = 'Verbleibende Zeit (in Sek.):'
@staticmethod
def get_timeout_seconds(player):
# second argument of get()-method is the default---in this case the respective value from the settings
return player.session.config.get("minutes_for_arguments",
settings.minutes_for_arguments) * 60
@staticmethod
def vars_for_template(player):
return {
"secondsTimerIsShown": player.session.config.get("secondsTimerIsShown",
settings.secondsTimerIsShown) # the last 60 seconds when the timer is shown
}
@staticmethod
def before_next_page(player, timeout_happened):
if not timeout_happened:
if player.BVote_YesNo == 1:
player.BVote_YesNoString = "Ich bin dafür, weil ..."
elif player.BVote_YesNo == 2:
player.BVote_YesNoString = "Ich bin dagegen, weil ..."
else:
player.BVote_YesNoString = "Error!" # Pretest only.
if timeout_happened:
if player.BVote_YesNo == 1:
player.BVote_YesNoString = "Ich bin dafür, weil ..."
if player.BVote_YesNo == 2:
player.BVote_YesNoString = "Ich bin dagegen, weil ..."
if player.BVote_YesNo == 0: # Nothing entered
player.BVote_YesNoString = ""
player.BVote_YesNo = -99
# Set argument
player.YesNoArg_BVote = player.YesNoArg_BVote + " (Zeit abgelaufen)"
# Now set to boolean:
if player.BVote_YesNo == 2:
player.BVote_YesNo = 0
# FOR PRESENTATION ONLY!!! !
# self.player.BVote_YesNo = 0
# self.player.YesNoArg_BVote = "xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx " \
# "xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx " \
# "xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx" \
# " xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx " \
# "xxx xxx xxx xxx xxx xxx xxx xxx xxx xx"
class WaitForArgs(WaitPage):
""" Waiting for all group members to enter their arguments for/against acceptance of the suggested distribution """
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"]
class WaitForVotes(WaitPage):
""" Waiting for all group members to vote for/against acceptance of the suggested distribution """
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"]
class BVote_RateBestArg1(Page):
""" Acceptance of arguments """
template_name = 'redistribution/BVote/BVote_RateBestArg1.html'
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"] and player.session.vars['do_acceptance']
form_model = "player"
@staticmethod
def get_form_fields(player):
field_list = []
for i in range(1, 6):
if player.GroupRank != i:
field_list.append("BVote_ArgAkz_" + str(i))
return field_list
@staticmethod
def vars_for_template(player):
""" A person cannot accept their own argument. Their assigned variable hence gets a value of -98. """
if player.GroupRank == 1:
player.BVote_ArgAkz_1 = -98
elif player.GroupRank == 2:
player.BVote_ArgAkz_2 = -98
elif player.GroupRank == 3:
player.BVote_ArgAkz_3 = -98
elif player.GroupRank == 4:
player.BVote_ArgAkz_4 = -98
elif player.GroupRank == 5:
player.BVote_ArgAkz_5 = -98
class BVote_RateBestArg2(Page):
""" Vote for best argument """
template_name = 'redistribution/BVote/BVote_RateBestArg2.html'
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"]
form_model = "player"
@staticmethod
def get_form_fields(player):
field_list = []
for i in range(1, 6):
if player.GroupRank != i:
field_list.append("BVote_ArgBest_" + str(i))
return field_list
class BVote_BestUebersicht(Page):
""" Show results for acceptances and votes for best argument """
template_name = 'redistribution/BVote/BVote_BestUebersicht.html'
@staticmethod
def is_displayed(player):
return player.session.vars["do_arguments_redistribution"]
@staticmethod
def vars_for_template(player):
calc_best_arg(player.group, "BVote")
# self.group.calc_acc_arg("BVote") # Not used in this experiment
class Ack_Chat_0WP_Before(WaitPage):
""" WaitPage before the chat starts """
@staticmethod
def after_all_players_arrive(group: Group):
for p in group.get_players():
p.BVote_ChatStart = int(round(time.time()))
# Ack - Chat und Vote about Acknowledgement
class Ack_Chat_Ack(Page):
""" Chat about the acceptance of the suggested distribution """
template_name = 'redistribution/Ack/Chat_Acknowledgement.html'
timeout_seconds = C.CHAT_TIME_ACK_SEC + 3
#
# FOR PRESENTATION ONLY!!! !
# @staticmethod
# def vars_for_template(player):
# player.YesNoArg_BVote = "Ich bin dagegen, weil ... xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx xxx"
#
class AckVote(Page):
""" Voting for the acceptance of the suggested distribution """
template_name = 'redistribution/Ack/Ack_Vote.html'
form_model = "player"
form_fields = ['AckVote']
class AckResultWP(WaitPage):
""" Waiting for the voting results for the acceptance of the suggested distribution """
# template_name = 'redistribution/Ack/Ack_ResultsWP.html'
@staticmethod
def after_all_players_arrive(group: Group):
calc_ack_result(group)
class AckResult(Page):
""" Voting results for the acceptance of the suggested distribution """
template_name = 'redistribution/Ack/Ack_Result.html'
page_sequence = [
BeforeAppStartWP, # Should always be shown!
AppIntro,
#
Infografiken1,
Infografiken2,
Infografiken3,
Infografiken4_RD,
Infografiken5,
Rounds6d1,
Rounds6d2,
#
#
BVote_Arg,
WaitForArgs,
BVote_RateBestArg2,
WaitForVotes,
BVote_BestUebersicht,
#
#
# Chat and Voting
Ack_Chat_0WP_Before,
Ack_Chat_Ack,
AckVote,
AckResultWP,
AckResult,
]