from otree.api import Currency as c, currency_range from ._builtin import Page, WaitPage from .models import Constants from scipy import stats import numpy as np import random class WaitForGroup(WaitPage): def is_displayed(self): return self.round_number == 1 title_text = "Please wait" body_text = "Waiting for the other participants to finish the tutorial. This might take several minutes." wait_for_all_groups = True class ElicitationBeliefs(Page): #timeout_seconds = Constants.timeout2 # Define the form fields that are necessary for the game and the html. form_model = 'player' form_fields = ['belief_effort1', 'belief_effort2', 'belief_effort3', 'belief_effort4', 'belief_effort5', 'belief_sabotage1', 'belief_sabotage2', 'belief_sabotage3', 'belief_sabotage4', 'belief_sabotage5', 'effort_calc_try', 'sabotage_calc_try', 'effort_opponent_calc_try', 'sabotage_opponent_calc_try', 'clicksEffort_calc_try', 'clicksSabotage_calc_try', 'clicksOpponentEffort_calc_try', 'clicksOpponentSabotage_calc_try', 'effort_p2_calc_try', 'sabotage_p2_calc_try', 'effort_p3_calc_try', 'sabotage_p3_calc_try', 'effort_p4_calc_try', 'sabotage_p4_calc_try', 'effort_p5_calc_try', 'sabotage_p5_calc_try', 'effort_p1_calc_try', 'sabotage_p1_calc_try'] def get_timeout_seconds(self): if self.group.round_number == 1: timeout_seconds = 120 # 2 minutes return timeout_seconds elif self.group.round_number == 7: timeout_seconds = 60 # 1 minute return timeout_seconds elif self.group.round_number == 13: timeout_seconds = 60 # 1 minute return timeout_seconds ### Only shown every 6 rounds def is_displayed(self): round = self.round_number if round == 1 or round == 7 or round == 13: a = True else: a = False return a ### Define the prevalues for the slider inputs & for the calculator def vars_for_template(self): p = self.player if p.round_number == 1: effort1 = 0 effort2 = 0 effort3 = 0 effort4 = 0 effort5 = 0 sabotage1 = 0 sabotage2 = 0 sabotage3 = 0 sabotage4 = 0 sabotage5 = 0 effort_calc = p.participant.vars['effort_calc_try'] sabotage_calc = p.participant.vars['sabotage_calc_try'] effort_opponent_calc = p.participant.vars['effort_opponent_calc_try'] sabotage_opponent_calc = p.participant.vars['sabotage_opponent_calc_try'] effort_p1_calc_try = p.participant.vars['effort_p1_calc_try'] sabotage_p1_calc_try = p.participant.vars['sabotage_p1_calc_try'] effort_p2_calc_try = p.participant.vars['effort_p2_calc_try'] sabotage_p2_calc_try = p.participant.vars['sabotage_p2_calc_try'] effort_p3_calc_try = p.participant.vars['effort_p3_calc_try'] sabotage_p3_calc_try = p.participant.vars['sabotage_p3_calc_try'] effort_p4_calc_try = p.participant.vars['effort_p4_calc_try'] sabotage_p4_calc_try = p.participant.vars['sabotage_p4_calc_try'] effort_p5_calc_try = p.participant.vars['effort_p5_calc_try'] sabotage_p5_calc_try = p.participant.vars['sabotage_p5_calc_try'] else: effort1 = p.in_round(p.round_number - 6).belief_effort1 effort2 = p.in_round(p.round_number - 6).belief_effort2 effort3 = p.in_round(p.round_number - 6).belief_effort3 effort4 = p.in_round(p.round_number - 6).belief_effort4 effort5 = p.in_round(p.round_number - 6).belief_effort5 sabotage1 = p.in_round(p.round_number - 6).belief_sabotage1 sabotage2 = p.in_round(p.round_number - 6).belief_sabotage2 sabotage3 = p.in_round(p.round_number - 6).belief_sabotage3 sabotage4 = p.in_round(p.round_number - 6).belief_sabotage4 sabotage5 = p.in_round(p.round_number - 6).belief_sabotage5 effort_calc = p.in_round(p.round_number - 1).effort_calc_try sabotage_calc = p.in_round(p.round_number - 1).sabotage_calc_try effort_opponent_calc = p.in_round(p.round_number - 1).effort_opponent_calc_try sabotage_opponent_calc = p.in_round(p.round_number - 1).sabotage_opponent_calc_try effort_p1_calc_try = p.in_round(p.round_number - 1).effort_p1_calc_try sabotage_p1_calc_try = p.in_round(p.round_number - 1).sabotage_p1_calc_try effort_p2_calc_try = p.in_round(p.round_number - 1).effort_p2_calc_try sabotage_p2_calc_try = p.in_round(p.round_number - 1).sabotage_p2_calc_try effort_p3_calc_try = p.in_round(p.round_number - 1).effort_p3_calc_try sabotage_p3_calc_try = p.in_round(p.round_number - 1).sabotage_p3_calc_try effort_p4_calc_try = p.in_round(p.round_number - 1).effort_p4_calc_try sabotage_p4_calc_try = p.in_round(p.round_number - 1).sabotage_p4_calc_try effort_p5_calc_try = p.in_round(p.round_number - 1).effort_p5_calc_try sabotage_p5_calc_try = p.in_round(p.round_number - 1).sabotage_p5_calc_try performance1 = effort_calc performance2 = effort_calc / (1 + sabotage_opponent_calc) performance3 = effort_calc / (1 + sabotage_opponent_calc*2) performance4 = effort_calc / (1 + sabotage_opponent_calc*3) performance5 = effort_calc / (1 + sabotage_opponent_calc*4) othersPerformance2 = effort_opponent_calc / (1 + sabotage_calc) othersPerformance3 = effort_opponent_calc / (1 + sabotage_calc + sabotage_opponent_calc) othersPerformance4 = effort_opponent_calc / (1 + sabotage_calc + sabotage_opponent_calc*2) othersPerformance5 = effort_opponent_calc / (1 + sabotage_calc + sabotage_opponent_calc*3) payoffWin = 400 - effort_calc - sabotage_calc payoffLose = 200 - effort_calc - sabotage_calc donations1 = performance1+Constants.donation_base donations2 = performance2+othersPerformance2+Constants.donation_base donations3 = performance3+othersPerformance3+Constants.donation_base donations4 = performance4+othersPerformance4+Constants.donation_base donations5 = performance5+othersPerformance5+Constants.donation_base group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) group4 = stats.binom.pmf(3, Constants.players_per_group - 1, Constants.entering_probability) group5 = stats.binom.pmf(4, Constants.players_per_group - 1, Constants.entering_probability) enter = round(Constants.entering_probability * 100, 0) return dict(e1=effort1, e2=effort2, e3=effort3, e4=effort4, e5=effort5, s1=sabotage1, s2=sabotage2, s3=sabotage3, s4=sabotage4, s5=sabotage5, eCalc=effort_calc, sCalc=sabotage_calc, eOppCalc=effort_opponent_calc, sOppCalc=sabotage_opponent_calc, eCalcP1=effort_p1_calc_try, sCalcP1=sabotage_p1_calc_try, eCalcP2=effort_p2_calc_try, sCalcP2=sabotage_p2_calc_try, eCalcP3=effort_p3_calc_try, sCalcP3=sabotage_p3_calc_try, eCalcP4=effort_p4_calc_try, sCalcP4=sabotage_p4_calc_try, eCalcP5=effort_p5_calc_try, sCalcP5=sabotage_p5_calc_try, performance1=round(performance1, 1), performance2=round(performance2, 1), performance3=round(performance3, 1), performance4=round(performance4, 1), performance5=round(performance5, 1), othersPerformance2=round(othersPerformance2, 1), othersPerformance3=round(othersPerformance3, 1), othersPerformance4=round(othersPerformance4, 1), othersPerformance5=round(othersPerformance5, 1), donations1=round(donations1, 1), donations2=round(donations2, 1), donations3=round(donations3, 1), donations4=round(donations4, 1), donations5=round(donations5, 1), payoffWin=payoffWin, payoffLose=payoffLose, g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), g4=round(group4 * 100, 1), g5=round(group5 * 100, 1), enter=int(enter)) def js_vars(self): # Calculate probabilities for group sizes p = self.player if p.round_number == 1: effort_calc_try = p.participant.vars['effort_calc_try'] sabotage_calc_try = p.participant.vars['sabotage_calc_try'] effort_opponent_calc_try = p.participant.vars['effort_opponent_calc_try'] sabotage_opponent_calc_try = p.participant.vars['sabotage_opponent_calc_try'] else: effort_calc_try = p.in_round(p.round_number - 1).effort_calc_try sabotage_calc_try = p.in_round(p.round_number - 1).sabotage_calc_try effort_opponent_calc_try = p.in_round(p.round_number - 1).effort_opponent_calc_try sabotage_opponent_calc_try = p.in_round(p.round_number - 1).sabotage_opponent_calc_try performance2 = effort_calc_try / (1 + sabotage_opponent_calc_try) performance3 = effort_calc_try / (1 + sabotage_opponent_calc_try*2) performance4 = effort_calc_try / (1 + sabotage_opponent_calc_try*3) performance5 = effort_calc_try / (1 + sabotage_opponent_calc_try*4) othersPerformance2 = effort_opponent_calc_try / (1 + sabotage_calc_try) othersPerformance3 = effort_opponent_calc_try / (1 + sabotage_calc_try + sabotage_opponent_calc_try) othersPerformance4 = effort_opponent_calc_try / (1 + sabotage_calc_try + sabotage_opponent_calc_try*2) othersPerformance5 = effort_opponent_calc_try / (1 + sabotage_calc_try + sabotage_opponent_calc_try*3) if (performance2+othersPerformance2) > 0: winning2 = performance2 / (performance2+othersPerformance2) else: winning2 = 0.5 if (performance3 + othersPerformance3) > 0: winning3 = performance3 / (performance3 + othersPerformance3*2) else: winning3 = 1/3 if (performance4 + othersPerformance4) > 0: winning4 = performance4 / (performance4 + othersPerformance4*3) else: winning4 = 0.5 if (performance5 + othersPerformance5) > 0: winning5 = performance5 / (performance5 + othersPerformance5*4) else: winning5 = 0.5 group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) group4 = stats.binom.pmf(3, Constants.players_per_group - 1, Constants.entering_probability) group5 = stats.binom.pmf(4, Constants.players_per_group - 1, Constants.entering_probability) return dict(g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), g4=round(group4 * 100, 1), g5=round(group5 * 100, 1), winning2=winning2, winning3 = winning3, winning4 = winning4, winning5 = winning5) class ElicitationChoices(Page): form_model = 'player' form_fields = ['effort1', 'effort2', 'effort3', 'sabotage1', 'sabotage2', 'sabotage3', 'effort_calc_try', 'sabotage_calc_try', 'effort_opponent_calc_try', 'sabotage_opponent_calc_try', 'clicksEffort_calc_try', 'clicksSabotage_calc_try', 'clicksOpponentEffort_calc_try', 'clicksOpponentSabotage_calc_try', 'clicksEffort_calc_advanced_try', 'clicksSabotage_calc_advanced_try', 'clicksOpponentEffort_calc_advanced_try', 'clicksOpponentSabotage_calc_advanced_try', 'effort_p2_calc_try', 'sabotage_p2_calc_try', 'effort_p3_calc_try', 'sabotage_p3_calc_try', 'effort_p1_calc_try', 'sabotage_p1_calc_try'] def get_timeout_seconds(self): if self.group.round_number == 1: timeout_seconds = 300 # 5minutes elif self.group.round_number == 2: timeout_seconds = 240 # 4minutes elif self.group.round_number < 5: timeout_seconds = 180 # 3minutes else: timeout_seconds = 90 # 1.5 minutes return timeout_seconds ## Define the prevalues for the slider inputs and for the calculator def vars_for_template(self): p = self.player if p.round_number == 1: effort1 = 0 effort2 = 0 effort3 = 0 sabotage1 = 0 sabotage2 = 0 sabotage3 = 0 effort_calc_try = p.participant.vars['effort_calc_try'] sabotage_calc_try = p.participant.vars['sabotage_calc_try'] effort_opponent_calc_try = p.participant.vars['effort_opponent_calc_try'] sabotage_opponent_calc_try = p.participant.vars['sabotage_opponent_calc_try'] effort_p1_calc_try = p.participant.vars['effort_p1_calc_try'] sabotage_p1_calc_try = p.participant.vars['sabotage_p1_calc_try'] effort_p2_calc_try = p.participant.vars['effort_p2_calc_try'] sabotage_p2_calc_try = p.participant.vars['sabotage_p2_calc_try'] effort_p3_calc_try = p.participant.vars['effort_p3_calc_try'] sabotage_p3_calc_try = p.participant.vars['sabotage_p3_calc_try'] else: effort1 = p.in_round(p.round_number - 1).effort1 effort2 = p.in_round(p.round_number - 1).effort2 effort3 = p.in_round(p.round_number - 1).effort3 sabotage1 = p.in_round(p.round_number - 1).sabotage1 sabotage2 = p.in_round(p.round_number - 1).sabotage2 sabotage3 = p.in_round(p.round_number - 1).sabotage3 effort_calc_try = p.in_round(p.round_number - 1).effort_calc_try sabotage_calc_try = p.in_round(p.round_number - 1).sabotage_calc_try effort_opponent_calc_try = p.in_round(p.round_number - 1).effort_opponent_calc_try sabotage_opponent_calc_try = p.in_round(p.round_number - 1).sabotage_opponent_calc_try effort_p1_calc_try = p.in_round(p.round_number - 1).effort_p1_calc_try sabotage_p1_calc_try = p.in_round(p.round_number - 1).sabotage_p1_calc_try effort_p2_calc_try = p.in_round(p.round_number - 1).effort_p2_calc_try sabotage_p2_calc_try = p.in_round(p.round_number - 1).sabotage_p2_calc_try effort_p3_calc_try = p.in_round(p.round_number - 1).effort_p3_calc_try sabotage_p3_calc_try = p.in_round(p.round_number - 1).sabotage_p3_calc_try performance1 = effort_calc_try performance2 = effort_calc_try / (1 + sabotage_opponent_calc_try) performance3 = effort_calc_try / (1 + sabotage_opponent_calc_try*2) othersPerformance2 = effort_opponent_calc_try / (1 + sabotage_calc_try) othersPerformance3 = effort_opponent_calc_try / (1 + sabotage_calc_try + sabotage_opponent_calc_try) payoffWin = 400 - effort_calc_try - sabotage_calc_try payoffLose = 200 - effort_calc_try - sabotage_calc_try donations1 = performance1+Constants.donation_base donations2 = performance2+othersPerformance2+Constants.donation_base donations3 = performance3+othersPerformance3+Constants.donation_base group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) enter = round(Constants.entering_probability * 100, 0) return dict(e1=effort1, e2=effort2, e3=effort3, s1=sabotage1, s2=sabotage2, s3=sabotage3, eCalc=effort_calc_try, sCalc=sabotage_calc_try, eOppCalc=effort_opponent_calc_try, sOppCalc=sabotage_opponent_calc_try, eCalcP1=effort_p1_calc_try, sCalcP1=sabotage_p1_calc_try, eCalcP2=effort_p2_calc_try, sCalcP2=sabotage_p2_calc_try, eCalcP3=effort_p3_calc_try, sCalcP3=sabotage_p3_calc_try, performance1=round(performance1, 1), performance2=round(performance2, 1), performance3=round(performance3, 1), othersPerformance2=round(othersPerformance2, 1), othersPerformance3=round(othersPerformance3, 1), donations1=round(donations1, 1), donations2=round(donations2, 1), donations3=round(donations3, 1), payoffWin=payoffWin, payoffLose=payoffLose, g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), enter=int(enter)) def js_vars(self): # Calculate probabilities for group sizes group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) p = self.player if p.round_number == 1: effort_calc_try = p.participant.vars['effort_calc_try'] sabotage_calc_try = p.participant.vars['sabotage_calc_try'] effort_opponent_calc_try = p.participant.vars['effort_opponent_calc_try'] sabotage_opponent_calc_try = p.participant.vars['sabotage_opponent_calc_try'] else: effort_calc_try = p.in_round(p.round_number - 1).effort_calc_try sabotage_calc_try = p.in_round(p.round_number - 1).sabotage_calc_try effort_opponent_calc_try = p.in_round(p.round_number - 1).effort_opponent_calc_try sabotage_opponent_calc_try = p.in_round(p.round_number - 1).sabotage_opponent_calc_try performance2 = effort_calc_try / (1 + sabotage_opponent_calc_try) performance3 = effort_calc_try / (1 + sabotage_opponent_calc_try*2) othersPerformance2 = effort_opponent_calc_try / (1 + sabotage_calc_try) othersPerformance3 = effort_opponent_calc_try / (1 + sabotage_calc_try + sabotage_opponent_calc_try) if (performance2+othersPerformance2) > 0: winning2 = performance2 / (performance2+othersPerformance2) else: winning2 = 0.5 if (performance3 + othersPerformance3) > 0: winning3 = performance3 / (performance3 + othersPerformance3*2) else: winning3 = 1/3 ## Set timeout times depending on the round if self.group.round_number < 3: timeout = 300000 ### 5 minutes elif self.group.round_number < 6: timeout = 180000 #### 3minutes else: timeout = 120000 #### 2minutes return dict(g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), timeout=timeout, eCalc=effort_calc_try, sCalc=sabotage_calc_try, eOppCalc=effort_opponent_calc_try, sOppCalc=sabotage_opponent_calc_try, winning2=winning2, winning3=winning3) class ResultsWaitPage(WaitPage): def after_all_players_arrive(self): self.group.realize_group_size() self.group.set_performances_probabilities_and_winner() self.group.set_payoff_round() self.group.set_individual_display() class Results(Page): def get_timeout_seconds(self): if self.group.round_number < 3: timeout_seconds = 120 # 2 minutes else: timeout_seconds = 90 # 1 minute return timeout_seconds def vars_for_template(self): group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) if self.player.active: winProbYou = round(100*self.player.probability, 2) else: winProbYou = 0 enter = round(Constants.entering_probability * 100, 0) otherActive = self.group.group_size_realization-1 return dict(g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), enter=int(enter), otherActive=otherActive, winProbYou=winProbYou) def js_vars(self): group1 = stats.binom.pmf(0, Constants.players_per_group - 1, Constants.entering_probability) group2 = stats.binom.pmf(1, Constants.players_per_group - 1, Constants.entering_probability) group3 = stats.binom.pmf(2, Constants.players_per_group - 1, Constants.entering_probability) enter = round(Constants.entering_probability * 100, 0) if self.player.active: winProbYou = round(100*self.player.probability, 2) else: winProbYou = 0 return dict( p1=winProbYou, p2=self.player.probability_other1, p3=self.player.probability_other2, g1=round(group1 * 100, 1), g2=round(group2 * 100, 1), g3=round(group3 * 100, 1), enter=int(enter) ) # Calculate the ultimate payoffs for this app. def before_next_page(self): self.player.set_average_choices_others() if self.player.round_number == 15: ### get the payoff from the sabotage game. Therefore get 3 numbers from 30 rounds (which includes part B) payoffCertaintyGame1 = -1 payoffCertaintyGame2 = -1 payoffCertaintyGame3 = -1 donations1 = -1 donations2 = -1 donations3 = -1 payoffRound1 = self.player.participant.vars['payoffRound1'] payoffRound2 = self.player.participant.vars['payoffRound2'] payoffRound3 = self.player.participant.vars['payoffRound3'] if payoffRound1 < 16: p = self.player.in_round(payoffRound1) payoffCertaintyGame1 = p.payoff_round donations1 = p.group.donations if payoffRound2 < 16: p = self.player.in_round(payoffRound2) payoffCertaintyGame2 = p.payoff_round donations2 = p.group.donations if payoffRound3 < 16: p = self.player.in_round(payoffRound3) payoffCertaintyGame3 = p.payoff_round donations3 = p.group.donations self.player.participant.vars['payoff1'] = payoffCertaintyGame1 self.player.participant.vars['payoff2'] = payoffCertaintyGame2 self.player.participant.vars['payoff3'] = payoffCertaintyGame3 self.player.participant.vars['donations1'] = donations1 self.player.participant.vars['donations2'] = donations2 self.player.participant.vars['donations3'] = donations3 ### Give the values from the calculator to the next app self.participant.vars['effort_calc_try'] = self.player.effort_calc_try self.participant.vars['sabotage_calc_try'] = self.player.sabotage_calc_try self.participant.vars['effort_opponent_calc_try'] = self.player.effort_opponent_calc_try self.participant.vars['sabotage_opponent_calc_try'] = self.player.sabotage_opponent_calc_try self.participant.vars['effort_p1_calc_try'] = self.player.effort_p1_calc_try self.participant.vars['sabotage_p1_calc_try'] = self.player.sabotage_p1_calc_try self.participant.vars['effort_p2_calc_try'] = self.player.effort_p2_calc_try self.participant.vars['sabotage_p2_calc_try'] = self.player.sabotage_p2_calc_try self.participant.vars['effort_p3_calc_try'] = self.player.effort_p3_calc_try self.participant.vars['sabotage_p3_calc_try'] = self.player.sabotage_p3_calc_try self.participant.vars['last_effort1_partA'] = self.player.effort1 self.participant.vars['last_effort2_partA'] = self.player.effort2 self.participant.vars['last_effort3_partA'] = self.player.effort3 self.participant.vars['last_sabotage1_partA'] = self.player.sabotage1 self.participant.vars['last_sabotage2_partA'] = self.player.sabotage2 self.participant.vars['last_sabotage3_partA'] = self.player.sabotage3 class Payoff(Page): def is_displayed(self): return self.round_number == 15 def vars_for_template(self): #payoffRoundBelief = self.player.participant.vars['payoffRoundBelief'] payoffCertaintyGame1 = self.player.participant.vars['payoff1'] payoffCertaintyGame2 = self.player.participant.vars['payoff2'] payoffCertaintyGame3 = self.player.participant.vars['payoff3'] payoffRound1 = self.player.participant.vars['payoffRound1'] payoffRound2 = self.player.participant.vars['payoffRound2'] payoffRound3 = self.player.participant.vars['payoffRound3'] donations1 = self.player.participant.vars['donations1'] donations2 = self.player.participant.vars['donations2'] donations3 = self.player.participant.vars['donations3'] return dict(payoffCertaintyGame1=payoffCertaintyGame1, payoffCertaintyGame2=payoffCertaintyGame2, payoffCertaintyGame3=payoffCertaintyGame3, payoffRound1=payoffRound1, payoffRound2=payoffRound2, payoffRound3=payoffRound3, donations1=donations1, donations2=donations2, donations3=donations3) page_sequence = [ WaitForGroup, ElicitationChoices, ResultsWaitPage, Results ]