import time from otree.api import Currency as c, currency_range from otree.api import * import random # from ._builtin import Page, WaitPage from .models import Constants from .models import Bot # from mcts_.mcts_main import mcts_live_simu # import time # import gc import pandas as pd # import threading from background.tasks import start_mcts, start_numeric_mcts, start_highest_mcts class Introduction(Page): template_name = 'text_exp_bot_bg/Introduction.html' form_model = 'player' form_fields = ['intro_test'] # def get_timeout_seconds(self): # return Constants.intro_timeout_minutes*60 def is_displayed(self): return self.round_number == 1 # show this page only in round 1: in the beginning of the game def before_next_page(self): if self.timeout_happened: # if the participant didn't read the instructions after 10 minutes self.participant.vars['instruction_timeout'] = True self.player.instruction_timeout = True for group_round in self.player.in_rounds(1, Constants.num_rounds): group_round.instruction_timeout = True else: # no timeout if str.lower(self.player.intro_test) != 'sdkot': # print('participant did not answer correctly on the intro test') self.participant.vars['failed_intro_test'] = True self.player.failed_intro_test = True for group_round in self.player.in_rounds(1, Constants.num_rounds): group_round.failed_intro_test = True else: self.participant.vars['failed_intro_test'] = False def vars_for_template(self): # if self.player.id_in_group == 1: # run this once self.subsession.creating_session() other_role = 'Expert' num_condition =\ True if self.session.config['cond'] == 'num' or self.session.config['cond'] == 'only_num' else False only_num_condition = True if self.session.config['cond'] == 'only_num' else False only_text_condition = True if self.session.config['cond'] == 'only_text' else False both_condition = True if self.session.config['cond'] == 'both' else False return { 'participation_fee': Constants.real_participation_fee, 'other_role': other_role, 'initial_points_dc': self.session.vars['initial_points_receiver'], 'num_condition': num_condition, 'both_condition': both_condition, 'only_num_condition': only_num_condition, 'only_text_condition': only_text_condition, } class AfterIntroTest(WaitPage): def is_displayed(self): # show this page only in round 1: in the beginning of the game return self.round_number == 1 and not self.player.failed_intro_test class IntroTimeout(Page): template_name = 'text_exp_bot_bg/IntroTimeout.html' def get_timeout_seconds(self): return 30 def before_next_page(self): self.player.participant.vars['already_saw_IntroTimeout_page'] = True self.player.participant.vars['automate_timeout'] = True def is_displayed(self): # show this page only in round 1 and only if one or both of the players had timeout in the instructions if not self.player.participant.vars.get('go_to_the_end', False): # players who didn't get a partner return self.round_number == 1 and self.player.instruction_timeout and not\ self.player.participant.vars.get('already_saw_IntroTimeout_page', False) else: return False def vars_for_template(self): # tell the participant that had timeout that and the participant that passed but the partner had timeout # that his partner failed and we will pay him for waiting receiver = self.player # self.player.get_player_by_role('Decision Maker') receiver_timeout = receiver.participant.vars.get('instruction_timeout') # decision maker if receiver_timeout: # the participant filed the test participant_timeout = True receiver.participant.payoff = c(0) else: participant_timeout = False receiver.participant.payoff = c(0) if self.player.pass_intro_test: page_name = 'insert your personal information' else: page_name = 'read the instructions' return { 'participant_timeout': participant_timeout, 'page_name': page_name, } class IntroTestFeedback(Page): template_name = 'text_exp_bot_bg/IntroTestFeedback.html' def get_timeout_seconds(self): return 30 def is_displayed(self): # show this page only in round 1: in the beginning of the game and only if one or both of the players failed if self.player.failed_intro_test: return True else: return False def before_next_page(self): self.player.participant.vars['already_saw_IntroTestFeedback_page'] = True self.player.participant.vars['automate_timeout'] = True def vars_for_template(self): # tell the participant that failed that he failed and the participant that passed but the partner failed # that his partner failed and we will pay him for waiting receiver = self.player receiver_failed = receiver.participant.vars.get('failed_intro_test') # if self.player.id_in_group == 1: #if sender_failed: # the participant filed the test participant_filed = receiver_failed receiver.participant.payoff = c(0) # else: # participant_filed = False # sender.participant.payoff = c(0 + sender.participant.vars['payment_for_wait']) # if receiver_failed: # the participant didn't filed but his partner failed # else: # decision maker # if receiver_failed: # the participant filed the test # participant_filed = True receiver.participant.payoff = c(0) # else: # participant_filed = False # receiver.participant.payoff = c(0 + receiver.participant.vars['payment_for_wait']) # if sender_failed: # the participant didn't filed but his partner failed # partner_filed = True # else: # partner_filed = False return { 'participant_filed': participant_filed, } class PersonalInformation(Page): template_name = 'text_exp_bot_bg/PersonalInformation.html' form_model = 'player' form_fields = ['name', 'age', 'gender', 'is_student', 'occupation', 'residence'] def get_timeout_seconds(self): return 240 def is_displayed(self): # show this page only in round 1: in the beginning of the game if not self.player.participant.vars.get('go_to_the_end', False): # players who didn't get a partner return self.round_number == 1 and not self.player.instruction_timeout and not self.player.failed_intro_test else: return False def before_next_page(self): self.player.pass_intro_test = True # if we are here --> they pass the intro test if self.timeout_happened: # if the participant didn't read the instructions after 10 minutes self.participant.vars['instruction_timeout'] = True self.player.instruction_timeout = True for group_round in self.player.in_rounds(1, Constants.num_rounds): group_round.instruction_timeout = True else: self.participant.vars['name'] = self.player.name self.participant.vars['age'] = self.player.age self.participant.vars['gender'] = self.player.gender self.participant.vars['occupation'] = self.player.occupation self.participant.vars['is_student'] = self.player.is_student self.participant.vars['residence'] = self.player.residence self.participant.vars['num_timeout'] = 0 class AfterInstructions(WaitPage): def is_displayed(self): # show this page only in round 1: in the beginning of the game return self.round_number == 1 and not self.player.instruction_timeout and not self.player.failed_intro_test class ReceiverWaitPage(Page): template_name = 'text_exp_bot_bg/ReceiverWaitPage.html' live_method = 'live_resultcheck' def is_displayed(self): if not self.player.failed_intro_test: return True def vars_for_template(self): if not self.player.action_id: time.sleep(1) self.player.set_round_parameters() bot = Bot(self.round_number) print('get action from bot', bot.name) print( [self.player.score_0, self.player.score_1, self.player.score_2, self.player.score_3, self.player.score_4, self.player.score_5, self.player.score_6], self.player.get_payoff_against_bot() ) action = Bot(self.player.round_number).act( [self.player.score_0, self.player.score_1, self.player.score_2, self.player.score_3, self.player.score_4, self.player.score_5, self.player.score_6], self.player.get_payoff_against_bot()) + 1 print(f"{action=}") # if self.session.config['bot_cond'] == 'verbal': # print('start start_mcts') # action = start_mcts(self.player.participant.vars['round_parameters'], self.player.round_number) # elif self.session.config['bot_cond'] == 'numeric': # print('start start_numeric_mcts') # action = start_numeric_mcts(self.player.participant.vars['round_parameters'], self.player.round_number) # else: # print('start start_highest_mcts') # action = start_highest_mcts() self.player.action_id = action#.id class HelloBotPage(Page): template_name = 'text_exp_bot_bg/HelloBotPage.html' live_method = 'live_resultcheck' def is_displayed(self): if not self.player.failed_intro_test: return (self.round_number-1) % Constants.rounds_per_bot == 0 def vars_for_template(self): return { 'expert_id': self.player.bot_order } class ReceiverPage(Page): template_name = 'text_exp_bot_bg/ReceiverPage.html' form_model = 'player' form_fields = ['receiver_choice'] timeout_submission = {'receiver_choice': bool(random.getrandbits(1))} # if the receiver didn't choose his choice after seconds_wait, an option will be chosen randomly def is_displayed(self): if self.player.failed_intro_test != True: return True def get_timeout_seconds(self): # print('ReceiverPage get_timeout_seconds') if self.round_number in Constants.first_rounds: return Constants.seconds_wait_first_rounds_dm else: return Constants.seconds_wait_dm def before_next_page(self): # print('ReceiverPage before_next_page') if self.timeout_happened: # if the receiver didn't provide a probability after seconds_wait # self.participant.vars['num_timeout'] += 1 self.player.receiver_timeout = True # print('receiver timeout:', self.player.receiver_timeout) self.player.set_payoffs() def vars_for_template(self): # print('ReceiverPage vars_for_template') if self.session.config['cond'] == 'verbal' or self.session.config['cond'] == 'only_text': score_all_review = self.player.sender_answer_reviews expert_selected = 'review' only_score = self.player.sender_answer_scores elif self.session.config['cond'] == 'both': score_all_review = self.player.sender_answer_reviews only_score = self.player.sender_answer_scores expert_selected = 'review and score' else: # num + only_num score_all_review = self.player.sender_answer_scores expert_selected = 'score' only_score = self.player.sender_answer_scores # print('prob:', score_review) return { 'score_all_review': score_all_review, 'only_score': only_score, 'round_number': self.round_number, 'expert_selected': expert_selected, 'sender_timeout': self.player.receiver_timeout, 'expert_id': self.player.bot_order } class Results(Page): """This page displays the result of the round - what the receiver choose and what was the result of the lottery""" template_name = 'text_exp_bot_bg/Results.html' def is_displayed(self): if self.player.failed_intro_test != True: return True def get_timeout_seconds(self): if self.round_number in Constants.first_rounds or self.round_number == Constants.num_rounds: return 30 else: return 10 def before_next_page(self): # receiver_finish_round[self.player.round_number - 1] = True self.player.receiver_finish_round = True def vars_for_template(self): self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'subsession_round_number'] =\ self.player.round_number self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_receiver_payoff'] =\ self.player.receiver_payoff self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_sender_payoff'] =\ (1 if self.player.receiver_payoff != 0 else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'chose_lose'] =\ (1 if self.player.receiver_payoff < 0 else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'chose_earn'] =\ (1 if self.player.receiver_payoff > 0 else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'not_chose_lose'] =\ (1 if self.player.receiver_payoff == 0 and None else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'not_chose_earn'] =\ (1 if self.player.receiver_payoff == 0 and None else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_sender_answer_scores'] =\ self.player.sender_answer_scores self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_sender_answer_index'] =\ self.player.sender_answer_index self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_average_score'] =\ round(self.player.average_score,2) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_sender_answer_reviews'] =\ self.player.sender_answer_reviews self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'group_lottery_result'] =\ self.player.lottery_result self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'lottery_result_low'] =\ (1 if self.player.lottery_result<3 else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'lottery_result_med1'] = \ (1 if (self.player.lottery_result >= 3 and self.player.lottery_result <= 5) else 0) self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'lottery_result_high'] =\ (1 if self.player.lottery_result>=8 else 0) # reviews_features = pd.read_csv('mcts_/hotels_index_test_data.csv') # if self.player.participant.vars['round_parameters'].at[self.player.round_number-1, # 'group_sender_answer_reviews'][0] == 'P': # self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'review_id'] = \ # reviews_features[(reviews_features.hotel == self.player.participant.vars['round_parameters'].at[ # self.player.round_number-1, 'group_average_score']) & # (reviews_features.rev_index == self.player.participant.vars['round_parameters'].at[ # self.player.round_number-1,'group_sender_answer_index']) & ( # reviews_features.posorneg == 'Positive')]['review_id'].values[0] # # else: # self.player.participant.vars['round_parameters'].at[self.player.round_number-1, 'review_id'] =\ # reviews_features[(reviews_features.hotel == self.player.participant.vars['round_parameters'].at[ # self.player.round_number-1, 'group_average_score']) & # (reviews_features.rev_index == self.player.participant.vars['round_parameters'].at[ # self.player.round_number-1,'group_sender_answer_index']) & ( # reviews_features.posorneg == 'Negative')]['review_id'].values[0] # print(self.player.participant.vars['df'].at[self.player.round_number-1,'review_id'],'maya_test') if self.player.receiver_choice: # if the receiver chose Status quo receiver_choice = 'Stay at home' other_choice = 'Hotel' # print('self.player.lottery_result: ', self.player.lottery_result) other_gain_receiver = self.player.lottery_result - Constants.cost receiver_payoff = 0 if other_gain_receiver < 0: negative_other_gain_receiver = True else: negative_other_gain_receiver = False other_gain_sender = 1 else: receiver_choice = 'Hotel' other_choice = 'Stay at home' other_gain_receiver = 0 receiver_payoff = self.player.receiver_payoff negative_other_gain_receiver = False other_gain_sender = 0 # print('lottery_result:', self.player.lottery_result) # print('receiver_payoff:', receiver_payoff) sender_timeout = self.player.sender_timeout return { 'round': self.round_number, 'receiver_choice': receiver_choice, 'other_choice': other_choice, 'lottery_result': self.player.lottery_result, 'other_gain_receiver': round(abs(other_gain_receiver), 2), 'other_gain_sender': other_gain_sender, 'receiver_payoff': round(receiver_payoff, 2), 'sender_payoff': self.player.sender_payoff, 'receiver_negative_result': abs(round(self.player.receiver_payoff, 2)), 'sender_timeout': sender_timeout, 'negative_other_gain_receiver': round(negative_other_gain_receiver, 2), 'receiver_timeout': self.player.receiver_timeout } class Test(Page): """ This page will be displayed only to the DM in the verbal condition, in order to test them if they read the texts. """ template_name = 'text_exp_bot_bg/Test.html' form_model = 'player' form_fields = ['dm_test_chosen_review_1', 'dm_test_chosen_review_2', 'dm_test_not_chosen_review_1', 'dm_test_not_chosen_review_2'] def is_displayed(self): if not self.player.participant.vars.get('go_to_the_end', False): # players who didn't get a partner # show this page only after the last round and only to DM in the verbal condition return self.round_number % Constants.rounds_per_bot == 0 and\ not self.player.instruction_timeout and \ not self.player.failed_intro_test and\ not self.player.failed_test # and self.session.config['cond'] == 'verbal' else: return False def before_next_page(self): receiver = self.player # self.player.get_player_by_role('Decision Maker') # the DM need to answered correctly to all texts chosen_reviews_sum = int(receiver.dm_test_chosen_review_1) + int(receiver.dm_test_chosen_review_2) not_chosen_reviews_sum = int(receiver.dm_test_not_chosen_review_1) + int(receiver.dm_test_not_chosen_review_2) if chosen_reviews_sum == 2 and not_chosen_reviews_sum == 0: # 4 correct answers receiver.participant.vars['pay'] = 1 # print("receiver passed the test") for group_round in self.player.in_all_rounds(): group_round.receiver_passed_test = 1 self.player.receiver_passed_test = 1 elif (chosen_reviews_sum == 2 and not_chosen_reviews_sum == 1) or\ (chosen_reviews_sum == 1 and not_chosen_reviews_sum == 0): # 3 correct answers receiver.participant.vars['pay'] = 0.5 for group_round in self.player.in_all_rounds(): group_round.receiver_passed_test = 0.5 self.player.receiver_passed_test = 0.5 else: receiver.participant.vars['pay'] = 0 for group_round in self.player.in_all_rounds(): group_round.receiver_passed_test = 0 self.player.receiver_passed_test = 0 receiver.participant.payoff = c(0) # print('receiver failed the test') self.player.participant.vars['failed_dm_test'] = True self.player.participant.vars['automate_timeout'] = True def vars_for_template(self): # get previous rounds chosen reviews and sample from not seen reviews self.player.participant.payoff = c(0) chosen_reviews = list() if self.session.config['cond'] in ['verbal', 'only_text', 'both']: not_chosen_reviews =\ Constants.reviews_not_seen.sample(n=len(Constants.rounds_for_reviews_in_test)).not_seen_reviews.tolist() else: # numeric condition not_chosen_reviews = [2.4, 9.35] for round_number in Constants.rounds_for_reviews_in_test: p = self.player.in_round(round_number) if self.session.config['cond'] in ['verbal', 'only_text', 'both']: chosen_reviews.append(p.sender_answer_reviews) else: chosen_reviews.append(p.sender_answer_scores) return { 'chosen_reviews': chosen_reviews, 'not_chosen_reviews': not_chosen_reviews, 'text_number': 'texts' if self.session.config['cond'] == 'verbal' else 'numbers', } class FeedbackTest(Page): """ This page will be displayed only to the DM in the verbal condition, this will be the feedback for the DM test """ template_name = 'text_exp_bot_bg/FeedbackTest.html' def is_displayed(self): if not self.player.participant.vars.get('go_to_the_end', False): # players who didn't get a partner # show this page only after the last round and only to DM in the verbal condition return self.round_number == Constants.num_rounds and\ not self.player.instruction_timeout and not self.player.failed_intro_test # and self.session.config['cond'] == 'verbal' else: return False def vars_for_template(self): # get previous rounds chosen and not chosen reviews chosen_reviews = list() for round_number in Constants.rounds_for_reviews_in_test: p = self.player.in_round(round_number) chosen_reviews.append(p.sender_answer_reviews) receiver = self.player return { 'chosen_reviews': chosen_reviews, 'receiver_not_paid': receiver.participant.vars['pay'], 'is_verbal': self.session.config['cond'] == 'verbal', } class GameOver(Page): """ This page will be displayed after the last round is over - the experiment is finish. It will display the results: the payoff of each player """ template_name = 'text_exp_bot_bg/GameOver.html' def is_displayed(self): # show this page only after the last round if not self.player.participant.vars.get('go_to_the_end', False): # players who didn't get a partner return not self.player.instruction_timeout and not self.player.failed_intro_test and \ self.round_number == Constants.num_rounds and self.player.receiver_passed_test != 0 else: return False def vars_for_template(self): # get the number of points of each player and convert to real money # receiver total points receiver_total_points = sum([p.payoff for p in self.player.in_all_rounds()]) + \ self.session.vars['initial_points_receiver'] receiver_p_to_bonus = float(receiver_total_points / self.player.participant.vars['max_points']) receiver_bonus = Constants.bonus if random.random() <= receiver_p_to_bonus else 0 receiver_total_payoff = receiver_bonus + Constants.real_participation_fee receiver_total_payoff = c(receiver_total_payoff) self.player.participant.payoff = c(receiver_total_payoff) return {'player_total_payoff': receiver_total_payoff, 'player_bonus': receiver_bonus, 'participation_fee': Constants.real_participation_fee, 'not_failed': not self.player.participant.vars.get('failed_dm_test', False) } class AfterAutoSubmit(Page): """ This page will be shown to players that their HIT was automatically submitted """ template_name = 'text_exp_bot_bg/afterAutoSubmit.html' def is_displayed(self): return (self.round_number == 1 and self.player.participant.vars.get('automate_timeout', False)) or\ (self.round_number == Constants.num_rounds and self.player.participant.vars.get('automate_timeout', False) and self.player.receiver_passed_test == 0) def vars_for_template(self): if self.player.participant.vars.get('failed_intro_test') and self.player.failed_intro_test: reason = 'you failed the instruction test' reject = True elif self.player.participant.vars.get('instruction_timeout') and self.player.instruction_timeout: reason = 'you have not responded on time' reject = True elif self.player.participant.vars['failed_dm_test']: reason = 'you have failed the test' reject = True else: reason = '' reject = True # self.player.participant.vars['df'].to_csv('oTree_mturk/mcts_/test_df.csv') return { 'reason': reason, 'reject': reject, 'payment': 0 } page_sequence = [ Introduction, IntroTestFeedback, IntroTimeout, PersonalInformation, ReceiverWaitPage, HelloBotPage, ReceiverPage, Results, Test, FeedbackTest, GameOver, AfterAutoSubmit ]