from otree.api import * import ast import static_data.generateAllPaths as gPaths c = Currency doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'resolution' players_per_group = None num_rounds = 1 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): feedback_understanding = models.IntegerField( label="Were the experiment and the tasks that you had to complete well explained?", choices=[ [1, "No"], [2, "Rather no"], [3, "So and so"], [4, "Rather yes"], [5, "Yes"], ], widget=widgets.RadioSelectHorizontal, ) feedback_internet = models.IntegerField( label="Have you had any problems with your internet connection during the experiment?", choices=[ [1, "I had severe problems"], [2, "I had problems"], [3, "I had some problems"], [4, "I had almost no problems"], [5, "I had no problems"], ], widget=widgets.RadioSelectHorizontal, ) feedback_layout = models.IntegerField( label="Were there any issues with the display of the experiment? This includes, for example, the legibility of the font, the display of the graphics, etc.", choices=[ [1, "I had severe issues"], [2, "I had issues"], [3, "I had some issues"], [4, "I had almost no issues"], [5, "I had no issues"], ], widget=widgets.RadioSelectHorizontal, ) feedback_trust = models.IntegerField( label="Do you believe that your bonus is determined fairly, exactly as described?", choices=[ [1, "No"], [2, "Rather no"], [3, "So and so"], [4, "Rather yes"], [5, "Yes"], ], widget=widgets.RadioSelectHorizontal, ) feedback_final_remarks = models.LongStringField( label="Do you have further feedback for us?", blank=True ) ### Risk resolution bonusTask = models.LongStringField(blank=True) resolveRisk = models.BooleanField(initial=False) # Save Path pathDrawn_bonus = models.LongStringField(blank=True) # Save Stopping decisions along path continuationDec_bonus = models.LongStringField(blank=True) # Save Winning Sides coinTossOutcome_bonus = models.LongStringField(blank=True) # Save Card Number chosenCards_bonus = models.LongStringField(blank=True) # Save Card Outcome cardOutcome_bonus = models.LongStringField(blank=True) # Save payoff riskyPayoff = models.LongStringField() endowment = models.LongStringField() completionFee = models.LongStringField() decoloringCosts = models.LongStringField() totalEarnings = models.LongStringField() # Show PW to Verification File showVerificationPW = models.BooleanField( default=False ) # PAGES class Questionnaire(Page): form_model = "player" form_fields = [ "feedback_understanding", "feedback_internet", "feedback_layout", "feedback_trust", "feedback_final_remarks", ] def is_displayed(player): return player.round_number == 1 and not player.participant.timeoutHappened def js_vars(player): return dict(min_time_on_page=player.session.config["min_time_on_page_feedback"],) def before_next_page(player, timeout_happened): player.participant.resolutionRound = 0 player.participant.finalPayoff = 0 @staticmethod def vars_for_template(player: Player): return dict( testing = player.session.config["testing"], ) class RiskResolution(Page): form_model = "player" form_fields = [ "pathDrawn_bonus", "coinTossOutcome_bonus", "chosenCards_bonus", "cardOutcome_bonus", ] @staticmethod def is_displayed(player: Player): # For testing only if player.session.config["testing"]: player.participant.resolutionRound = 0 player.participant.payoffPath = [0]*6 player.participant.coinTossOutcomeDecoloring = [0]*6 return player.resolveRisk and player.participant.treatment in [0,1,3] and not player.participant.timeoutHappened @staticmethod def js_vars(player): # Can only be reached for decoloring task return dict( stopStrategy = player.participant.decoloring, roundNumber = player.participant.resolutionRound, path = player.participant.payoffPath, min_time_on_page= player.session.config["min_time_on_page_instructions"], upTick = player.session.config["upTick"], initialColor = player.participant.plotColor, allPaths = gPaths.getAllPaths(), ) @staticmethod def live_method(player, data): t = data["type"] value = data["value"] roundNumber = player.participant.resolutionRound winningSide = "" imagePathGuess = '/static/img/coin.png' imagePathOutcome = '/static/img/coin_questionmark.png' if t == "coin": player.participant.resolutionRound += 1 player.participant.coinTossOutcomeDecoloring[roundNumber] = value winningSides = player.participant.winningSideDict['decoloring'] # Only reached for decoloring task winningSide = winningSides[int(roundNumber)] if value == "H": imagePathGuess = '/static/img/coin_h.png' else: imagePathGuess = '/static/img/coin_t.png' if winningSide == "H": imagePathOutcome = '/static/img/coin_h.png' else: imagePathOutcome = '/static/img/coin_t.png' if winningSide == value: # Move Up player.participant.payoffPath[roundNumber+1] = player.participant.payoffPath[roundNumber] + roundNumber + 1 else: # Move Down player.participant.payoffPath[roundNumber+1] = player.participant.payoffPath[roundNumber] + roundNumber + 2 elif t == "payment": player.participant.payoffPath = player.participant.payoffPath[0:roundNumber + 1] player.participant.finalPayoff = value return { player.id_in_group: dict( type = t, value = value, roundNumber = player.participant.resolutionRound, drawn = player.participant.payoffPath, imagePathGuess = imagePathGuess, imagePathOutcome = imagePathOutcome, )} @staticmethod def vars_for_template(player): return dict( user_chosen_decision = player.participant.vars["bf"], testing = player.session.config["testing"] ) def before_next_page(player, timeout_happened): # Get continuation decision along payoff path tmp = player.participant.decoloring stopStrategy = tmp["continuation"] strategyAlongPath = [stopStrategy[node] for node in player.participant.payoffPath] strategyAlongPath[-1] = "Stop" player.pathDrawn_bonus = str(player.participant.payoffPath) player.coinTossOutcome_bonus = str(player.participant.coinTossOutcomeDecoloring) player.continuationDec_bonus = str(strategyAlongPath) player.chosenCards_bonus = str(player.participant.chosenCardDecoloring) player.cardOutcome_bonus = str(player.participant.cardOutcomeDecoloring) # Save bonus payment player.riskyPayoff = str(player.participant.finalPayoff) class RiskResolution_rand(Page): form_model = "player" form_fields = [ "pathDrawn_bonus", "coinTossOutcome_bonus", "chosenCards_bonus", "cardOutcome_bonus", ] @staticmethod def is_displayed(player: Player): # For testing only if player.session.config["testing"]: player.participant.resolutionRound = 0 player.participant.payoffPath = [0]*6 player.participant.coinTossOutcomeDecoloring = [-1]*6 # Coin Toss Outcome player.participant.chosenCardDecoloring = [-1] * 6 # Save chosen card player.participant.cardOutcomeDecoloring = [-1] * 6 # Save card outcome return player.resolveRisk and player.participant.treatment in [2, 4] and not player.participant.timeoutHappened @staticmethod def js_vars(player): # Can only be reached for decoloring task return dict( stopStrategy = player.participant.decoloring, roundNumber = player.participant.resolutionRound, path = player.participant.payoffPath, min_time_on_page= player.session.config["min_time_on_page_instructions"], upTick = player.session.config["upTick"], initialColor = player.participant.plotColor, cardNumbersDict = player.participant.cardNumbersDict["Decoloring"], chosenCard = player.participant.chosenCardDecoloring, cardOutcome = player.participant.cardOutcomeDecoloring, ) @staticmethod def live_method(player, data): t = data["type"] value = data["value"] roundNumber = player.participant.resolutionRound winningSide = "" imagePathGuess = '/static/img/coin.png' imagePathOutcome = '/static/img/coin_questionmark.png' if t == "card": player.participant.chosenCardDecoloring[roundNumber] = value assignedCardNumber = player.participant.cardNumbersDict["Decoloring"][value][roundNumber] stopStrategy = player.participant.decoloring["continuation"] currentNode = player.participant.payoffPath[roundNumber] stopAtNode = stopStrategy[currentNode] blackProb = 10 - (stopAtNode / 10) if (assignedCardNumber <= blackProb): player.participant.cardOutcomeDecoloring[roundNumber] = "Stop" else: player.participant.cardOutcomeDecoloring[roundNumber] = "Continue" elif t == "coin": player.participant.resolutionRound += 1 player.participant.coinTossOutcomeDecoloring[roundNumber] = value winningSides = player.participant.winningSideDict['decoloring'] # Only reached for decoloring task winningSide = winningSides[int(roundNumber)] if value == "H": imagePathGuess = '/static/img/coin_h.png' else: imagePathGuess = '/static/img/coin_t.png' if winningSide == "H": imagePathOutcome = '/static/img/coin_h.png' else: imagePathOutcome = '/static/img/coin_t.png' if winningSide == value: # Move Up player.participant.payoffPath[roundNumber+1] = player.participant.payoffPath[roundNumber] + roundNumber + 1 else: # Move Down player.participant.payoffPath[roundNumber+1] = player.participant.payoffPath[roundNumber] + roundNumber + 2 elif t == "payment": player.participant.payoffPath = player.participant.payoffPath[0:roundNumber + 1] player.participant.finalPayoff = value return { player.id_in_group: dict( type = t, value = value, roundNumber = player.participant.resolutionRound, drawn = player.participant.payoffPath, imagePathGuess = imagePathGuess, imagePathOutcome = imagePathOutcome, cardOutcome = player.participant.cardOutcomeDecoloring )} @staticmethod def vars_for_template(player): return dict( user_chosen_decision = player.participant.vars["bf"], testing = player.session.config["testing"] ) def before_next_page(player, timeout_happened): # Get continuation decision along payoff path tmp = player.participant.decoloring stopStrategy = tmp["continuation"] strategyAlongPath = [stopStrategy[node] for node in player.participant.payoffPath] #strategyAlongPath[-1] = "Stop" player.pathDrawn_bonus = str(player.participant.payoffPath) player.coinTossOutcome_bonus = str(player.participant.coinTossOutcomeDecoloring) player.continuationDec_bonus = str(strategyAlongPath) player.chosenCards_bonus = str(player.participant.chosenCardDecoloring) player.cardOutcome_bonus = str(player.participant.cardOutcomeDecoloring) # Save bonus payment player.riskyPayoff = str(player.participant.finalPayoff) class BonusPayment(Page): form_model = "player" form_fields = [ "riskyPayoff", "endowment", "totalEarnings", "showVerificationPW"] @staticmethod def is_displayed(player): return not player.participant.timeoutHappened @staticmethod def js_vars(player): bonusFileData = player.participant.bonusFileDict[player.participant.bfNumber], continuationDec = "" if (player.participant.treatment in [0,1,3]): continuationDec = ast.literal_eval(player.continuationDec_bonus) else: continuationDec = ast.literal_eval(player.cardOutcome_bonus) stopPath = "" if (player.participant.treatment in [2, 4]): stopPath = ast.literal_eval(player.continuationDec_bonus) return dict( treatment = player.participant.treatment, envelope = player.participant.bfNumber, bonusFileData = bonusFileData, continuationDec = continuationDec, player_winningSides = ast.literal_eval(player.coinTossOutcome_bonus), #player_cardNumbers = player_cardNumbers, player_path = ast.literal_eval(player.pathDrawn_bonus), min_time_on_page=player.session.config["min_time_on_page_instructions"], upTick = player.session.config['upTick'], stoppingStrat = player.participant.decoloring, initialColor = player.participant.plotColor, stopPath = stopPath, drawnCards = ast.literal_eval(player.chosenCards_bonus), ) @staticmethod def vars_for_template(player): completionFee = player.session.config['completionFee'] endowment = player.session.config['endowment'] costPerBall = player.session.config['costPerBall'] costly = player.participant.treatment == 4 or (player.participant.treatment == 3 and player.resolveRisk) # Costly studies decoloringCosts = 0 ballName = "" if costly and player.resolveRisk: # Decoloring Task is payoff relevant data = player.participant.decoloring stopStrategy = data["continuation"] costlyStops = sum(1 for x in stopStrategy if x < 100 and x != 0) decoloringCosts = costlyStops * costPerBall if player.participant.treatment == 3: ballName = "white-black-gradient" elif player.participant.treatment == 4: ballName = "numbered" elif costly and not player.resolveRisk: # Walking task in RandC stopPath = ast.literal_eval(player.continuationDec_bonus) # path cardOutcomes = ast.literal_eval(player.cardOutcome_bonus) stopIndex = 0 for idx, outcome in enumerate(cardOutcomes): if outcome == "Stop": stopIndex = idx break stopPath = stopPath[:stopIndex + 1] costlyStops = sum(1 for x in stopPath if (x < 100 and x != 0)) decoloringCosts = costlyStops * costPerBall ballName = "numbered" player.completionFee = str(completionFee) player.endowment = str(endowment) player.decoloringCosts = str(decoloringCosts) player.totalEarnings = str(float(endowment) + float(player.participant.finalPayoff) + float(completionFee) - float(decoloringCosts)) return dict( payoff = '%.2f' %float(player.riskyPayoff), completionFee = '%.2f' %float(completionFee), endowment = '%.2f' %float(endowment), decoloringCosts = '%.2f' %float(decoloringCosts), totalEarnings = '%.2f' %(float(endowment) + float(player.participant.finalPayoff) + float(completionFee) - float(decoloringCosts)), user_chosen_decision = player.participant.vars["bf"], password_bonus = player.participant.password_bonus, password_verification = player.participant.password_verification, testing = player.session.config["testing"], costly = costly, ballName = ballName, ) class RevealPWD(Page): @staticmethod def is_displayed(player): return not player.participant.timeoutHappened @staticmethod def js_vars(player): return dict( password = player.participant.password_bonus, min_time_on_page=player.session.config["min_time_on_page_instructions"],) @staticmethod def vars_for_template(player): return dict( user_chosen_decision = player.participant.vars["bf"], testing = player.session.config["testing"]) @staticmethod def before_next_page(player, timeout_happened): # Determine payoff and route player to correct page chosenFile = player.participant.bfNumber data = player.participant.bonusFileDict[chosenFile] task = data[0] # Calculate payment treeStructure = [ [0], [1,2], [3,4,5], [6,7,8,9], [10,11,12,13,14], [15,16,17,18,19,20] ] if task == "decoloring": player.bonusTask = "the Decoloring Task" player.resolveRisk = True # Initialize variables for risk resolution player.participant.resolutionRound = 0 player.participant.payoffPath = [0]*6 player.participant.coinTossOutcomeDecoloring = [-1]*6 # Coin Toss Outcome player.participant.chosenCardDecoloring = [-1] * 6 # Save chosen card player.participant.cardOutcomeDecoloring = [-1] * 6 # Save card outcome elif task == "walking" and player.participant.treatment in [0,1, 3]: taskNumber = data[2] player.bonusTask = "Walking Task " + str(data[2]) player.resolveRisk = False ## Fetch data bonusPath = player.participant.walkingPath[taskNumber] bonusDecisions = player.participant.continuationDec[taskNumber] ## Calculate payment stopRepetition = bonusDecisions.index("Stop") stopNode = bonusPath[stopRepetition] for idx, nodes in enumerate(treeStructure): if stopNode in nodes: layer = idx relativePos = nodes.index(stopNode) payment = (layer - (relativePos * 2)) * player.session.config["upTick"] player.pathDrawn_bonus = str(bonusPath) player.coinTossOutcome_bonus = str(player.participant.coinTossOutcome[taskNumber]) player.continuationDec_bonus = str(bonusDecisions) player.cardOutcome_bonus = str([""]) player.chosenCards_bonus = str([""]) # Save bonus payment player.participant.finalPayoff = payment player.riskyPayoff = str(payment) elif task == "walking" and player.participant.treatment in [2, 4]: taskNumber = data[2] player.bonusTask = "Walking Task " + str(taskNumber) player.resolveRisk = False ## Fetch data bonusPath = player.participant.walkingPath[taskNumber] bonusDecisions = player.participant.continuationDec[taskNumber] cardOutcomes = player.participant.cardOutcome[taskNumber] # Calculate payment stopRepetition = cardOutcomes.index("Stop") stopNode = bonusPath[stopRepetition] for idx, nodes in enumerate(treeStructure): if stopNode in nodes: layer = idx relativePos = nodes.index(stopNode) payment = (layer - (relativePos * 2)) * player.session.config["upTick"] player.pathDrawn_bonus = str(bonusPath) player.coinTossOutcome_bonus = str(player.participant.coinTossOutcome[taskNumber]) player.continuationDec_bonus = str(bonusDecisions) player.cardOutcome_bonus = str(cardOutcomes) player.chosenCards_bonus = str(player.participant.chosenCard[taskNumber]) # Save bonus payment player.participant.finalPayoff = payment player.riskyPayoff = str(payment) class timeoutAlert(Page): @staticmethod def is_displayed(player): return player.participant.timeoutHappened page_sequence = [ Questionnaire, RevealPWD, RiskResolution, RiskResolution_rand, BonusPayment, timeoutAlert, ]