from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) from django.db import models as django_models from otree.models import Participant from django.db.models.signals import post_save from django.dispatch import receiver from random import randint import time class Constants(BaseConstants): name_in_url = "karma_10" players_per_group = 10 PLAYERS_PER_GROUP = players_per_group NUM_MAIN_ROUNDS = 100 NUM_TEST_ROUNDS = 10 NUM_ROUNDS = NUM_MAIN_ROUNDS + NUM_TEST_ROUNDS num_rounds = NUM_ROUNDS NAME_IN_URL = 'karma' URGENCY_VALUES_1 = [1, 3] URGENCY_PROBABILITIES_1 = [0.5, 0.5] URGENCY_VALUES_2 = [1, 6] URGENCY_PROBABILITIES_2 = [0.8, 0.2] INITIAL_KARMA = 9 MAX_KARMA = 18 TIME_GROUPING = 10 * 60 TIME_INTRODUCTION = 4 * 60 TIME_INSTRUCTION = 3 * 60 TIME_TEST_ROUND = 20 TIME_TEST_RESULT = 20 TIME_TEST_END = 30 TIME_ROUND = 10 TIME_RESULT = 10 BASE_PAYMENT = 1.5 # MAX_BONUS_PAYMENT = 20.0 # SCORE_TO_PAYMENT_RATIO = MAX_BONUS_PAYMENT / (2.0 * NUM_MAIN_ROUNDS) # BONUS_PAYMENT_RANDOM = 1.0 BONUS_PAYMENT_RANDOM = 1.0 BONUS_PAYMENT_AVERAGE = 10.0 BONUS_PAYMENT_MAX = 20.0 RANDOM_SCORE = 0.6 * NUM_MAIN_ROUNDS AVERAGE_SCORE = 1.5 * NUM_MAIN_ROUNDS SCORE_TO_BONUS_OFFSET = (BONUS_PAYMENT_AVERAGE * RANDOM_SCORE - BONUS_PAYMENT_RANDOM * AVERAGE_SCORE) / ( RANDOM_SCORE - AVERAGE_SCORE) SCORE_TO_BONUS_FACTOR = (BONUS_PAYMENT_RANDOM - SCORE_TO_BONUS_OFFSET) / RANDOM_SCORE DROPOUT_COUNT = 10 class Subsession(BaseSubsession): counter = models.IntegerField(initial=1) def creating_session(self): self.counter = 1 players = self.get_players() if self.round_number == 1: for p in players: p.participant.vars['timeout_count'] = 0 p.participant.vars['is_dropout'] = False def group_by_arrival_time_method(self, waiting_players): if len(waiting_players) >= Constants.players_per_group: return waiting_players[:Constants.players_per_group] else: for p in waiting_players: p.participant.vars['connected'] = len(waiting_players) for p in waiting_players: if p.waiting_too_long(): # [p] means a single-player group. p.participant.vars['grouping_timeout'] = True return [p] class Group(BaseGroup): treatment_id = models.IntegerField() group_counter = models.IntegerField() total_payment = models.IntegerField() redistribution = models.FloatField() class Player(BasePlayer): karma_input = models.IntegerField( min=0, label="Please enter your bid:" ) # karma_input = models.IntegerField( # label="Please choose how you want to proceed:", # choices=[ # [0, 'Gain'], # [1, 'Maintain'], # [4, 'Spend'], # ], # widget=widgets.RadioSelect # ) urgency = models.IntegerField() is_winner = models.BooleanField(initial=False) is_tied = models.BooleanField(initial=False) is_tied_win = models.BooleanField(initial=False) is_tied_lose = models.BooleanField(initial=False) partner_id = models.IntegerField() role_id = models.IntegerField() treatment_id = models.IntegerField() group_counter = models.IntegerField() group_redistribution = models.FloatField() dropout = models.BooleanField(initial=False) karma = models.FloatField() karma_int = models.IntegerField() k_pre_redist = models.FloatField() redistribution = models.FloatField() # Grouping def waiting_too_long(self): return time.time() - self.participant.vars['wait_page_arrival'] > Constants.TIME_GROUPING