import time from otree import settings from otree.api import * from . import task_matrix from .image_utils import encode_image doc = """ Count character in characters """ # TODO: In settings einbauen um das zu zeigen def get_constants_from_settings(player): session = player.session width = session.config.get('width') C.WIDTH = width ### hier den spaß genauso machen, wenn man es von aussen setzen will pass class C(BaseConstants): NAME_IN_URL = 'count_numbers' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 HEIGHT = 10 WIDTH = 6 IGNORED_CHARS = "012345689" COUNTED_CHARS = "7" DEVIATION_GROUP = 2 ## Deviation for Group stuff INSTRUCTION_TEMPLATE = __name__ + "/instructions.html" class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): session = subsession.session defaults = dict( retry_delay=1.0, puzzle_delay=1.0, attempts_per_puzzle=1, max_iterations=None ) session.params = {} for param in defaults: session.params[param] = session.config.get(param, defaults[param]) class Group(BaseGroup): solution = models.IntegerField(initial=0) response = models.IntegerField(initial=0) is_correct = models.BooleanField(initial=False) class Player(BasePlayer): iteration = models.IntegerField(initial=0) num_trials = models.IntegerField(initial=0) num_correct = models.IntegerField(initial=0) num_failed = models.IntegerField(initial=0) # Puzzlestuff class Puzzle(ExtraModel): player = models.Link(Player) iteration = models.IntegerField(initial=0) attempts = models.IntegerField(initial=0) timestamp = models.FloatField(initial=0) text = models.LongStringField() # entw. Text oder Json (wie in Slider) solution = models.LongStringField() # genauso wie text response = models.LongStringField() response_timestamp = models.FloatField() is_correct = models.BooleanField() def gen_puzzle(player: Player) -> Puzzle: """ generate new puzzle for a player""" fields = task_matrix.generate_puzzle_fields(ignored_chars=C.IGNORED_CHARS, counted_char=C.COUNTED_CHARS, width=C.WIDTH, height=C.HEIGHT) ## Schriftgröße kann hier mitgegeben werden player.iteration += 1 return Puzzle.create( player=player, iteration=player.iteration, timestamp=time.time(), **fields # text & solution ) def get_cur_puzzle(player: Player): puzzles = Puzzle.filter(player=player, iteration=player.iteration) if puzzles: [puzzle] = puzzles return puzzle def enc_puzzle(puzzle: Puzzle): image = task_matrix.render_image(puzzle) return dict(image=encode_image(image)) def get_progess(player:Player): return dict( num_trials= player.num_trials, num_correct = player.num_correct, num_incorrect = player.num_failed, iteration = player.iteration ) def play_game(player: Player, msg: dict): ## siehe slider session = player.session my_id = player.id_in_group params = session.params now = time.time() current = get_cur_puzzle(player) msg_type = msg['type'] if msg_type == 'load': prog = get_progess(player) if current: return { my_id: dict(type='status',progress=prog, puzzle=enc_puzzle(current)) } else: return {my_id: dict(type='status',progress=prog)} if msg_type == 'cheat' and settings.DEBUG: return {my_id: dict(type='solution', solution=current.solution)} if msg_type == 'next': if current is not None: if current.response is None: raise RuntimeError('trying to skip over unsolved puzzle') if now < current.timestamp + params["puzzle_delay"]: raise RuntimeError('retrying too fast') if current.iteration == params['max_iterations']: return { my_id: dict(type='status', progess=get_progess(player), iterations_left=0) } puzz = gen_puzzle(player) prog = get_progess(player) return {my_id: dict(type='puzzle', puzzle=enc_puzzle(puzz), progress=prog)} if msg_type == 'answer': if current is None: raise RuntimeError('trying to answer no puzzle') if current.response is not None: if current.attempts >= params['attempts_per_puzzle']: raise RuntimeError('no more attempts allowed') if now < current.response_timestamp + params['retry_delay']: raise RuntimeError('retrying too fast') player.num_trials -=1 if current.is_correct: player.num_correct-= 1 else: player.num_failed -= 1 answer = msg['answer'] if answer == '' or answer is None: raise ValueError('Answer is empty ') current.response = answer current.is_correct = task_matrix.is_correct(answer,current) current.response_timestamp = now current.attempts +=1 if current.is_correct: player.num_correct += 1 else: player.num_failed +=1 player.num_trials += 1 tries_left = params['attempts_per_puzzle'] - current.attempts prog = get_progess(player) return { my_id: dict( type='feedback', is_correct=current.is_correct, retries_left = tries_left, progress=prog, ) } raise RuntimeError("unrecognized message from client") def calculate_group_findings(player:Player): pass # PAGES class Spiel(Page): timeout_seconds = 60 live_method = play_game @staticmethod def js_vars(player: Player): return dict(params=player.session.params) @staticmethod def vars_for_template(player: Player): return dict(DEBUG=settings.DEBUG, input_type=task_matrix.INPUT_TYPE, placeholder=task_matrix.INPUT_HINT) @staticmethod def before_next_page(player: Player, timeout_happened): if not timeout_happened and not player.session.params['max_iterations']: raise RuntimeError("malicious page submission") if C.PLAYERS_PER_GROUP is not None and C.PLAYERS_PER_GROUP > 1: ### An der Stelle Zusammenrechnen der Gruppenberechnung machen, bzw in der Gruppe speichern current = get_cur_puzzle(player) player.group.solution += current.solution player.group.response += current.response pass class Group_Stage(Page): @staticmethod def is_displayed(player: Player): return C.PLAYERS_PER_GROUP is not None and C.PLAYERS_PER_GROUP > 1 ### nur wenn es eine Gruppe gibt @staticmethod def vars_for_template(player: Player): calculate_group_findings(player) return dict()## hier dict füllen wenn ihr was anzeigen wollt für den spaß class Results(Page): pass page_sequence = [Spiel,Group_Stage, Results]