from otree.api import * import random import timeit from datetime import datetime as dt doc = """""" class C(BaseConstants): NAME_IN_URL = 'luck&skill' PLAYERS_PER_GROUP = None NUM_BLOCKS = 1 REPEATED_ROUNDS = 40 PRACTICE_ROUNDS = 3 NUM_ROUNDS = NUM_BLOCKS*REPEATED_ROUNDS + PRACTICE_ROUNDS + 1 show_up_fee = 0.8 QUESTIONS = [ {"Which philosopher is associated with the concept of the 'veil of ignorance'?": ["John Stuart Mill", "Immanuel Kant", "John Rawls", "Friedrich Nietzsche", "Jean-Jacques Rousseau", "Aristotle"]}, {"What is the capital city of Mongolia?": ["Moshkntar", "Astana", "Ulaanbaatar", "Bishkek", "Tashkent", "Dushanbe"]}, {"Which ancient civilization built the city of Machu Picchu?": ["Aztecs", "Egyptians", "Greeks", "Incas", "Romans", "Mayans"]}, {"In Greek mythology, who is the goddess of home, family, and domesticity?": ["Aphrodite", "Hera", "Demeter", "Athena", "Artemis", "Hestia"]}, {"What is the term for the psychological phenomenon where people of higher ability tend to perform lower than their actual ability in competitive situations?": ["Dunning-Kruger effect", "Imposter syndrome", "Cognitive dissonance", "Hawthorne effect", "Stockholm syndrome", "Pygmalion effect"]}, {"How many legs does a cat have?": ["Two", "Four", "Six", "Eight", "Ten", "Twelve"]}, {"Who was the architect of the United States Capitol building in Washington, D.C.?": ["Frank Lloyd Wright", "I. M. Pei", "William Thornton", "Thomas Jefferson", "Daniel Burnham", "Frederick Law Olmsted"]}, {"Which famous physicist developed the theory of general relativity?": ["Isaac Newton", "Niels Bohr", "Albert Einstein", "Max Planck", "Werner Heisenberg", "Marie Curie"]}, {"Who was the first name of the mathematician responsible for Fermat's Last Theorem?": ["Simon", "Carl", "Pierre", "Andrew", "Leonhard", "Évariste"]}, {"Which element is the most abundant in the Earth's crust?": ["Iron", "Oxygen", "Silicon", "Aluminum", "Calcium", "Sodium"]}, {"Which ancient Greek mathematician is credited with the discovery of the method of exhaustion, a precursor to calculus?": ["Euclid", "Pythagoras", "Archimedes", "Diophantus", "Thales", "Apollonius"]}, {"Who wrote the classic novel 'One Hundred Years of Solitude'?": ["Gabriel García Márquez", "Isabel Allende", "Julio Cortázar", "Jorge Luis Borges", "Mario Vargas Llosa", "Carlos Fuentes"]}, {"What is the chemical symbol for the element gold?": ["Au", "Ag", "Fe", "Cu", "Pt", "Hg"]}, {"In which year did the Russian Revolution, leading to the establishment of the Soviet Union, take place?": ["1905", "1917", "1923", "1930", "1945", "1956"]}, {"Which ancient civilization developed the first known positional numeral system, the precursor to our modern number system?": ["Roman", "Babylonian", "Greek", "Egyptian", "Mayan", "Chinese"]}, {"Which Shakespearean play features the famous line, 'To be, or not to be: that is the question'?": ["Hamlet", "Macbeth", "Romeo and Juliet", "Othello", "King Lear", "Julius Caesar"]}, {"Which chemical element has the highest melting point?": ["Tungsten", "Platinum", "Titanium", "Osmium", "Rhenium", "Iridium"]}, {"In which year did the first modern Olympic Games take place?": ["1886", "1892", "1898", "1904", "1876", "1896"]}, {"What is the name of the theoretical framework that aims to reconcile general relativity and quantum mechanics?": ["Quantum field theory", "Loop quantum gravity", "M-theory", "String theory", "Grand Unified Theory", "Supersymmetry"]}, {"In computer science, what does the acronym 'DNS' stand for?": ["Dynamic Network Services", "Domain Name System", "Digital Network Security", "Data Node Server", "Distributed Network Storage", "Domain Naming Service"]}, {"What is the capital of France?": ["Berlin", "Madrid", "Paris", "Rome", "London", "Beijing"]}, {"Which country was the first non-host to win the FIFA World Cup twice consecutively, achieving this feat in 1934 and 1938?": ["Brazil", "Italy", "Germany", "Argentina", "Uruguay", "England"]}, {"What ancient civilization is credited with the invention of the wheel?": ["Roman", "Greek", "Sumerian", "Egyptian", "Chinese", "Indus Valley"]}, {"Who composed the famous classical piece 'The Four Seasons'?": ["Ludwig van Beethoven", "Wolfgang Amadeus Mozart", "Antonio Vivaldi", "Johann Sebastian Bach", "Franz Schubert", "Pyotr Ilyich Tchaikovsky"]}, {"What is the capital city of Bhutan?": ["Kathmandu", "Thimphu", "Dhaka", "Ulaanbaatar", "Colombo", "Islamabad"]}, {"In literature, what does the term 'bildungsroman' refer to?": ["Epic poem", "Coming-of-age novel", "Satirical play", "Historical biography", "Philosophical treatise", "Mystery thriller"]}, {"Which planet is known as the 'Morning Star' or the 'Evening Star' and is often visible shortly before sunrise or after sunset?": ["Mars", "Venus", "Mercury", "Jupiter", "Saturn", "Uranus"]}, {"What is the primary component of Earth's atmosphere?": ["Oxygen", "Nitrogen", "Carbon dioxide", "Argon", "Hydrogen", "Helium"]}, {"What is the largest planet in our solar system?": ["Earth", "Jupiter", "Mars", "Saturn", "Venus", "Neptune"]}, {"Who wrote the dystopian novel 'Brave New World'?": ["Aldous Huxley", "George Orwell", "Ray Bradbury", "Margaret Atwood", "Yevgeny Zamyatin", "H.G. Wells"]}, {"Which famous detective novel features the fictional detective Hercule Poirot?": ["The Hound of the Baskervilles", "Murder on the Orient Express", "The Maltese Falcon", "The Big Sleep", "Agatha Christie", "The Murder of Roger Ackroyd"]}, {"Which programming language is known for its use in statistical computing and analysis?": ["Python", "R", "Java", "C++", "Ruby", "Swift"]}, {"Which of the following mathematical constants represents the ratio of a circle's circumference to its diameter?": ["π", "φ", "ε", "ψ", "γ", "τ"]}, {"Who is the author of the science fiction novel 'Dune'?": ["Isaac Asimov", "Arthur C. Clarke", "H.G. Wells", "Philip K. Dick", "Ray Bradbury", "Frank Herbert"]}, {"What is the currency of the United States?": ["Euro", "Pound Sterling", "Yen", "Dollar", "Rupee", "Peso"]}, {"Who is the famous fictional spy created by author Ian Fleming?": ["Jason Bourne", "Jack Ryan", "James Bond", "George Smiley", "Hercule Poirot", "Sherlock Holmes"]}, {"Which ancient Greek philosopher is often referred to as the 'Laughing Philosopher'?": ["Socrates", "Democritus", "Heraclitus", "Thales", "Anaxagoras", "Parmenides"]}, {"In which country would you find the ancient city of Petra, famous for its rock-cut architecture?": ["Greece", "Italy", "Egypt", "Jordan", "Turkey", "Lebanon"]}, {"In literature, which Shakespearean play features the character Iago as its primary antagonist?": ["Hamlet", "Macbeth", "Romeo and Juliet", "Othello", "King Lear", "Julius Caesar"]}, {"What is the term for the phenomenon where a liquid spontaneously moves up a narrow tube against the force of gravity?": ["Capillary action", "Osmotic pressure", "Viscosity", "Surface tension", "Brownian motion", "Pascal's principle"]} ] CORRECT_ANS = ["John Rawls", "Ulaanbaatar", "Incas", "Hestia", "Dunning-Kruger effect", "Four", "William Thornton", "Albert Einstein", "Pierre", "Oxygen", "Archimedes", "Gabriel García Márquez", "Au", "1917", "Babylonian", "Hamlet", "Tungsten", "1896", "String theory", "Domain Name System", "Paris", "Italy", "Sumerian", "Antonio Vivaldi", "Thimphu", "Coming-of-age novel", "Venus", "Nitrogen", "Jupiter", "Aldous Huxley", "Murder on the Orient Express", "R", "π", "Frank Herbert", "Dollar", "James Bond", "Democritus", "Jordan", "Othello", "Capillary action"] class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): show_up_fee = models.CurrencyField() is_mobile = models.BooleanField(initial=False) is_dropout = models.BooleanField(initial=False, blank=True) prolific_id = models.StringField(label="Prolific ID: ") gender = models.StringField(label="Gender: ", choices=["Man", "Woman", "Other"]) age = models.IntegerField(label="Age") total_time_taken_min = models.StringField() time_ended_utc = models.StringField() consent = models.BooleanField(label="", choices=[[True, 'CONSENT - I consent to participate in the study and agree to the collection, storage, and use of my data.'], [False, 'DO NOT CONSENT - I do not consent to participate in the study and wish to quit the site.'] ]) condition = models.StringField() low_points = models.IntegerField() high_points = models.IntegerField() yes_side = models.StringField() die_outcome = models.IntegerField() chose_yes = models.BooleanField() rt_think_ms = models.FloatField() rt_choice_ms = models.FloatField() trivia_ans = models.StringField(blank=True, widget=widgets.RadioSelect, initial="no trivia", label="") rt_trivia_ms = models.FloatField() correct_ans = models.StringField(initial="no trivia") bonus = models.CurrencyField() bonus_chosen_round = models.IntegerField() finished = models.BooleanField(initial=False) def creating_session(subsession: Subsession): if subsession.round_number == 1: start = timeit.default_timer() for p in subsession.get_players(): print(f'plyaer num: {p.id_in_group}') participant = p.participant chosen_cond = random.choice(["One-shot", "Repeated"]) yes_side = random.choice(["right", "left"]) for p_r in p.in_rounds(1, C.NUM_ROUNDS): p_r.show_up_fee = cu(C.show_up_fee) p_r.yes_side = yes_side p_r.condition = chosen_cond p_r.low_points = 0 p_r.high_points = 1 participant.show_up_fee = p_r.show_up_fee participant.yes_side = p_r.yes_side participant.condition = p_r.condition stop = timeit.default_timer() print('Time to create session: ', (stop - start)/60) def trivia_ans_choices(player): if player.condition == "Repeated": question_pos = 0 else: question_pos = player.round_number - C.PRACTICE_ROUNDS - 2 question = list(C.QUESTIONS[question_pos].keys())[0] answers = C.QUESTIONS[question_pos][question] return answers def trivia_ans_error_message(plauer, value): if value == "no trivia": return 'Please select one of the above answers.' # def prolific_id_error_message(player, value): # if len(value) != 24: # return 'Prolific ID should be exactly 24 characters.' def age_error_message(player, value): if value < 18: return "You must be over 18 to participate." def get_time_taken(curr_timestamp, time_started): if "." in time_started: diff_timestamp = curr_timestamp - dt.strptime(time_started[:time_started.rfind(".")], '%Y-%m-%d %H:%M:%S').timestamp() else: diff_timestamp = curr_timestamp - dt.strptime(ptime_started, '%Y-%m-%d %H:%M:%S').timestamp() minutes, seconds = divmod(int(diff_timestamp), 60) while minutes >= 60 or minutes < 0: if minutes >= 60: minutes -= 60 else: minutes += 60 time_difference = f"{minutes}:{seconds:02d}" return time_difference # PAGES class Consent(Page): form_model = 'player' form_fields = ['consent', 'is_mobile', 'is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == 1 def vars_for_template(player: Player): return {"max_bonus" : (player.high_points*2)/100} def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout or not player.consent: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True for p_r in player.in_rounds(1, C.NUM_ROUNDS): p_r.consent = player.consent p_r.is_mobile = player.is_mobile class Demographics(Page): form_model = 'player' form_fields = ['prolific_id', 'gender', 'age', 'is_dropout'] timeout_seconds = 60*5 def is_displayed(player): return player.round_number == 1 def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True for p_r in player.in_rounds(1, C.NUM_ROUNDS): p_r.prolific_id = player.prolific_id p_r.age = player.age p_r.gender = player.gender class InitialInstructions(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == 1 def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True class PracticeOneShot(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == 1 and player.condition == "One-shot" def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True class PracticeRepeated(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == 1 and player.condition == "Repeated" def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True class PracticeEndedOneShot(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == C.PRACTICE_ROUNDS and player.condition == "One-shot" class PracticeEndedRepeated(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): return player.round_number == C.PRACTICE_ROUNDS and player.condition == "Repeated" class ThinkNumber(Page): form_model = 'player' form_fields = ['is_dropout','rt_think_ms'] timeout_seconds = 60*5 def is_displayed(player: Player): if player.round_number <= C.PRACTICE_ROUNDS + C.REPEATED_ROUNDS and player.condition == "Repeated": return True elif player.round_number <= C.PRACTICE_ROUNDS + 1 and player.condition == "One-shot": return True else: return False def vars_for_template(player: Player): if player.round_number <= C.PRACTICE_ROUNDS: text = "This is a practice round" else: text = "" return { "text": text } def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True class RollChoice(Page): form_model = 'player' form_fields = ['is_dropout','chose_yes', 'rt_choice_ms', 'die_outcome'] timeout_seconds = 60*5 def is_displayed(player: Player): if player.round_number <= C.PRACTICE_ROUNDS + C.REPEATED_ROUNDS and player.condition == "Repeated": return True elif player.round_number <= C.PRACTICE_ROUNDS + 1 and player.condition == "One-shot": return True else: return False def vars_for_template(player: Player): if player.yes_side == "right": on_right = "Yes" on_left = "No" else: on_right = "No" on_left = "Yes" if player.round_number <= C.PRACTICE_ROUNDS: title = "This is a practice round" else: title = "" if player.condition == "One-shot": note = "Note: you will receive a £1 bonus only if you report “Yes”." else: note = 'Note: If this round will be selected, you will receive a £1 bonus only if you report "Yes".' return { 'right': on_right, 'left': on_left, 'title': title, 'note': note } def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True class MindGameCompleted(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60*5 def is_displayed(player: Player): if player.round_number == C.PRACTICE_ROUNDS + C.REPEATED_ROUNDS and player.condition == "Repeated": return True elif player.round_number == C.PRACTICE_ROUNDS + 1 and player.condition == "One-shot": return True else: return False class TriviaInsOneShot(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60 * 5 def is_displayed(player: Player): return player.round_number == C.PRACTICE_ROUNDS + 2 and player.condition == "One-shot" class TriviaInsRepeated(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60 * 5 def is_displayed(player: Player): return player.round_number == C.PRACTICE_ROUNDS + C.REPEATED_ROUNDS + 1 and player.condition == "Repeated" class TriviaGame(Page): form_model = 'player' form_fields = ['is_dropout', 'trivia_ans', 'rt_trivia_ms'] timeout_seconds = 60*5 def is_displayed(player: Player): # Displays the page in the relevant rounds according to condition if player.round_number > C.PRACTICE_ROUNDS + C.REPEATED_ROUNDS and player.condition == "Repeated": return True elif player.round_number > C.PRACTICE_ROUNDS + 1 and player.condition == "One-shot": return True else: return False def vars_for_template(player: Player): # For repeated get the first question; For one-shot from the first question to 40th if player.condition == "Repeated": question_pos = 0 else: question_pos = player.round_number - C.PRACTICE_ROUNDS - 2 question = list(C.QUESTIONS[question_pos].keys())[0] answers = C.QUESTIONS[question_pos][question] return {"question": question, } def before_next_page(player: Player, timeout_happened): if timeout_happened or player.is_dropout: for p in player.in_rounds(1, C.NUM_ROUNDS): p.is_dropout = True if player.condition == "Repeated": question_pos = 0 else: question_pos = player.round_number - C.PRACTICE_ROUNDS - 2 question = list(C.QUESTIONS[question_pos].keys())[0] answers = C.QUESTIONS[question_pos][question] if player.trivia_ans == C.CORRECT_ANS[question_pos]: player.correct_ans = "correct" else: player.correct_ans = "not correct" class DropOut(Page): form_model = 'player' form_fields = ['total_time_taken_min'] timeout_seconds = 60 * 5 def is_displayed(player: Player): if player.is_dropout or player.consent == 0 or player.is_mobile: end_time = dt.now().strftime('%Y-%m-%d %H:%M:%S') curr_timestamp = dt.now().timestamp() time_difference = get_time_taken(curr_timestamp, player.participant.time_started_utc) for p_r in player.in_rounds(1, C.NUM_ROUNDS): p_r.total_time_taken_min = time_difference p_r.time_ended_utc = end_time return player.is_dropout or player.consent == 0 or player.is_mobile class EndPage(Page): form_model = 'player' form_fields = ['is_dropout'] timeout_seconds = 60 * 5 def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS def js_vars(player: Player): return { 'start_utc': player.participant.time_started_utc, } def vars_for_template(player: Player): import random if player.condition == "Repeated": chosen_round = random.randint(4,C.NUM_ROUNDS - 1) else: chosen_round = 4 bonus = int(player.in_round(chosen_round).chose_yes) for p_r in player.in_rounds(1, C.NUM_ROUNDS): p_r.bonus = Currency(bonus) p_r.bonus_chosen_round = chosen_round player.payoff = player.bonus print("Endpage:",player.round_number) return {"bonus": bonus} def before_next_page(player: Player, timeout_happened): end_time = dt.now().strftime('%Y-%m-%d %H:%M:%S') curr_timestamp = dt.now().timestamp() time_difference = get_time_taken(curr_timestamp, player.participant.time_started_utc) player.participant.finished = True for p_r in player.in_rounds(1, C.NUM_ROUNDS): p_r.total_time_taken_min = time_difference p_r.time_ended_utc = end_time p_r.finished = True class CloseWindow(Page): def is_displayed(player: Player): return player.consent == 0 or player.is_mobile == 1 or player.finished == 1 page_sequence = [ Consent, DropOut, Demographics, DropOut, InitialInstructions, DropOut, PracticeOneShot, PracticeRepeated, DropOut, ThinkNumber, DropOut, RollChoice, DropOut, PracticeEndedOneShot, PracticeEndedRepeated, DropOut, MindGameCompleted, DropOut, TriviaInsOneShot, TriviaInsRepeated, DropOut, TriviaGame, DropOut, EndPage, CloseWindow ]