from otree.api import Currency as c, currency_range # To show currency from . import models # Contains my data structure and functions from ._builtin import Page, WaitPage # Necessary to build custom pages from .models import Constants, Bid # Constants is necessary. Bid is my own from datetime import datetime # To handle time properly import time # Why? import datetime # Why? import random # For 'risky' stuff #from pip._vendor.requests.sessions import session #from .utils import get_field_names_for_csv # For custom export from collections import OrderedDict from django.http import JsonResponse from django.contrib.auth.decorators import login_required class WPstart(WaitPage): def after_all_players_arrive(self): for p in self.group.get_players(): p.private_value = int( self.session.config['min_private_value']*(100/self.session.config['point_worth_ct']) + random.random() * ( (self.session.config['max_private_value'] - self.session.config['min_private_value']) *(100/self.session.config['point_worth_ct']) ) ) class WP(WaitPage): def after_all_players_arrive(self): now = time.time() self.group.auctionstartdate = now #self.group.auctionenddate = now + Constants.starting_time class ResultsWP(WaitPage): def after_all_players_arrive(self): self.group.set_payoffs() #self.group.write_results_to_file() class InbetweenWP(WaitPage): def is_displayed(self): if all(p.second_stage_bid == False for p in self.group.get_players()): return False else: return True def after_all_players_arrive(self): if not all(p.second_stage_bid == False for p in self.group.get_players()): for pl in self.group.get_players(): pl.second_stage_bid = True for pl in self.group.get_players(): pl.second_stage_bid_amount = None class InstructionsPage(Page): def is_displayed(self): return self.round_number == 1 def vars_for_template(self): return { 'probability': Constants.bid_success_probability, 'low':int(self.session.config['min_private_value']*(100/self.session.config['point_worth_ct'])), 'high':int(self.session.config['max_private_value']*(100/self.session.config['point_worth_ct'])), } class Stage1(Page): timeout_seconds = Constants.timeout_seconds live_method = 'live_auction' def is_displayed(self): if all(p.second_stage_bid == False for p in self.group.get_players()): return False else: return True def vars_for_template(self): return { 'max_bid': self.player.highest_bid().amount, 'probability': Constants.bid_success_probability, 'low':int(self.session.config['min_private_value']*(100/self.session.config['point_worth_ct'])), 'high':int(self.session.config['max_private_value']*(100/self.session.config['point_worth_ct'])), } #def before_next_page(self): # self.player.second_stage_bid_amount = self.player.highest_bid().amount class Stage2(Page): def is_displayed(self): if all(p.second_stage_bid == False for p in self.group.get_players()): return False else: return True form_model = models.Player form_fields = ['second_stage_bid', 'second_stage_bid_amount'] def second_stage_bid_amount_max(self): return Constants.endowment def second_stage_bid_amount_min(self): return max(self.player.highest_bid().amount, self.group.second_price)+1 def vars_for_template(self): return { 'first_price': self.group.first_price, 'second_price': self.group.second_price, 'winner': self.group.curwinner, 'max_bid': self.player.highest_bid().amount, 'probability': Constants.bid_success_probability, 'low':int(self.session.config['min_private_value']*(100/self.session.config['point_worth_ct'])), 'high':int(self.session.config['max_private_value']*(100/self.session.config['point_worth_ct'])), } def before_next_page(self): if self.player.second_stage_bid == True: if not self.player.second_stage_bid_amount == None: # "Illegal" bids are prevented by formfield validation if random.random() <= Constants.bid_success_probability: Bid.objects.create( player=self.player, amount = self.player.second_stage_bid_amount, at_time = time.time() - self.group.auctionstartdate, in_stage = 2, success = 1, in_round = self.subsession.round_number, p_value = self.player.private_value ) else: Bid.objects.create( player=self.player, amount = self.player.second_stage_bid_amount, at_time = time.time() - self.group.auctionstartdate, in_stage = 2, success = 0, in_round = self.subsession.round_number, p_value = self.player.private_value ) # Ugly hack (conceptually), but it works # Resets only because of rng self.player.second_stage_bid = False # Sort players by their respective maximum bid and then the time they submitted it (in case of duplicates) sorted_players = sorted( self.group.get_players(), key=lambda player: (player.highest_bid().amount,-player.highest_bid().at_time), reverse = True) # Replace the prices self.group.first_price = sorted_players[0].highest_bid().amount self.group.second_price = sorted_players[1].highest_bid().amount # Set winner self.group.curwinner = sorted_players[0].id_in_group #print('winner: ', mygroup.curwinner) else: print('Player submitted last bid empty') class Results(Page): pass class ResultsSummary(Page): def is_displayed(self): return self.round_number == Constants.num_rounds def vars_for_template(self): return { 'total_payoff': sum([p.payoff for p in self.player.in_all_rounds()]), 'paying_round': self.session.vars['paying_round'] } # @login_required # def export_view_json(request): # """ # Custom view function to export full results for this game as JSON file # """ # # def create_odict_from_object(obj, fieldnames): # """ # Small helper function to create an OrderedDict from an object using # as attributes. # """ # data = OrderedDict() # for f in fieldnames: # data[f] = getattr(obj, f) # # return data # # # get the complete result data from the database # qs_results = models.Player.objects.select_related('subsession', 'subsession__session', 'group', 'participant')\ # .prefetch_related('bid_set')\ # .all() # # session_fieldnames = [] # will be defined by get_field_names_for_csv # subsess_fieldnames = [] # will be defined by get_field_names_for_csv # group_fieldnames = [] # will be defined by get_field_names_for_csv # player_fieldnames = [] # will be defined by get_field_names_for_csv # bid_fieldnames = ['mode','amount','at_time','in_stage','success','in_round','p_value'] # # # get all sessions, order them by label # sessions = sorted(set([p.subsession.session for p in qs_results]), key=lambda x: x.label) # # # this will be a list that contains data of all sessions # output = [] # # # loop through all sessions # for sess in sessions: # session_fieldnames = session_fieldnames or get_field_names_for_csv(sess.__class__) # sess_output = create_odict_from_object(sess, session_fieldnames) # sess_output['subsessions'] = [] # # # loop through all subsessions (i.e. rounds) ordered by round number # subsessions = sorted(sess.get_subsessions(), key=lambda x: x.round_number) # for subsess in subsessions: # subsess_fieldnames = subsess_fieldnames or get_field_names_for_csv(subsess.__class__) # subsess_output = create_odict_from_object(subsess, subsess_fieldnames) # subsess_output['groups'] = [] # # # loop through all groups ordered by ID # groups = sorted(subsess.get_groups(), key=lambda x: x.id_in_subsession) # for g in groups: # group_fieldnames = group_fieldnames or get_field_names_for_csv(g.__class__) # g_output = create_odict_from_object(g, group_fieldnames) # g_output['players'] = [] # # # loop through all players ordered by ID # players = sorted(g.get_players(), key=lambda x: x.participant.id_in_session) # for p in players: # player_fieldnames = player_fieldnames or get_field_names_for_csv(p.__class__) # p_output = create_odict_from_object(p, player_fieldnames) # # # add some additional player information # p_output['participant_id_in_session'] = p.participant.id_in_session # p_output['bids'] = [] # # # loop through all decisions ordered by ID # bids = p.bid_set.order_by('id') # for bid in bids: # bid_output = create_odict_from_object(bid, bid_fieldnames) # p_output['bids'].append(bid_output) # # g_output['players'].append(p_output) # # subsess_output['groups'].append(g_output) # # sess_output['subsessions'].append(subsess_output) # # output.append(sess_output) # # return JsonResponse(output, safe=False) page_sequence = [ WPstart, InstructionsPage, WP, Stage1, Stage2, InbetweenWP, Stage1, Stage2, InbetweenWP, Stage1, Stage2, InbetweenWP, Stage1, Stage2, InbetweenWP, Stage1, Stage2, InbetweenWP, Stage1, Stage2, InbetweenWP, ResultsWP, Results, #ResultsSummary ]