# -*- coding: utf-8 -*- # from otree.api import * import csv import settings import time # author = 'Jan Romann (jan.romann@uni-bremen.de), ' \ 'Patricia Zauchner (zauchner@uni-bremen.de)' doc = """ Effort task: Answer as many questions as possible. """ class C(BaseConstants): NAME_IN_URL = 'effort_trivial' PLAYERS_PER_GROUP = 5 # Not really necessary in effort tasks. But so it looks better in the data TASK_TIMER = settings.task_timer NUM_ROUNDS = 1 POINTS_PER_CORRECT_ANSWER = 1 # Numbers for the effort task. Could also be randomly generated or derived from excel spreadsheet with open('effort_trivial/questions.csv', encoding="utf-8") as csvfile: reader = csv.reader(csvfile) next(reader, None) # skip the headers QUESTIONS = list(reader) NUM_TASKS = len(QUESTIONS) class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): # # 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 effort_trivial", subsession.session.vars['id_matrix']) # # try: subsession.session.vars["do_effort_task"] = subsession.session.config["do_effort_task"] except KeyError: subsession.session.vars["do_effort_task"] = getattr(settings, "do_effort_task", True) # Set session vars (For counting number of effort apps in effort_intro) subsession.session.vars["DoEffort_Trivial"] = True # class Group(BaseGroup): pass def get_question(index): current_question = C.QUESTIONS[index] return { "question": current_question[0], "false_answer_1": current_question[1], "false_answer_2": current_question[2], "false_answer_3": current_question[3], "correct_answer": current_question[4], } def live_answer_question(player, data): player.question_index = index = player.question_index + 1 new_question_data = get_question(index) # Get new numbers answer = int(data.get("answer", 0)) Answer.create(player=player, question_number=index - 1, answer=answer) # Save answer in database # Check if the answer was correct (correct value is always 4) player.last_answer_correct = answer_correct = answer == 4 player.number_of_attempts = number_of_attempts = player.number_of_attempts + 1 # Increment number of attempts # Retrieve old number of right guesses from the database number_of_correct_answers = player.number_of_correct_answers # If correct, increment number of correct guesses and, at the same time, write new value back to the database if answer_correct: player.number_of_correct_answers = number_of_correct_answers = number_of_correct_answers + 1 response = { "question": new_question_data["question"], "false_answer_1": new_question_data["false_answer_1"], "false_answer_2": new_question_data["false_answer_2"], "false_answer_3": new_question_data["false_answer_3"], "correct_answer": new_question_data["correct_answer"], "answer_correct": answer_correct, "number_of_attempts": number_of_attempts, "number_of_correct_answers": number_of_correct_answers, } return {player.id_in_group: response} class Player(BasePlayer): question_index = models.IntegerField( doc="The number of the current task (for iterating through the list of values).", initial=0) number_of_correct_answers = models.IntegerField( doc="Number of correct answers in total.", initial=0) number_of_attempts = models.IntegerField( doc="Number of attempts in total.", initial=0) last_answer_correct = models.BooleanField( doc="Did the user answer the last question correctly?", initial=False) class Answer(ExtraModel): """ Creates an extra dataframe output. Is called with custom_export """ player = models.Link(Player) question_number = models.IntegerField() answer = models.IntegerField() def custom_export(players): """ Custom export xlsx/csv """ yield ['session_code', 'participant_code', 'question_number', "answer", "correct"] # Header row for answer in Answer.filter(): player = answer.player session = player.session participant = player.participant correct = 1 if 4 == answer.answer else 0 yield [session.code, participant.code, answer.question_number, answer.answer, correct] # Pages class EffortPage(Page): """ Handles if other pages are displayed """ @staticmethod def is_displayed(player): return player.session.vars.get("do_effort_task", True) class Intro(EffortPage): """ Introduction to the trivial task """ @staticmethod def before_next_page(player, timeout_happened): # User has task_timer seconds to complete as many pages as possible player.participant.vars['expiry_timestamp'] = time.time() + C.TASK_TIMER class Task(EffortPage): """ Trivial task """ live_method = 'live_answer_question' @staticmethod def get_timeout_seconds(player): return player.participant.vars['expiry_timestamp'] - time.time() timer_text = 'Verbleibende Zeit (in Sek.): ' @staticmethod def vars_for_template(player): index = player.question_index question_data = get_question(index) return { "question": question_data["question"], "false_answer_1": question_data["false_answer_1"], "false_answer_2": question_data["false_answer_2"], "false_answer_3": question_data["false_answer_3"], "correct_answer": question_data["correct_answer"], "debug": False } @staticmethod def before_next_page(player, timeout_happened): correct_answers = player.number_of_correct_answers player.participant.vars["trivialpoints"] = correct_answers player.participant.vars["trivialmistakes"] = player.number_of_attempts - correct_answers class Results(EffortPage): """ Results of trivial task """ pass page_sequence = [ Intro, Task, Results ]