# 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, ]