from otree.api import * doc = """ This is a one-shot "Prisoner's Dilemma". Two players are asked separately whether they want to cooperate or defect. Their choices directly determine the payoffs. """ class C(BaseConstants): NAME_IN_URL = 'prisoner' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 15 PAYOFF_A = cu(18) PAYOFF_B = cu(12) PAYOFF_C = cu(6) PAYOFF_D = cu(0) RESPONSE_SCALE_1= [ (1, 'Überhaupt nicht'), (2, 'Ein bisschen'), (3, 'Weder ein bisschen noch viel'), (4, 'Viel'), (5, 'Völlig'), ] RESPONSE_SCALE_2 = [ (1, 'Stimme überhaupt nicht zu'), (2, 'Stimme nicht zu'), (3, 'Stimme eher nicht zu'), (4, 'Neutral'), (5, 'Stimme eher zu'), (6, 'Stimme völlig zu'), (7, 'Stimme zu'), ] POSITION_CHOICES = [ ("Professur W3, C4, o.ä.", "Professur W3, C4, o.ä."), ("Professur W2, C3, o.ä.", "Professur W2, C3, o.ä."), ("Professur C2, o.ä.", "Professur C2, o.ä."), ("Juniorprofessur", "Juniorprofessur"), ("Andere Hochschullehrposition", "Andere Hochschullehrposition"), ("Andere Wissenschaftlerposition EG14 TVL/TVöD und höher", "Andere Wissenschaftlerposition EG14 TVL/TVöD und höher"), ("Andere Wissenschaftlerposition EG13 TVL/TVöD und darunter", "Andere Wissenschaftlerposition EG13 TVL/TVöD und darunter"), ] DISCIPLINE_CHOICES = [ ("Pädagogik, Lehramt und Erziehungswissenschaften", "Pädagogik, Lehramt und Erziehungswissenschaften"), ("Geisteswissenschaften und Künste", "Geisteswissenschaften und Künste"), ("Sozialwissenschaften und Psychologie", "Sozialwissenschaften und Psychologie"), ("Wirtschaftswissenschaften", "Wirtschaftswissenschaften"), ("Rechtswissenschaften", "Rechtswissenschaften"), ("Lebenswissenschaften", "Lebenswissenschaften"), ("Physik und Mathematik", "Physik und Mathematik"), ("Chemie", "Chemie"), ("Informatik", "Informatik"), ("Ingenieurwesen", "Ingenieurwesen"), ("Agrarwissenschaft und Forstwissenschaft", "Agrarwissenschaft und Forstwissenschaft"), ("Medizin, Pharmazie und Gesundheitswesen", "Medizin, Pharmazie und Gesundheitswesen"), ("Soziale Arbeit und Sozialwesen", "Soziale Arbeit und Sozialwesen"), ("Andere (bitte angeben)", "Andere (bitte angeben)"), ] EMPLOYMENT_CHOICES = [ ("Vollzeit", "Vollzeit"), ("Teilzeit", "Teilzeit"), ] EMPLOYMENT_DURATION_CHOICES = [ ("Unbefristet beamtet", "Unbefristet beamtet"), ("Unbefristet angestellt", "Unbefristet angestellt"), ("Befristet mit Aussicht auf unbefristeten Vertrag", "Befristet mit Aussicht auf unbefristeten Vertrag"), ("Befristet ohne Aussicht auf unbefristeten Vertrag", "Befristet ohne Aussicht auf unbefristeten Vertrag"), ("Bezahlung nach Stunden, Werkvertrag, o.ä.", "Bezahlung nach Stunden, Werkvertrag, o.ä."), ("Andere (bitte angeben)", "Andere (bitte angeben)"), ] #randomizes particpants in the first round and #keeps the matching constant over all following rounds: class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: self.group_randomly() elif self.round_number <= 10: self.group_like_round(1) else: # After round 10, split groups into treatment and control randomly treatment_groups = self.get_groups() control_groups = self.get_groups() # Shuffle the order of groups to ensure random assignment self.session.shuffle(treatment_groups) self.session.shuffle(control_groups) # Assign half of the groups to treatment and half to control num_groups = len(treatment_groups) for i in range(num_groups): if i < num_groups / 2: treatment_groups[i].treatment = True control_groups[i].treatment = False else: treatment_groups[i].treatment = False control_groups[i].treatment = True class Group(BaseGroup): treatment = models.BooleanField() class Player(BasePlayer): gender_b = models.StringField(label="Bitte wählen Sie Ihr Geschlecht aus:", choices=["Männlich", "Weiblich", "Divers"]) birthd_b = models.IntegerField(label="Bitte tragen Sie Ihr Geburtsdatum ein*:") email_b = models.StringField(label="Bitte tragen Sie Ihre E-Mail Adresse ein*:") state_b = models.StringField(label="In welchem Bundesland leben Sie?") traum_role = models.StringField(label="Bitte geben Sie an, welche Rolle/Position Sie im T!Raum-Projekt innehaben") from otree.api import ( models, widgets ) hprofed_b = models.StringField( label="Welchen höchsten beruflichen Ausbildungs- oder (Fach-)Hochschulabschluss haben Sie?", choices=[ 'Noch in beruflicher Ausbildung (Berufsvorbereitungsjahr, Auszubildende/-r, Praktikant/-in, Student/-in)', 'Schüler/-in und besuche eine berufsorientierte Aufbau-, Fachschule o. ä.', 'Keinen beruflichen Abschluss und bin nicht in beruflicher Ausbildung', 'Beruflich-betriebliche Berufsausbildung (Lehre) abgeschlossen', 'Beruflich-schulische Ausbildung (Berufsfachschule, Handelsschule, Vorbereitungsdienst für den mittleren Dienst in der öffentlichen Verwaltung) abgeschlossen', 'Ausbildung an einer Fachschule der DDR abgeschlossen Ausbildung an einer Fach-, Meister-, Technikerschule, Berufs- oder Fachakademie abgeschlossen', 'Bachelor an (Fach-)Hochschule abgeschlossen', 'Fachhochschulabschluss (z. B. Diplom, Master)', 'Universitätsabschluss (z. B. Diplom, Magister, Staatsexamen, Master)', 'Promotion' ], widget=widgets.RadioSelect ) other_hprofed_b = models.StringField( label="Ein anderer beruflicher Abschluss, und zwar", blank=True ) salc_b = models.StringField( label="Was ist Ihre heutige Position bzw. Gehaltskategorie?", choices=C.POSITION_CHOICES, widget=widgets.RadioSelect, ) salc_b_other_position = models.StringField( label="Andere (bitte angeben):", blank=True ) arear_b = models.StringField( label="Bitte nennen Sie Ihre Disziplin bzw. Fachrichtungsgruppe, der Sie Ihre wissenschaftliche Tätigkeit zurechnen. (Bitte nur eine Angabe)", choices=C.DISCIPLINE_CHOICES, widget=widgets.RadioSelect, ) other_arear_b = models.StringField( label="", blank=True ) scopee_b = models.StringField( label="In Welchem Umfang sind Sie derzeitig in Ihrem T!Raum-Projekt beschäftigt?", choices=C.EMPLOYMENT_CHOICES, widget=widgets.RadioSelect, ) part_time_description = models.StringField( label="Bitte geben Sie Ihren genauen Teilzeitumfang an:", blank=True ) other_employment = models.StringField( label="Andere: Bitte geben Sie Ihre genaue Beschäftigung an:", blank=True ) duratione_b = models.StringField( label="Welche Beschäftigungsdauer ist bei Ihrem Beschäftigungsvertrag vorgesehen? (Bitte nur eine Angabe)", choices=C.EMPLOYMENT_DURATION_CHOICES, widget=widgets.RadioSelect, ) other_duratione_b = models.StringField( label="", blank=True ) Bigfive_b = models.LongStringField( label="Geben Sie für jede Aussage an, inwieweit Sie ihr zustimmen oder nicht. Ich bin jemand, der...", blank=True ) Arbeitet_gewissenhaft = models.IntegerField( label="gründlich arbeitet", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) Gespraechig_Extraversion = models.IntegerField( label="kommunikativ, gesprächig ist", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) Ist_anderen_gegenueber_manchmal_unhoeflich = models.IntegerField( label="manchmal etwas unhöflich zu andern ist", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) Kreativ_Ideen = models.IntegerField( label="orginell ist, neue Ideen einbringt", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) macht_sich_sorgen = models.IntegerField( label="sich oft Sorgen macht", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_nachsichtig = models.IntegerField( label="verzeihen kann", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) neigt_zu_faulheit = models.IntegerField( label="eher faul ist", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_gesellig = models.IntegerField( label="aus sich herausgehen kann, gesellig ist", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) hat_freude_an_kunst = models.IntegerField( label="künstlerische Erfahrungen schätzt", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_leicht_aengstlich = models.IntegerField( label="leicht nervös wird", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_effizient = models.IntegerField( label="Aufgaben wirksam und effizient erledigt", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_zurueckhaltend = models.IntegerField( label="zurückhalten ist", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) ist_ruecksichtsvoll = models.IntegerField( label="rücksichtsvoll und freundlich mit anderen umgeht", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) hat_grosse_vorstellungskraft = models.IntegerField( label="eine lebhafte Phatansie, Vorstellungen hat", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) bleibt_ruhig = models.IntegerField( label="entspannt ist, mit Stress gut umgehen kann", choices=C.RESPONSE_SCALE_1, widget=widgets.RadioSelect, ) collab_b = models.LongStringField( label="Geben Sie für jede Aussage an, inwieweit Sie ihr zustimmen oder nicht", blank=True ) statement_1 = models.IntegerField( label="Zusammenarbeit ist für jede Organisation, die Wachstum, Innovation und Produktivität erreichen möchte, von entscheidender Bedeutung", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_2 = models.IntegerField( label="Ich bin „gut“ darin, Konflikte oder Meinungsverschiedenheiten mit Kolleginnen und Kollegen oder Teammitgliedern zu lösen", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_3 = models.IntegerField( label="In meiner aktuellen Position muss ich oft mit anderen zusammenarbeiten", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_4 = models.IntegerField( label="Wenn andere mir sagen, dass ich etwas tun soll, bestehe ich darauf, zu wissen, warum", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_5 = models.IntegerField( label="Wenn es Begriffe gibt, die ich nicht verstehe, mache ich mir normalerweise nicht die Mühe zu fragen, was sie bedeuten", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_6 = models.IntegerField( label="Ich verhandle mit anderen, wenn ich denke, dass es nötig ist", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_7 = models.IntegerField( label="Oft erkunde ich keine alternativen Lösungen", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_8 = models.IntegerField( label="Ich übernehme die Verantwortung, wenn Entscheidungen getroffen werden müssen", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_9 = models.IntegerField( label="Es macht mir Spaß, mich an Entscheidungen zu beteiligen", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_10 = models.IntegerField( label="Oft vertrete ich meinen Standpunkt nicht, wenn es widersprüchliche Ansichten gibt", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_11 = models.IntegerField( label="Ich frage nicht nach alternativen Lösungen", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_12 = models.IntegerField( label="Ich neige dazu, Vorschläge für Optionen zu vermeiden", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_13 = models.IntegerField( label="Meistens initiiere ich Vorschläge", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_14 = models.IntegerField( label="Normalerweise spreche ich offen darüber, wie ich mich fühle", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_15 = models.IntegerField( label="Wenn ich nicht alle Optionen verstehe, schweige ich", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) statement_16 = models.IntegerField( label="Ich schaue anderen in die Augen, wenn ich anderer Meinung bin", choices=C.RESPONSE_SCALE_2, widget=widgets.RadioSelect, ) consent = models.BooleanField( label='Ich habe die Informationen nach Art. 13 DSGVO anlässlich der Datenerhebung bei der Teilnahme und Durchführung des Lab-in-the-field Experiments im Rahmen der T!Raum Begleitforschung des International Center for Higher Education Research (INCHER) der Universität Kassel gelesen und ich willige in die Teilnahme am Forschungsprojekt und die damit verbundene Datenverarbeitung ein. Sofern ich besondere Kategorien von personenbezogenen Daten angebe bzw. angegeben habe, sind diese von der Einwilligungserklärung umfasst. Mir ist bewusst, dass die Einwilligung/en freiwillig ist/sind und ohne Nachteile (auch einzeln) verweigert oder jederzeit auch ohne Angaben von Gründen widerrufen werden können. Ich weiß, dass im Falle eines Widerrufs die Rechtmäßigkeit der aufgrund der Einwilligung bis zum Widerruf erfolgten Verarbeitung nicht berührt wird. Ich habe verstanden, dass ich mich für einen Widerruf einfach an Herrn Prof. Dr. Guido Bünstorf, E-Mail: buenstorf@uni-kassel.de, Telefon +49 561 804 2961, wenden kann und dass aus der Verweigerung der Einwilligung oder ihrem Widerruf keine Nachteile entstehen', widget=widgets.CheckboxInput, ) essay = models.LongStringField( label="Das Ziel dieses Kurz-Essays besteht darin, Ihnen bei der Reflektion über unterschiedliche Strategien " "behilflich zu sein. In diesem Zusammenhang möchten wir Sie dazu einladen, innerhalb der " "nächsten 5 Minuten einen kurzen Text zu verfassen, in dem Sie Argumente sowohl für als auch gegen " "jede denkbare Verteilung von Auszahlungen erörtern.", blank=True ) quiz1 = models.IntegerField(label="Füllen Sie die Lücke aus: Wenn Sie und die andere Person beide A wählen, erhalten Sie beide", choices = [0, 12, 6, 18], ) quiz2 = models.IntegerField(label="Füllen Sie die Lücke aus: Wenn Sie B wählen und die andere Person A wählt, erhalten Sie 18 und die andere Person erhält", choices = [0,12,6,18], ) quiz3 = models.StringField( label="Ihr Gegenüber im Spiel ist über alle Runden", choices = ['identisch', 'unterschiedlich'], ) cooperate = models.BooleanField( choices=[[True, 'A'], [False, 'B']], doc="""This player's decision""", widget=widgets.RadioSelect, ) #chat_messages = models.TextField(default="") # FUNCTIONS def set_payoffs(group: Group): for p in group.get_players(): set_payoff(p) def other_player(player: Player): return player.get_others_in_group()[0] def set_payoff(player: Player): payoff_matrix = { (False, True): C.PAYOFF_A, (True, True): C.PAYOFF_B, (False, False): C.PAYOFF_C, (True, False): C.PAYOFF_D, } other = other_player(player) player.payoff = payoff_matrix[(player.cooperate, other.cooperate)] class Testfragen(Page): form_model = 'player' form_fields = ['quiz1', 'quiz2', 'quiz3'] def is_displayed(self): return self.round_number == 1 @staticmethod def error_message(player: Player, values): solutions = dict(quiz1=12, quiz2=0, quiz3='identisch') if values != solutions: return "Eine oder mehrere Antworten waren falsch, versuchen Sie es noch einmal." # PAGES class Introduction(Page): timeout_seconds = 180 def is_displayed(self): return self.round_number == 1 class Instruction(Page): timeout_seconds = 420 def is_displayed(self): return self.round_number == 1 class ResultsWaitPage1(WaitPage): after_all_players_arrive = set_payoffs def is_displayed(self): return self.round_number <= 5 class ResultsWaitPage2(WaitPage): after_all_players_arrive = set_payoffs def is_displayed(self): return self.round_number <= 10 class ResultsWaitPage3(WaitPage): after_all_players_arrive = set_payoffs def is_displayed(self): return self.round_number > 10 class Results1(Page): @staticmethod def vars_for_template(player: Player): opponent = other_player(player) return dict( opponent=opponent, same_choice=player.cooperate == opponent.cooperate, my_decision=player.field_display('cooperate'), opponent_decision=opponent.field_display('cooperate'), ) def is_displayed(self): return self.round_number <= 5 class Results2(Page): @staticmethod def vars_for_template(player: Player): opponent = other_player(player) return dict( opponent=opponent, same_choice=player.cooperate == opponent.cooperate, my_decision=player.field_display('cooperate'), opponent_decision=opponent.field_display('cooperate'), ) def is_displayed(self): return self.round_number <= 10 class Results3(Page): @staticmethod def vars_for_template(player: Player): opponent = other_player(player) return dict( opponent=opponent, same_choice=player.cooperate == opponent.cooperate, my_decision=player.field_display('cooperate'), opponent_decision=opponent.field_display('cooperate'), ) def is_displayed(self): return self.round_number > 10 class Survey1(Page): form_model = 'player' form_fields = ['gender_b', 'email_b','state_b', 'traum_role','hprofed_b','other_hprofed_b', 'salc_b', 'salc_b_other_position','arear_b','other_arear_b','scopee_b','part_time_description','other_employment', 'duratione_b','other_duratione_b'] def is_displayed(self): return self.round_number == 1 class Survey2(Page): form_model = 'player' form_fields = ['Arbeitet_gewissenhaft','Gespraechig_Extraversion','Ist_anderen_gegenueber_manchmal_unhoeflich', 'Kreativ_Ideen', 'macht_sich_sorgen', 'ist_nachsichtig','neigt_zu_faulheit','ist_gesellig', 'hat_freude_an_kunst','ist_leicht_aengstlich','ist_effizient','ist_zurueckhaltend', 'ist_ruecksichtsvoll','hat_grosse_vorstellungskraft','bleibt_ruhig'] def is_displayed(self): return self.round_number == 1 class Survey3(Page): form_model = 'player' form_fields = ['statement_1','statement_2','statement_3','statement_4','statement_5','statement_6','statement_7', 'statement_8','statement_9','statement_10','statement_11','statement_12','statement_13', 'statement_14','statement_15','statement_16'] def is_displayed(self): return self.round_number == 1 class Consent(Page): form_model = 'player' form_fields = ['consent'] def is_displayed(self): return self.round_number == 1 class Info(Page): timeout_seconds = 50 def is_displayed(self): return self.round_number == 1 #class Message(ExtraModel): #group = models.Link(Group) #sender = models.Link(Player) #text = models.StringField() class DecisionBeforeRound10(Page): form_model = 'player' form_fields = ['cooperate'] def is_displayed(self): return self.round_number <= 10 class Decision(Page): form_model = 'player' form_fields = ['cooperate'] def is_displayed(self): return self.round_number == 10 def before_next_page(self): # Check if it's round 10 or later if self.round_number == 10 and self.group.treatment: self.page_sequence.add_page(Chat2) # Access the treatment field of the current group # is_treatment = self.group.treatment elif self.round_number == 10 and not self.group.treatment: self.page_sequence.add_page(Essay) # Conditionally set the next page based on the treatment group #if is_treatment: #self.page_sequence.add_page(Chat2) # else: #self.page_sequence.add_page(Essay) # Control Page class Essay(Page): form_model = 'player' form_fields = ['essay'] timeout_seconds = 300 def is_displayed(self): return self.round_number == 10 and not self.group.treatment # def is_displayed(player: Player): #return player.round_number == 2 class Chat1(Page): timeout_seconds = 300 def is_displayed(self): return self.round_number == 2 class AnotherPage(Page): def is_displayed(self): # Display this page only for rounds after round 10 return self.round_number > 10 # Treatment page class Chat2(Page): timeout_seconds = 300 def is_displayed(self): return self.round_number == 10 and self.group.treatment #def is_displayed(player: Player): #return player.round_number == 2 #def to_dict(msg: Message): #return dict(sender=msg.sender.id_in_group, text=msg.text) #class Chaty(Page): #timeout_seconds = 300 #@staticmethod #def js_vars(player: Player): #return dict(my_id=player.id_in_group) # @staticmethod #def live_method(player: Player, data): # my_id = player.id_in_group #group = player.group #if 'text' in data: #text = data['text'] #msg = Message.create(group=group, sender=player, text=text) #print(f"Message created: {msg}") #return {0: [to_dict(msg)]} #messages = [to_dict(msg) for msg in Message.filter(group=group)] #print(f"Messages in group {group.id}: {messages}") #return {my_id: [to_dict(msg) for msg in Message.filter(group=group)]} #def write_to_csv(msg: Message): #file_path = 'chat_messages.csv' #with open(file_path, mode='a', newline='') as file: #writer = csv.writer(file) #writer.writerow([msg.sender.id_in_group, msg.text]) #def is_displayed(player: Player): # return player.round_number == 2 #class Chatx(Page): #timeout_seconds = 300 # @staticmethod #def js_vars(player: Player): # return dict(my_id=player.id_in_group) # @staticmethod # def live_method(player: Player, data): #my_id = player.id_in_group #group = player.group #if 'text' in data: # text = data['text'] # msg = Message.create(group=group, sender=player, text=text) #return {0: [to_dict(msg)]} # return {my_id: [to_dict(msg) for msg in Message.filter(group=group)]} #def is_displayed(player: Player): # return player.round_number == 10 #class ChatPage(Page): # form_model = 'player' #form_fields = ['chat_message'] # def is_displayed(self): # return self.player.id_in_group == 1 #def before_next_page(self): # # Store chat message in the player's chat_messages field #self.player.store_chat_message(self.player.chat_message) #class DisplayChatPage(Page): #def vars_for_template(self): #return {'chat_messages': self.group.get_player_by_id(1).chat_messages} #def is_displayed(self): #return self.player.id_in_group == 2 page_sequence = [Introduction, Consent, Info, Instruction, Testfragen,DecisionBeforeRound10, ResultsWaitPage1, Results1, Chat1, Decision, ResultsWaitPage2, Results2, Chat2, Essay, AnotherPage, ResultsWaitPage3, Results3] #Introduction, Consent, Survey1, Survey2, Survey3, Info, Instruction, Testfragen, # Chat1, Chat2