from otree.api import * from . import * from enum import Enum from settings import STRATEGIES, ROUNDS_PER_STRATEGY class Case(Enum): TIMEOUT_GENERAL_INTRODUCTION = "oneapp_two Timeout GeneralIntroduction" TIMEOUT_ATTENTION_CHECK = "oneapp_two Timeout AttentionCheck" ATTENTION_CHECK_FAILED = "oneapp_two AttentionCheck Failed" ATTENTION_CHECK_PASSED = "oneapp_two AttentionCheck Passed" TIMEOUT_INTRODUCTION = "oneapp_two Timeout Introduction" TIMEOUT_DECISION = "oneapp_two Timeout Decision" DECISION_ALWAYS_CORRECT = "oneapp_two Decision always correct" DECISION_SOMETIMES_CORRECT_WRONG_BEGINNING = "oneapp_two Decision sometimes correct wrong beginning" DECISION_SOMETIMES_CORRECT_WRONG_MIDDLE = "oneapp_two Decision sometimes correct wrong middle" DECISION_ALWAYS_WRONG = "oneapp_two Decision always wrong" TIMEOUT_RESULTS = "oneapp_two Timeout results" class PlayerBot(Bot): cases = [case.value for case in [ Case.TIMEOUT_GENERAL_INTRODUCTION, Case.TIMEOUT_ATTENTION_CHECK, Case.ATTENTION_CHECK_FAILED, Case.ATTENTION_CHECK_PASSED, Case.TIMEOUT_INTRODUCTION, Case.TIMEOUT_DECISION, Case.DECISION_ALWAYS_CORRECT, Case.DECISION_SOMETIMES_CORRECT_WRONG_BEGINNING, Case.DECISION_SOMETIMES_CORRECT_WRONG_MIDDLE, Case.DECISION_ALWAYS_WRONG, Case.TIMEOUT_RESULTS ]] def play_round(self): translation = {0: "Y", 1: "X"} if self.player.participant.timeout or self.player.participant.order == 2: print(f"Skipping case {self.case}") return print(f"Playing case {self.case}") if self.player.round_number == 1: # GeneralIntroduction expect("You will now be asked to choose between", "in", self.html) if self.case == Case.TIMEOUT_GENERAL_INTRODUCTION.value: yield Submission( GeneralIntroduction, timeout_happened=True, ) expect("You ran out of time", "in", self.html) expect(self.player.participant.timeout, True) return yield Submission(GeneralIntroduction) # AttentionCheck expect("What is 7-5?", "in", self.html) if self.case == Case.TIMEOUT_ATTENTION_CHECK.value: yield Submission( AttentionCheck, timeout_happened=True, ) expect("You ran out of time", "in", self.html) expect(self.player.participant.timeout, True) return if self.case == Case.ATTENTION_CHECK_FAILED.value: yield Submission(AttentionCheck, {"attention_check": 3}) expect(self.player.participant.attention_check_failed, True) else: previous = self.player.participant.attention_check_failed yield Submission(AttentionCheck, {"attention_check": 2}) if not previous: expect(self.player.participant.attention_check_failed, False) # Introduction expect("Strategy Instructions", "in", self.html) if self.player.participant.treatment_rule == "TfT": expect("Choose X in round 1. After round 1: choose X if the computer chose X in " "the previous round.", "in", self.html) elif self.player.participant.treatment_rule == "Tf3T": expect("Choose X until the other has chosen Y three times", "in", self.html) else: raise ValueError(f"App not tested for treatment {self.player.participant.treatment_rule}. " f"Please make sure that everything works as expected and ideally extend the " f"test code to cover your added treatment.") if self.case == Case.TIMEOUT_INTRODUCTION.value: yield Submission( Introduction, timeout_happened=True, ) expect("You ran out of time", "in", self.html) expect(self.player.participant.timeout, True) return current_time = datetime.now() yield Submission(Introduction) expect((self.player.participant.last_timestamp-current_time).total_seconds(), "<", 0.5) # Decision expect("Make your choice", "in", self.html) if self.player.participant.treatment_reminder == "Baseline": expect("Choose", "not in", self.html) expect("function checkSubmit()", "not in", self.html) expect("Previous choices:", "not in", self.html) elif self.player.participant.treatment_reminder == "Strategy reminder": expect("function checkSubmit()", "not in", self.html) expect("Previous choices:", "in", self.html) if self.player.participant.treatment_rule == "TfT": expect("Choose X in round 1.", "in", self.html) elif self.player.participant.treatment_rule == "Tf3T": expect("Choose X until the other has chosen Y three times", "in", self.html) elif self.player.participant.treatment_reminder == "Action reminder": expect("Choose", "not in", self.html) expect("Previous choices:", "not in", self.html) expect("function checkSubmit()", "in", self.html) elif self.player.participant.treatment_reminder == "Strategy and action reminder": expect("function checkSubmit()", "in", self.html) expect("Previous choices:", "in", self.html) if self.player.participant.treatment_rule == "TfT": expect("Choose X in round 1.", "in", self.html) elif self.player.participant.treatment_rule == "Tf3T": expect("Choose X until the other has chosen Y three times", "in", self.html) else: raise ValueError("Unexpected treatment") else: raise ValueError( f"App not tested for treatment {self.player.participant.treatment_reminder}. " f"Please make sure that everything works as expected and ideally extend the " f"test code to cover your added treatment.") if self.case == Case.TIMEOUT_DECISION.value: yield Submission( Decision, check_html=False, timeout_happened=True, ) expect("You ran out of time", "in", self.html) expect(self.player.participant.timeout, True) return if self.case == Case.DECISION_ALWAYS_WRONG.value: if self.player.participant.treatment_rule == "TfT": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 0}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: current_time = datetime.now() yield Submission( Decision, {"choice": 1-self.player.in_round(self.player.round_number - 1).computer_choice }, check_html=False) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) elif self.player.participant.treatment_rule == "Tf3T": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 0}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: count_computer_y = 0 for round_nr in range(1, self.player.round_number): comp_choice = self.player.in_round( round_nr).computer_choice if comp_choice == 0: count_computer_y += 1 continue elif count_computer_y >= 3: count_computer_y = 0 if count_computer_y >= 3: choice = 1 else: choice = 0 current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": choice}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect(eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: raise ValueError("Unexpected treatment") expect(self.player.participant.payment, "==", False) if self.player.round_number == ROUNDS_PER_STRATEGY: expect(self.player.participant.sft_pay, "==", 0) elif self.case == Case.DECISION_SOMETIMES_CORRECT_WRONG_BEGINNING.value: if self.player.participant.treatment_rule == "TfT": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 0}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: current_time = datetime.now() yield Submission( Decision, {"choice": self.player.in_round(self.player.round_number - 1).computer_choice }, check_html=False) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) elif self.player.participant.treatment_rule == "Tf3T": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 0}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: count_computer_y = 0 for round_nr in range(1, self.player.round_number): comp_choice = self.player.in_round( round_nr).computer_choice if comp_choice == 0: count_computer_y += 1 continue elif count_computer_y >= 3: count_computer_y = 0 if count_computer_y >= 3: choice = 0 else: choice = 1 current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": choice}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: raise ValueError("Unexpected treatment") expect(self.player.participant.payment, "==", False) if self.player.round_number == ROUNDS_PER_STRATEGY: expect(self.player.participant.sft_pay, "==", 0) elif self.case == Case.DECISION_SOMETIMES_CORRECT_WRONG_MIDDLE.value: if self.player.participant.treatment_rule == "TfT": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 1}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) elif self.player.round_number == 5: current_time = datetime.now() yield Submission( Decision, {"choice": 1 - self.player.in_round(self.player.round_number - 1).computer_choice }, check_html=False) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: current_time = datetime.now() yield Submission( Decision, {"choice": self.player.in_round(self.player.round_number - 1).computer_choice }, check_html=False) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) elif self.player.participant.treatment_rule == "Tf3T": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 1}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: if self.player.round_number != 5: count_computer_y = 0 for round_nr in range(1, self.player.round_number): comp_choice = self.player.in_round( round_nr).computer_choice if comp_choice == 0: count_computer_y += 1 continue elif count_computer_y >= 3: count_computer_y = 0 if count_computer_y >= 3: choice = 0 else: choice = 1 current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": choice}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: count_computer_y = 0 for round_nr in range(1, self.player.round_number): comp_choice = self.player.in_round( round_nr).computer_choice if comp_choice == 0: count_computer_y += 1 continue elif count_computer_y >= 3: count_computer_y = 0 if count_computer_y >= 3: choice = 1 else: choice = 0 current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": choice}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: raise ValueError("Unexpected treatment") if self.player.round_number >= 5: expect(self.player.participant.payment, "==", False) else: expect(self.player.participant.payment, "==", True) if self.player.round_number == ROUNDS_PER_STRATEGY: expect(self.player.participant.sft_pay, "==", 0) else: # Always correct if self.player.participant.treatment_rule == "TfT": if self.player.round_number == 1: current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": 1}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: current_time = datetime.now() yield Submission( Decision, {"choice": self.player.in_round(self.player.round_number - 1).computer_choice }, check_html=False) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect( eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) elif self.player.participant.treatment_rule == "Tf3T": count_computer_y = 0 for round_nr in range(1, self.player.round_number): comp_choice = self.player.in_round( round_nr).computer_choice if comp_choice == 0: count_computer_y += 1 continue elif count_computer_y >= 3: count_computer_y = 0 if count_computer_y >= 3: choice = 0 else: choice = 1 current_time = datetime.now() yield Submission(Decision, check_html=False, post_data={"choice": choice}) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5) expect(eval(f"self.player.participant.seconds_round_{self.player.round_number}") - (current_time - self.player.participant.last_timestamp).total_seconds(), "<", 0.5) else: raise ValueError("Unexpected treatment") expect(self.player.participant.payment, "==", True) if self.player.round_number == ROUNDS_PER_STRATEGY: expect(self.player.participant.sft_pay, "==", 2) # Results expect(f"You chose to play { translation[self.player.choice] }. The computer played " f"{ translation[self.player.computer_choice] }.", "in", self.html) if self.case == Case.TIMEOUT_RESULTS.value: yield Submission( Results, timeout_happened=True, ) expect("You ran out of time", "in", self.html) expect(self.player.participant.timeout, True) return current_time = datetime.now() yield Submission(Results) expect((self.player.participant.last_timestamp - current_time).total_seconds(), "<", 0.5)