# Models from otree.api import * import random from collections import Counter import time import settings author = 'Patricia Zauchner (zauchner@uni-bremen.de)' doc = """ Rejection: Finding a new Distribution if the group rejected the suggested distribution procedure. """ class C(BaseConstants): NAME_IN_URL = 'rejection' PLAYERS_PER_GROUP = 5 NUM_ROUNDS = 1 NEEDS = settings.Needs USUAL_CONSUMPTION = 0.9 # 90% of the income will be consumed TOKEN_ADD_TOTAL = settings.TokenAddTotal TokenAdd_1dArticle = settings.TokenAdd_1dArticle # Arguments ARG_MIN_LENGHT = 10 ARG_MAX_LENGHT = 250 ARG_TIME = 5 CHAT_HEIGHT = 600 # Time (in minutes) CHAT_TIME_DISTRIBUTION = settings.minutes_for_chrej1 # Formerly known as ChatTime_Verteilung CHAT_TIME_DISTRIBUTION_CORR = settings.minutes_for_chrej2 # Formerly known as ChatTime_VerteilungKorr CHAT_TIME_DISTRIBUTION_CORRSEK = CHAT_TIME_DISTRIBUTION_CORR * 60 # Formerly known as ChatTime_VerteilungKorrSek class Subsession(BaseSubsession): ... def creating_session(subsession: Subsession): """" create ID, StartToken, Wealth, and Treatments """ # try: subsession.session.vars["StartToken"] = subsession.session.config["StartToken"] # print("Rejection ... StartToken taken from session config") except KeyError: subsession.session.vars["StartToken"] = settings.StartToken # print("Rejection ... StartToken taken from settings") try: subsession.session.vars["Taxes"] = subsession.session.config["Taxes"] # print("Rejection ... Taxes taken from session config") except KeyError: subsession.session.vars["Taxes"] = settings.Taxes # print("Rejection ... Taxes taken from settings") subsession.session.vars["StartTokenPT"] = [] # StartToken --> Brutto pre taxes for i in range(0, 5): subsession.session.vars["StartTokenPT"].append(subsession.session.vars["StartToken"][i] + subsession.session.vars["Taxes"][i]) # # # 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 rejection", subsession.session.vars['id_matrix']) # # # Whether arguments should be made try: subsession.session.vars['do_arguments_rejection'] = subsession.session.config["do_arguments_rejection"] # print("Rejection ... do_arguments_rejection in session.config is", # subsession.session.vars['do_arguments_rejection']) except KeyError: subsession.session.vars["do_arguments_rejection"] = getattr(settings, "do_arguments_rejection", True) # # try: subsession.session.vars['do_acceptance'] = subsession.session.config["do_acceptance"] except KeyError: subsession.session.vars["do_acceptance"] = getattr(settings, "do_acceptance", False) # class Group(BaseGroup): REDIS = models.IntegerField(initial=1) # 0 = DIS, 1 = REDIS ---> FIS: From now on always redis # Effort is not needed in this app GroupAcknowledgement = models.IntegerField(doc="GV: Whether group accepted suggested distribution or not.") # GroupRank und StartToken zuweisen # StartToken zuweisen # Chat Channels und Nickname # Chat Channels Channel_DisProcedure = models.TextField(doc="Chat channel") Channel_DisProcedureCorr = models.TextField(doc="Chat channel") # Arguments # Number of votes for best argument Rej_nArgBest_1 = models.IntegerField(doc="Number of group members stating that Player 1s argument was best") Rej_nArgBest_2 = models.IntegerField(doc="Number of group members stating that Player 2s argument was best") Rej_nArgBest_3 = models.IntegerField(doc="Number of group members stating that Player 3s argument was best") Rej_nArgBest_4 = models.IntegerField(doc="Number of group members stating that Player 4s argument was best") Rej_nArgBest_5 = models.IntegerField(doc="Number of group members stating that Player 5s argument was best") # Acceptance of arguments - Not used in this experiment # Rej_nArgAkz_1 = models.IntegerField() # Rej_nArgAkz_2 = models.IntegerField() # Rej_nArgAkz_3 = models.IntegerField() # Rej_nArgAkz_4 = models.IntegerField() # Rej_nArgAkz_5 = models.IntegerField() # # Rej_nArgAkzNo_1 = models.IntegerField() # Rej_nArgAkzNo_2 = models.IntegerField() # Rej_nArgAkzNo_3 = models.IntegerField() # Rej_nArgAkzNo_4 = models.IntegerField() # Rej_nArgAkzNo_5 = models.IntegerField() # Count acceptance (not used in this experiment) # def calc_acc_arg(self, argpart): # if self.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(self, group_acc_mod, # sum((vars(p)[ind_acc_mod]) for p in self.get_players() if vars(p)[ind_acc_mod] is not None)) # setattr(self, group_accNo_mod, 5 - vars(self)[group_acc_mod]) # Choice for new distribution NumElegibleToVoteNewDis = models.IntegerField( doc="Number of group members eligible to vote", initial=5) # Choice for new distribution - Reached/TokenAdd_New/SumRoundIncome/WealthNewDis/WealthNewDis_5R" found_new_distribution = models.IntegerField( # Old variable name: NeueVerteilungErreicht doc="Whether new distribution was found by the group in the first try.", initial=0) found_new_distribution_corr = models.IntegerField( # Old variable name: NeueVerteilungErreicht_Corr doc="Whether new distribution was found by the group in the second try.", initial=0) # Election for distribution ELECTORAL RESULT - TokenAdd_New_1/5" # First try TokenAdd_New_1 = models.FloatField( doc="Voting result in first try. Assingment to player 1.", ) TokenAdd_New_2 = models.FloatField( doc="Voting result in first try. Assingment to player 2.", ) TokenAdd_New_3 = models.FloatField( doc="Voting result in first try. Assingment to player 3.", ) TokenAdd_New_4 = models.FloatField( doc="Voting result in first try. Assingment to player 4.", ) TokenAdd_New_5 = models.FloatField( doc="Voting result in first try. Assingment to player 5.", ) # Second try TokenAdd_New_corr_1 = models.FloatField( doc="Voting result in second try. Assingment to player 1.", ) TokenAdd_New_corr_2 = models.FloatField( doc="Voting result in second try. Assingment to player 2.", ) TokenAdd_New_corr_3 = models.FloatField( doc="Voting result in second try. Assingment to player 3.", ) TokenAdd_New_corr_4 = models.FloatField( doc="Voting result in second try. Assingment to player 4.", ) TokenAdd_New_corr_5 = models.FloatField( doc="Voting result in second try. Assingment to player 5.", ) # Group Functions def nickname(group: Group): group.Channel_DisProcedure = str(group.id_in_subsession) + "_DisProc" group.Channel_DisProcedureCorr = str(group.id_in_subsession) + "_DisProcCorr" rand = random.sample(list(range(0, 5)), 5) for p in group.get_players(): p.Nickname = "Player " + str(p.GroupRank) if "randomnicknamecolors" not in p.participant.vars: p.participant.vars["randomnicknamecolors"] = rand # CountSame - individual level . Count Number of same inputs def abzahlen(group: Group, Correction): # Neue Version """ How many group members entered the same numbers? Old function name in ztree: Countsame. If this function is called after the Correction chat, enter "Corr" when calling the function. Wird in Pages --> Rej_5_Chat_DistributionProcedure_2WP_After aufgerufen """ corr = "" if Correction == "Corr": corr = "_" + "corr" listofallvotes = [] for p in group.get_players(): listofallvotes.append([ vars(p)["iTokenAddVoteFor" + corr + "_" + str(1)], vars(p)["iTokenAddVoteFor" + corr + "_" + str(2)], vars(p)["iTokenAddVoteFor" + corr + "_" + str(3)], vars(p)["iTokenAddVoteFor" + corr + "_" + str(4)], vars(p)["iTokenAddVoteFor" + corr + "_" + str(5)] ]) new_listofallvotes = map(tuple, listofallvotes) final_count = Counter(new_listofallvotes) voteergebnis = [k for k, v in final_count.items() if v >= 3] voteergebnis = [list(row) for row in voteergebnis] # Distribution was achieved? if not voteergebnis: # If empty, then no distribution was found setattr(group, "found_new_distribution" + corr, 0) elif voteergebnis[0] == [0, 0, 0, 0, 0]: print("Rejection ... No distribution found because skipped") setattr(group, "found_new_distribution" + corr, 0) else: setattr(group, "found_new_distribution" + corr, 1) # Save group election result for i in range(1, 6): setattr(group, "TokenAdd_New" + corr + "_" + str(i), voteergebnis[0][i - 1]) # Save result for individuals for p in group.get_players(): for i in range(1, 6): if p.GroupRank == i: p.TokenAdd = getattr(group, "TokenAdd_New" + corr + "_" + str(i)) # Calculate Token Add # Calculate Roundincome after Tokenadd and Needs-Satisfaction for p in group.get_players(): p.SumRoundIncome = p.StartToken + p.TokenAdd if p.SumRoundIncome * C.USUAL_CONSUMPTION < C.NEEDS: p.ConsumptionFinal = C.NEEDS p.WealthNewDis_1R = p.SumRoundIncome - C.NEEDS else: p.ConsumptionFinal = p.SumRoundIncome * C.USUAL_CONSUMPTION p.WealthNewDis_1R = p.SumRoundIncome * (1-C.USUAL_CONSUMPTION) p.WealthNewDis_5R = p.WealthNewDis_1R * 5 p.participant.vars["WealthNewDis_5R"] = p.WealthNewDis_5R 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] 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.ArgBestToken) 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") def results_graph(group: Group): """ Called in Pages - class Rej_9_Rounds(Page)""" series_Start = [] series_TokenAdd = [] series_Income = [] series_Cumulative = [] series_highest_lowest = [] series_WealthAt1 = [] series_WealthAt5 = [] wealth_min = 0 wealth_max = 0 for p in group.get_players(): # Wealth series_WealthAt1.append({ "name": p.GroupRank, "y": p.WealthNewDis_1R}) series_WealthAt5.append({ "name": p.GroupRank, "y": p.WealthNewDis_1R * 5}) # min/max Runde 1 if p.WealthNewDis_1R < wealth_min: wealth_min = p.WealthNewDis_1R if p.WealthNewDis_1R > wealth_max: wealth_max = p.WealthNewDis_1R # min/max Rund e5 if p.WealthNewDis_5R < wealth_min: wealth_min = p.WealthNewDis_5R if p.WealthNewDis_5R > wealth_max: wealth_max = p.WealthNewDis_5R series_Start.append({ "name": p.GroupRank, "y": p.StartToken}) series_TokenAdd.append({ "name": p.GroupRank, "y": p.TokenAdd}) cumulativedata = [0, p.WealthNewDis_1R * 1, p.WealthNewDis_1R * 2, p.WealthNewDis_1R * 3, p.WealthNewDis_1R * 4, p.WealthNewDis_1R * 5 ] series_Cumulative.append({ "name": p.GroupRank, "data": cumulativedata}) series_highest_lowest.append(p.WealthNewDis_1R * 5) series_Income.append(p.StartToken + p.TokenAdd) return { "StartToken": series_Start, "TokenAdd": series_TokenAdd, "Cumulative": series_Cumulative, "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 "WealthAt1": series_WealthAt1, "WealthAt5": series_WealthAt5, "wealth_min": wealth_min, "wealth_max": wealth_max, } 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 define_group_rank(group: Group): """ Define group rank. Either get GroupRanks from the participant variables or assign new ones. """ randomnumber = random.sample(list(range(1, 6)), 5) for p in group.get_players(): try: p.GroupRank = p.participant.vars["GroupRank"] except KeyError: print("Rejection ... No Grouprank here. Pretest only!") p.GroupRank = randomnumber[p.id_in_group - 1] # For Pretest Reasons Only # Change id_in_group for p in group.get_players(): p.id_in_group = p.GroupRank class Player(BasePlayer): # Variables for all apps # Income of the individuals 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") ConsumptionFinal = models.FloatField( doc="Final consumption = with TokenAdd as voted for by group as alternative distribution") SumRoundIncome = models.FloatField(doc="Final income in each round.") GroupRank = models.IntegerField(doc="GV: Rank in group") # Arguments Rejection # Enter arguments for new distribution. Only with Rejection ----- initials still delete iTokenAddSuggestion_1 = models.FloatField( doc="Argument for new distribution. Assignment to Player 1", # label="Player 1 (" + str(format(C.StartToken_0[1-1], '.0f')) + "Token)", min=0, max=C.TOKEN_ADD_TOTAL, ) iTokenAddSuggestion_2 = models.FloatField( doc="Argument for new distribution. Assignment to Player 2", # label="Player 2 (" + str(format(C.StartToken_0[2-1], '.0f')) + "Token)", min=0, max=C.TOKEN_ADD_TOTAL, ) iTokenAddSuggestion_3 = models.FloatField( doc="Argument for new distribution. Assignment to Player 3", # label="Player 3 (" + str(format(C.StartToken_0[3-1], '.0f')) + "Token)", min=0, max=C.TOKEN_ADD_TOTAL, ) iTokenAddSuggestion_4 = models.FloatField( doc="Argument for new distribution. Assignment to Player 4", # label="Player 4 (" + str(format(C.StartToken_0[4-1], '.0f')) + "Token)", min=0, max=C.TOKEN_ADD_TOTAL, ) iTokenAddSuggestion_5 = models.FloatField( doc="Argument for new distribution. Assignment to Player 5", # label="Player 5 (" + str(format(C.StartToken_0[5-1], '.0f')) + "Token)", min=0, max=C.TOKEN_ADD_TOTAL, ) Rej_Arg = models.TextField( doc="The argument a person has entered for their preferred distribution of the 20 Token.", label="", max_length=250, # blank=True # this will be overridden later in the javascript ) # Accept arguments - Rejection (not used in this experiment) # Rej_ArgAkz_1 = models.IntegerField( # choices=[ # [1, "Ich akzeptiere das Argument"], # [0, "Ich akzeptiere das Argument nicht"], # ], # widget=widgets.RadioSelect, # # ) # Rej_ArgAkz_2 = models.IntegerField( # choices=[ # [1, "Ich akzeptiere das Argument"], # [0, "Ich akzeptiere das Argument nicht"], # ], # widget=widgets.RadioSelect, # # ) # Rej_ArgAkz_3 = models.IntegerField( # choices=[ # [1, "Ich akzeptiere das Argument"], # [0, "Ich akzeptiere das Argument nicht"], # ], # widget=widgets.RadioSelect, # # ) # Rej_ArgAkz_4 = models.IntegerField( # choices=[ # [1, "Ich akzeptiere das Argument"], # [0, "Ich akzeptiere das Argument nicht"], # ], # widget=widgets.RadioSelect, # # ) # Rej_ArgAkz_5 = models.IntegerField( # choices=[ # [1, "Ich akzeptiere das Argument"], # [0, "Ich akzeptiere das Argument nicht"], # ], # widget=widgets.RadioSelect, # # ) # Vote for best argument Rej_ArgBest_1 = models.BooleanField( doc="Individual votes for best argument - for player 1", blank=True, initial=False) Rej_ArgBest_2 = models.BooleanField( doc="Individual votes for best argument - for player 2", blank=True, initial=False) Rej_ArgBest_3 = models.BooleanField( doc="Individual votes for best argument - for player 3", blank=True, initial=False) Rej_ArgBest_4 = models.BooleanField( doc="Individual votes for best argument - for player 4", blank=True, initial=False) Rej_ArgBest_5 = models.BooleanField( doc="Individual votes for best argument - for player 5.", blank=True, initial=False) # Rej --> Calculate best argument for new distribution - winners and tokens Rej_nArgBest = models.IntegerField(doc="Number of votes for best vote") Rej_ArgBest = models.IntegerField(doc="Whether participant is one of the best-vote winners") # Rej_ArgToken = models.IntegerField(initial=0, doc="Token for the argument.") # Not used in this experiment Rej_ArgBestSingle = models.IntegerField(doc="Whether participant is the only best-vote winner") # Helping variables Chat Nickname = models.TextField(doc="Nickname in chat") # New Distribution TokenAdd = models.FloatField(doc="Chosen new distribution - if suggested distribution was rejected") # Votes for new distribution - First try -iTokenAddVoteFor_1 iTokenAddVoteFor_1 = models.FloatField( doc="Individual votes for assignment to player 1 in new distribution. First try.", min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_2 = models.FloatField( doc="Individual votes for assignment to player 2 in new distribution. First try.", min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_3 = models.FloatField( doc="Individual votes for assignment to player 3 in new distribution. First try.", min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_4 = models.FloatField( doc="Individual votes for assignment to player 4 in new distribution. First try.", min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_5 = models.FloatField( doc="Individual votes for assignment to player 5 in new distribution. First try.", min=0, max=C.TOKEN_ADD_TOTAL) # Votes for new distribution - Second try - iTokenAddVoteFor_corr_1 iTokenAddVoteFor_corr_1 = models.FloatField( doc="Individual votes for assignment to player 1 in new distribution. Second try.", # initial=0, min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_corr_2 = models.FloatField( doc="Individual votes for assignment to player 2 in new distribution. Second try.", # initial=0, min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_corr_3 = models.FloatField( doc="Individual votes for assignment to player 3 in new distribution. Second try.", # initial=0, min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_corr_4 = models.FloatField( doc="Individual votes for assignment to player 4 in new distribution. Second try.", # initial=0, min=0, max=C.TOKEN_ADD_TOTAL) iTokenAddVoteFor_corr_5 = models.FloatField( doc="Individual votes for assignment to player 5 in new distribution. Second try.", # initial=0, min=0, max=C.TOKEN_ADD_TOTAL) # Wealth für Final Distribution as Voted WealthNewDis_1R = models.FloatField(doc="Wealth after one round in newly chosen distribution") WealthNewDis_5R = models.FloatField(doc="Wealth after five rounds in newly chosen distribution") # Chat times Rej1_ChatStart = models.IntegerField( doc="Start of first chat. Since epoch, in UTC", null=True, default=-99) # old player.ChatDisProStart Rej1corr_ChatStart = models.IntegerField( doc="Start of second chat. Since epoch, in UTC", null=True, default=-99) # old player.ChatDisProStartKorr # Pages class Before_Intro_WP(WaitPage): """ Intro to rejection app. Variable GroupAcknowledgement is defined here. """ # Note. GroupRank etc. cannot be calculated if this is in the same page. @staticmethod def after_all_players_arrive(group: Group): print("------------------------------------- Start Rejection App ---------------------------------------------") # Get GroupAcknowledgement for p in group.get_players(): # GroupAcknowledgement has been calculated in redistribution/AckResultWP p.group.GroupAcknowledgement = p.participant.vars.get("GroupAcknowledgement", 0) define_group_rank(group) define_start_token(group) nickname(group) # Create nicknames for chat class Rej_1_Intro(Page): # TODO text must be adjusted here if there are no arguments. template_name = 'rejection/rejection/Rej_1_Intro.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 class Rej_2_Arg(Page): """ Enter the argument """ template_name = 'rejection/rejection/Rej_2_Arg.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and \ player.session.vars['do_arguments_rejection'] # 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 { "languageDE": 1 if settings.LANGUAGE_CODE == 'de' else 0, "secondsTimerIsShown": player.session.config.get("secondsTimerIsShown", settings.secondsTimerIsShown) # secondsTimerIsShown = the last 60 seconds when the timer is shown } @staticmethod def before_next_page(player, timeout_happened): # Note: timeout_happend is either none or True # If a person hasn't entered a valid distribution (timeout is automatically assumed here) if (player.iTokenAddSuggestion_1 + player.iTokenAddSuggestion_2 + player.iTokenAddSuggestion_3 + player.iTokenAddSuggestion_4 + player.iTokenAddSuggestion_5 != C.TOKEN_ADD_TOTAL): player.iTokenAddSuggestion_1 = player.iTokenAddSuggestion_2 = \ player.iTokenAddSuggestion_3 = player.iTokenAddSuggestion_4 = \ player.iTokenAddSuggestion_5 = -99 player.Rej_Arg = " (Zeit abgelaufen)" # If a person has entered a valid distribution but a timeout happened when entering the argument if ((player.iTokenAddSuggestion_1 + player.iTokenAddSuggestion_2 + player.iTokenAddSuggestion_3 + player.iTokenAddSuggestion_4 + player.iTokenAddSuggestion_5 == C.TOKEN_ADD_TOTAL) and timeout_happened): player.Rej_Arg = player.Rej_Arg + " (Zeit abgelaufen)" form_model = "player" form_fields = ["iTokenAddSuggestion_1", "iTokenAddSuggestion_2", "iTokenAddSuggestion_3", "iTokenAddSuggestion_4", "iTokenAddSuggestion_5", "Rej_Arg"] def error_message(player, values): if sum([values["iTokenAddSuggestion_1"], values["iTokenAddSuggestion_2"], values["iTokenAddSuggestion_3"], values["iTokenAddSuggestion_4"], values["iTokenAddSuggestion_5"]]) != C.TOKEN_ADD_TOTAL: return ("Die Summe der von Ihnen gewählten Verteilung beträgt nicht" + str( C.TOKEN_ADD_TOTAL) + "Token!") # FOR PRESENTATION ONLY!!! ! # @staticmethod # def before_next_page(player, timeout_happened): # player.iTokenAddSuggestion_1 = C.TOKEN_ADD_TOTAL # player.iTokenAddSuggestion_2 = 0 # player.iTokenAddSuggestion_3 = 0 # player.iTokenAddSuggestion_4 = 0 # player.iTokenAddSuggestion_5 = 0 # player.Rej_Arg = "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 Rej_3_RateBestArg(Page): """ Acceptance of arguments """ template_name = 'rejection/rejection/Rej_3_RateBestArg.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and \ player.session.vars['do_arguments_rejection'] \ 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("Rej_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.Rej_ArgAkz_1 = -98 elif player.GroupRank == 2: player.Rej_ArgAkz_2 = -98 elif player.GroupRank == 3: player.Rej_ArgAkz_3 = -98 elif player.GroupRank == 4: player.Rej_ArgAkz_4 = -98 elif player.GroupRank == 5: player.Rej_ArgAkz_5 = -98 class Rej_3_RateBestArg2(Page): """ Vote for best argument """ template_name = 'rejection/rejection/Rej_3_RateBestArg2.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.session.vars['do_arguments_rejection'] form_model = "player" @staticmethod def get_form_fields(player): field_list = [] for i in range(1, 6): if player.GroupRank != i: field_list.append("Rej_ArgBest_" + str(i)) return field_list class WaitForArgs(WaitPage): """ Wait for the arguments of the group members """ @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.session.vars['do_arguments_rejection'] class WaitForVotes(WaitPage): @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.session.vars['do_arguments_rejection'] class Rej_4_BestUebersicht(Page): """ Show results for acceptances and votes for best argument """ template_name = 'rejection/rejection/Rej_4_BestUebersicht.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and \ player.session.vars['do_arguments_rejection'] @staticmethod def vars_for_template(player): calc_best_arg(player.group, "Rej") # player.group.calc_acc_arg("Rej") # Not used in this experiment class Rej_5_Chat_DistributionProcedure_0WP_Before(WaitPage): """ Waitpage before Chat """ @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 @staticmethod def after_all_players_arrive(group: Group): for p in group.get_players(): p.Rej1_ChatStart = int(round(time.time())) class Rej_5_Chat_DistributionProcedure_1(Page): """ Chat to find a new distribution """ template_name = 'rejection/rejection/Rej_5_Chat_DistributionProcedure_1.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 form_model = "player" form_fields = ["iTokenAddVoteFor_1", "iTokenAddVoteFor_2", "iTokenAddVoteFor_3", "iTokenAddVoteFor_4", "iTokenAddVoteFor_5"] def error_message(player, values): if sum([values["iTokenAddVoteFor_1"], values["iTokenAddVoteFor_2"], values["iTokenAddVoteFor_3"], values["iTokenAddVoteFor_4"], values["iTokenAddVoteFor_5"]]) != C.TOKEN_ADD_TOTAL: return ("Die Summe der von Ihnen gewählten Verteilung beträgt nicht " + str( C.TOKEN_ADD_TOTAL) + " Token!") # For presentation only!!!! # @staticmethod # def vars_for_template(player): # player.iTokenAddSuggestion_1 = C.TOKEN_ADD_TOTAL # player.iTokenAddSuggestion_2 = 0 # player.iTokenAddSuggestion_3 = 0 # player.iTokenAddSuggestion_4 = 0 # player.iTokenAddSuggestion_5 = 0 # player.Rej_Arg = "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" # FOR PRESENTATION ONLY!! # @staticmethod # def before_next_page(player, timeout_happened): # player.iTokenAddVoteFor_1 = 10 # player.iTokenAddVoteFor_2 = 10 # player.iTokenAddVoteFor_3 = 0 # player.iTokenAddVoteFor_4 = 0 # player.iTokenAddVoteFor_5 = 0 class Rej_5_Chat_DistributionProcedure_2WP_After(WaitPage): """ Chat to find a new distribution. If a person enters their assignments but needs to wait for the other participants. """ template_name = 'rejection/rejection/Rej_5_Chat_DistributionProcedure_2WP_After.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 @staticmethod def after_all_players_arrive(group: Group): abzahlen(group, Correction="") class Rej_6_Voting_Results(Page): template_name = 'rejection/rejection/Rej_6_Voting_Results.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 @staticmethod def vars_for_template(player): if player.group.found_new_distribution == 1: return dict( languageDE=1 if settings.LANGUAGE_CODE == 'de' else 0, Token1=str(player.group.TokenAdd_New_1), Token2=str(player.group.TokenAdd_New_2), Token3=str(player.group.TokenAdd_New_3), Token4=str(player.group.TokenAdd_New_4), Token5=str(player.group.TokenAdd_New_5) ) else: return dict( languageDE=1 if settings.LANGUAGE_CODE == 'de' else 0, Token1=-99, Token2=-99, Token3=-99, Token4=-99, Token5=-99 ) class Rej_7_Chat_DistributionProcedureKorr_0WP_Before(WaitPage): @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.group.found_new_distribution == 0 @staticmethod def after_all_players_arrive(group: Group): for p in group.get_players(): p.Rej1corr_ChatStart = int(round(time.time())) class Rej_8_Chat_DistributionProcedureKorr_1(Page): """ Second chat to find a new distribution - 1 minute more to enter the correct numbers """ template_name = 'rejection/rejection/Rej_7_Chat_DistributionProcedureKorr_1.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.group.found_new_distribution == 0 form_model = "player" form_fields = ["iTokenAddVoteFor_corr_1", "iTokenAddVoteFor_corr_2", "iTokenAddVoteFor_corr_3", "iTokenAddVoteFor_corr_4", "iTokenAddVoteFor_corr_5"] def error_message(player, values): if sum([values["iTokenAddVoteFor_corr_1"], values["iTokenAddVoteFor_corr_2"], values["iTokenAddVoteFor_corr_3"], values["iTokenAddVoteFor_corr_4"], values["iTokenAddVoteFor_corr_5"]]) != C.TOKEN_ADD_TOTAL: return ("Die Summe der von Ihnen gewählten Verteilung beträgt nicht " + str( C.TOKEN_ADD_TOTAL) + " Token!") class Rej_8_Chat_DistributionProcedureKorr_WP_After(WaitPage): template_name = 'rejection/rejection/Rej_7_Chat_DistributionProcedureKorr_WP_After.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.group.found_new_distribution == 0 @staticmethod def after_all_players_arrive(group: Group): abzahlen(group, Correction="Corr") class Rej_8_Voting_ResultsKorr(Page): template_name = 'rejection/rejection/Rej_8_Voting_ResultsKorr.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 and player.group.found_new_distribution == 0 @staticmethod def vars_for_template(player): if player.group.found_new_distribution_corr == 1: # Send as string, otherwise the javascript won't take the commas return dict( languageDE=1 if settings.LANGUAGE_CODE == 'de' else 0, Token1=str(player.group.TokenAdd_New_corr_1), Token2=str(player.group.TokenAdd_New_corr_2), Token3=str(player.group.TokenAdd_New_corr_3), Token4=str(player.group.TokenAdd_New_corr_4), Token5=str(player.group.TokenAdd_New_corr_5) ) else: return dict( languageDE=1 if settings.LANGUAGE_CODE == 'de' else 0, Token1=-99, Token2=-99, Token3=-99, Token4=-99, Token5=-99 ) class Rej_9_Rounds1(Page): template_name = 'rejection/rejection/Rej_9_Rounds1.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 \ and (player.group.found_new_distribution == 1 or player.group.found_new_distribution_corr == 1) @staticmethod def vars_for_template(player): return results_graph(player.group) class Rej_9_Rounds2(Page): template_name = 'rejection/rejection/Rej_9_Rounds2.html' @staticmethod def is_displayed(player): return player.group.GroupAcknowledgement == 0 \ and (player.group.found_new_distribution == 1 or player.group.found_new_distribution_corr == 1) @staticmethod def vars_for_template(player): return results_graph(player.group) page_sequence = [ Before_Intro_WP, # Can be taken out when passing through. Rej_1_Intro, Rej_2_Arg, WaitForArgs, Rej_3_RateBestArg, Rej_3_RateBestArg2, WaitForVotes, Rej_4_BestUebersicht, Rej_5_Chat_DistributionProcedure_0WP_Before, Rej_5_Chat_DistributionProcedure_1, Rej_5_Chat_DistributionProcedure_2WP_After, Rej_6_Voting_Results, Rej_7_Chat_DistributionProcedureKorr_0WP_Before, Rej_8_Chat_DistributionProcedureKorr_1, Rej_8_Chat_DistributionProcedureKorr_WP_After, Rej_8_Voting_ResultsKorr, Rej_9_Rounds1, Rej_9_Rounds2 ]