from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import random import itertools from collections import defaultdict import numpy as np from django import forms from django.forms import widgets as django_widgets import math import time author = 'Jindi Huang' doc = """ Game Complexity """ class Constants(BaseConstants): name_in_url = 'game_stage1_twoauction' players_per_group = 3 round_per_game = 5 game_num = 4 num_rounds = game_num * (round_per_game + 2) signal_interval = 1 signal_max = 45 signal_num = int(signal_max/signal_interval) bid_max = 50 budget = 20 possible = [i for i in range(0, bid_max+signal_interval)] possible.append(999) group_name = itertools.cycle([i for i in range(1, 999)]) class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: for player in self.get_players(): player.participant.vars['game_payment'] = 0 player.participant.vars['correct_num'] = 0 player.participant.vars['correct_payment'] = 0 player.participant.vars['instruction_round'] = [i for i in range(1, Constants.num_rounds+1) if i%(Constants.round_per_game+2) == 1] player.participant.vars['trial_round'] = [i+1 for i in player.participant.vars['instruction_round']] player.participant.vars['payround'] = random.choice([i for i in range(1, Constants.num_rounds+1) if i not in player.participant.vars['instruction_round'] and i not in player.participant.vars['trial_round']]) player.pay_round = player.participant.vars['payround'] player.participant.vars['payin20'] = random.choice([i for i in range(1, 21)]) player.payin20 = player.participant.vars['payin20'] player.participant.vars['start_time'] = 0 player.participant.vars['skip'] = False for player in self.get_players(): player.signal = c(Constants.signal_interval * random.randint(0, Constants.signal_num)) player.set_current_play() def group_by_arrival_time_method(self, waiting_players): if len(waiting_players) >= Constants.players_per_group: return waiting_players[:Constants.players_per_group] for p in waiting_players: if p.waiting_too_long(): p.participant.vars['skip'] = True return [p] class Group(BaseGroup): aa_stop = models.IntegerField(initial=0) no_winner = models.IntegerField() bid1 = models.CurrencyField() bid2 = models.CurrencyField() bid3 = models.CurrencyField() start = models.IntegerField(initial=0) current_play = models.StringField() start_time = models.FloatField(initial=0) def set_payoffs(self): players = self.get_players() group_name = next(Constants.group_name) for p in players: if p.bid not in Constants.possible and (p.current_play == "fp" or p.current_play == "sp"): p.bid = None p.group_name = group_name bids = [p.bid for p in players if p.bid != None] bids.sort(reverse=True) try: self.bid1 = bids[0] except IndexError: self.bid1 = 0 try: self.bid2 = bids[1] except IndexError: self.bid2 = 0 try: self.bid3 = bids[2] except IndexError: self.bid3 = 0 if self.bid1 == self.bid2 and self.current_play != 'aa': self.no_winner = 1 for player in players: player.round_payoff = c(0) player.winner = 0 else: for player in players: if player.current_play != 'aa': if player.bid == self.bid1: player.winner = 1 if player.current_play == 'fp' or player.current_play == 'da': player.round_payoff = player.signal - player.bid else: if self.bid2 == None: player.round_payoff = player.signal else: player.round_payoff = player.signal - self.bid2 elif player.current_play != 'da' and player.bid == None: player.winner = 0 player.round_payoff = c(-1 * self.session.config['baseline_bonus']) else: player.winner = 0 player.round_payoff = c(0) else: if player.bid == None: player.winner = 1 player.round_payoff = player.signal - self.bid1 else: player.winner = 0 player.round_payoff = c(0) for player in players: if player.participant.vars['payin20'] == 1: if self.round_number == player.participant.vars['payround']: player.game_payment = player.round_payoff + self.session.config['baseline_bonus'] if player.game_payment < 0: player.game_payment = c(0) player.participant.vars['game_payment'] = c(player.game_payment) player.total_payment = player.game_payment + self.session.config['participation_fee'] player.participant.vars['total_payment'] = c(player.total_payment) class Player(BasePlayer): bid = models.CurrencyField(label=False, blank=True) signal = models.CurrencyField() current_play = models.StringField() current_game = models.IntegerField() current_round = models.IntegerField() round_payoff = models.CurrencyField() winner = models.IntegerField() total_payment = models.CurrencyField() game_payment = models.CurrencyField() group_size = models.IntegerField(initial=Constants.players_per_group) group_name = models.IntegerField() pay_round = models.IntegerField() payin20 = models.IntegerField() stop_help = models.IntegerField(blank=True) skip = models.BooleanField(initial=False) wrong_bid = models.IntegerField(initial=0) def set_current_play(self): if self.round_number <= Constants.num_rounds / Constants.game_num: self.current_play = 'fp' self.current_game = 1 if self.round_number > Constants.num_rounds / Constants.game_num and self.round_number <= 2 * Constants.num_rounds / Constants.game_num: self.current_play = 'sp' self.current_game = 2 if self.round_number > 2 * Constants.num_rounds / Constants.game_num and self.round_number <= 3 * Constants.num_rounds / Constants.game_num: self.current_play = 'aa' self.current_game = 3 if self.round_number > 3 * Constants.num_rounds / Constants.game_num: self.current_play = 'da' self.current_game = 4 self.current_round = (self.round_number - 1) % (Constants.round_per_game + 2) - 1 def live_aa(self, bid): t = bid['type'] if t == "time": self.group.start += 1 if self.group.start == Constants.players_per_group: self.group.start_time = bid['value'] - 1608955588328 if self.group.start >= Constants.players_per_group: response = dict(start=1, start_time=self.group.start_time, stop=0) else: response = dict(start=0, start_time=0, stop=0) return {0: response} if t == "stop": self.group.aa_stop += 1 if self.current_play == 'aa': if self.group.aa_stop >= Constants.players_per_group - 1: response = dict(start=0, start_time=0, stop=1) return {0: response} if self.current_play == 'da': if self.group.aa_stop >= 1: response = dict(start=0, start_time=0, stop=1) return {0: response} def waiting_too_long(self): return time.time() - self.participant.vars['wait_page_arrival'] > 5*60