from otree.api import * import time # 時間計測に用いる import decording_task.keydata as keydata doc = """ Your app description """ class Constants(BaseConstants): practice_round = 2 # 練習のラウンド数(実験者側で設定) production_round = 6 # 本番のラウンド数(実験者側で設定) round_minutes = 2 # 各ラウンドの所要時間(分) round_seconds = 0 # 各ラウンドの所要時間(秒) name_in_url = 'decording_task' players_per_group = None # 一人で逐次進めるための設定 num_rounds = practice_round + production_round class Subsession(BaseSubsession): pass class Group(BaseGroup): pass # 一人で実験を進める都合上、Groupに依存しなくていい class Player(BasePlayer): num_of_responses = models.IntegerField() # 回答数 num_of_digit1_correct = models.IntegerField() # 正答数 num_of_digit2_correct = models.IntegerField() # 正答数 question_field = models.StringField() start_timestamp = models.IntegerField() pass # プレイヤーのラウンド数を読み取り該当するキーを取得 # ラウンド数と該当するものがなかった場合は例外終了 def ref_key(player: Player): if player.round_number == 1: return keydata.Key1 elif player.round_number == 2: return keydata.Key2 elif player.round_number == 3: return keydata.Key3 elif player.round_number == 4: return keydata.Key4 elif player.round_number == 5: return keydata.Key5 elif player.round_number == 6: return keydata.Key6 elif player.round_number == 7: return keydata.Key7 elif player.round_number == 8: return keydata.Key8 else: raise NotImplementedError() # 本当なら最後に一気に採点できたらいいかもしれないがそれまでデータを保持する仕組みを作るのは大変そう -> 代わりに逐次採点して正誤情報のみ保持するようにする def check_answer(player, q_response, num_of_responses): answer = gen_map(player.question_field)[num_of_responses] if len(q_response) != len(answer): return False is_correct = True ans_data = list(answer) key = ref_key(player) for i in range(len(ans_data)): is_correct = key[ans_data[i]] == str.upper(q_response[i]) return is_correct def gen_map(q_field): return q_field.split(',') def generate_question(player: Player): import random import decording_task.datalistfield txt = "" digit1 = 0 digit2 = 0 for i in range(200): gen_val = 0 if random.randint(0, 1) % 2 and digit1 < 100: gen_val = random.randint(0, 9) digit1 = digit1 + 1 else: gen_val = random.randint(10, 99) digit2 = digit2 + 1 txt = datalistfield.add_data(txt, gen_val) player.question_field = txt def live_method(player: Player, data): if data: try: q_response = data['q_response'] except Exception: print('invalid message received:', data) # For developer message return if check_answer(player, q_response, player.num_of_responses): if len(q_response) == 1: player.num_of_digit1_correct = player.num_of_digit1_correct + 1 # 1桁の答えがあっている場合は正答数を増やす elif len(q_response) == 2: player.num_of_digit2_correct = player.num_of_digit2_correct + 1 # 2桁の答えがあっている場合は正答数を増やす player.num_of_responses = player.num_of_responses + 1 return { player.id_in_group: dict( num_of_responses=player.num_of_responses ) } # PAGES class Instruction(Page): @staticmethod def before_next_page(player: Player, timeout_happened): player.num_of_responses = -1 # ライブページの初期呼び出し時になぜか実行されるので-1にした(直せるなら直したい) player.num_of_digit1_correct = 0 player.num_of_digit2_correct = 0 # if 'point_list' in player.participant.vars: generate_question(player) player.start_timestamp = int(time.time()) def vars_for_template(player: Player): round_number = player.round_number if player.round_number - Constants.practice_round <= 0 else player.round_number - Constants.practice_round return dict(round_number=round_number) pass class Main(Page): live_method = live_method @staticmethod def vars_for_template(player: Player): round_number = player.round_number if player.round_number - Constants.practice_round <= 0 else player.round_number - Constants.practice_round return dict(round_number=round_number) @staticmethod def js_vars(player: Player): q_codes = gen_map(player.question_field) key = ref_key(player) return dict(key=key, q_codes=q_codes) @staticmethod def get_timeout_seconds(player: Player): import time return Constants.round_minutes * 60 + Constants.round_seconds + player.start_timestamp - time.time() # 2分測る class Results(Page): # ラウンド数とプレイヤーの獲得ポイントを計算した値を返す def vars_for_template(player: Player): round_number = player.round_number if player.round_number - Constants.practice_round <= 0 else player.round_number - Constants.practice_round point = player.num_of_digit1_correct * 20 + player.num_of_digit2_correct * 40 # 仕様にあるポイント計算 if player.round_number - Constants.practice_round > 0: # 本番の場合 if 'point_list' not in player.participant.vars: # ポイントを管理する辞書がない場合は作る player.participant.vars['point_list'] = {} player.participant.vars['point_list'][player.round_number - Constants.practice_round] = point # 辞書に登録 return dict(round_number=round_number, point=point) pass page_sequence = [Instruction, Main, Results]