from otree.api import * import random doc = """ Indi Take T3 Part 1 """ class C(BaseConstants): NAME_IN_URL = 'Indi_Take_T3_P1' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 8 MULTIPLIER = 1.5 Pool = 40 Account = 0 class Subsession(BaseSubsession): pass # def creating_session(subsession: Subsession): # import itertools # treatments = itertools.cycle([True, False]) # for g in subsession.get_groups(): # g.treatment = next(treatments) class Group(BaseGroup): extraction = models.IntegerField() size_pool = models.IntegerField() payoff_per_group = models.FloatField() additional_payoff1 = models.IntegerField() additional_payoff2 = models.IntegerField() pool = models.FloatField() class Player(BasePlayer): possible_payoff = models.FloatField() extraction1 = models.IntegerField( min=0, max=20, label="So viele Taler (zwischen 0 und 20) nehme ich aus dem Gemeinschaftsprojekt:" ) extraction2 = models.IntegerField( min=0, max=20, label="So viele Taler (zwischen 0 und 20) nehme ich aus dem Gemeinschaftsprojekt:" ) Frage1 = models.StringField( label='1. Wie viele Teilnehmer verwalten ein Gemeinschaftsprojekt?', choices=['2', '3', '6'], widget=widgets.RadioSelect, ) Frage2 = models.BooleanField( label='2. Das Experiment besteht aus drei Teilen. Jeder Teilnehmer wird in Teil 2 einem anderen Teilnehmer zugeordnet als in Teil 1.', choices=[[True, 'Richtig'], [False, 'Falsch']], widget=widgets.RadioSelect, ) Frage3 = models.StringField( label='3. Die Taler, die nach den Entscheidungen im Gemeinschaftsprojekt sind,', choices=['werden auf beide Teilnehmer aufgeteilt.', 'wachsen auf das Anderthalbfache an und werden dann auf beide Teilnehmer aufgeteilt.', 'verfallen.'], widget=widgets.RadioSelect, ) Frage4 = models.StringField( label='4. Stellen Sie sich vor, dass beide Teilnehmer alles aus dem Gemeinschaftsprojekt nehmen. Wie viele Taler bekommt jeder Teilnehmer insgesamt aus dem Gemeinschaftsprojekt und dem privaten Konto ausgezahlt?', choices=['0', '10', '15', '20', '30', '40'], widget=widgets.RadioSelect, ) Frage5 = models.StringField( label='5. Stellen Sie sich vor, dass beide Teilnehmer nichts aus dem Gemeinschaftsprojekt nehmen. Wie viele Taler bekommt jeder Teilnehmer insgesamt aus dem Gemeinschaftsprojekt und dem privaten Konto ausgezahlt?', choices=['0', '10', '15', '20', '30', '40'], widget=widgets.RadioSelect, ) Frage6 = models.StringField( label='6. Wie viele Taler bekommt der erste Teilnehmer aus dem Gemeinschaftsprojekt und dem privaten Konto insgesamt ausgezahlt?', choices=['0', '10', '15', '20', '35', '40'], widget=widgets.RadioSelect, ) Frage7 = models.StringField( label='7. Wie viele Taler bekommt der zweite Teilnehmer aus dem Gemeinschaftsprojekt und dem privaten Konto insgesamt ausgezahlt?', choices=['0', '10', '15', '20', '35', '40'], widget=widgets.RadioSelect, ) Frage8 = models.StringField( label='8. Welche Aktion maximiert die Gesamtauszahlung beider Teilnehmer?', choices=['Keine Taler aus dem Gemeinschaftsprojekt nehmen.', 'Alle Taler aus dem Gemeinschaftsprojekt nehmen.'], widget=widgets.RadioSelect, ) Frage9 = models.StringField( label='9. Welche Aktion maximiert Ihre individuelle Auszahlung?', choices=['Keine Taler aus dem Gemeinschaftsprojekt nehmen.', 'Alle Taler aus dem Gemeinschaftsprojekt nehmen.'], widget=widgets.RadioSelect, ) Strategy_Q1 = models.StringField( label='Was denken Sie: Welche der folgenden Strategien beschreibt das Verhalten eines typischen Teilnehmers im nächsten Teil am besten? Das heißt, welche der folgenden Strategien ist die häufigste? ', choices=[ '(1) Immer viele/alle Taler (d.h. zwischen 14-20 Taler) nehmen.', '(2) Immer wenige/keine Taler (d.h. zwischen 0-6 Taler) nehmen.', '(3) In der ersten Runde wenige/keine Taler nehmen. In den folgenden Runden das Verhalten des anderen Teilnehmers aus der vorherigen Runde spiegeln: Hat er wenige/keine Taler genommen, nimmt man ebenfalls wenige/keine; hat er viele/alle genommen, nimmt man ebenfalls viele/alle.', '(4) In der ersten Runde wenige/keine Taler nehmen. In den folgenden Runden weiterhin wenige/keine Taler nehmen, solange der andere Teilnehmer zuvor ebenfalls wenige/keine Taler genommen hat. Nimmt der andere Teilnehmer jedoch einmal viele/alle Taler, nimmt man ab diesem Zeitpunkt dauerhaft viele/alle Taler.', '(5) Wie Strategie (3), nur in der ersten Runde viele/alle Taler nehmen.', '(6) Wie Strategie (3), nur in Runde 8 auf jeden Fall viele/alle Taler nehmen.', '(7) Wie Strategie (3), nur in Runden 7 und 8 auf jeden Fall viele/alle Taler nehmen.', 'Keine der oben genannten Strategien' ], widget=widgets.RadioSelect, ) Strategy_Q2 = models.StringField( label='Was denken Sie: Welche der folgenden Strategien beschreibt das Verhalten eines typischen Teilnehmern im gerade gespielten Teil am besten? Das heißt, welche der folgenden Strategien war die häufigste? ', choices=['(1) Immer viele/alle Taler (d.h. zwischen 14-20 Taler) nehmen.', '(2) Immer wenige/keine Taler (d.h. zwischen 0-6 Taler) nehmen.', '(3) In der ersten Runde wenige/keine Taler nehmen. In den folgenden Runden das Verhalten des anderen Teilnehmers aus der vorherigen Runde spiegeln: Hat er wenige/keine Taler genommen, nimmt man ebenfalls wenige/keine; hat er viele/alle genommen, nimmt man ebenfalls viele/alle.', '(4) In der ersten Runde wenige/keine Taler nehmen. In den folgenden Runden weiterhin wenige/keine Taler nehmen, solange der andere Teilnehmer zuvor ebenfalls wenige/keine Taler genommen hat. Nimmt der andere Teilnehmer jedoch einmal viele/alle Taler, nimmt man ab diesem Zeitpunkt dauerhaft viele/alle Taler.', '(5) Wie Strategie (3), nur in der ersten Runde viele/alle Taler nehmen.', '(6) Wie Strategie (3), nur in Runde 8 auf jeden Fall viele/alle Taler nehmen.', '(7) Wie Strategie (3), nur in Runden 7 und 8 auf jeden Fall viele/alle Taler nehmen.', 'Keine der oben genannten Strategien'], widget=widgets.RadioSelect, ) class IncorrectResponse(ExtraModel): player = models.Link(Player) field_name = models.StringField() response = models.StringField() def creating_session(subsession): if subsession.round_number == 1: subsession.group_randomly() else: subsession.group_like_round(1) def set_possible_payoffs(group: Group): p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) extraction1 = p1.extraction1 extraction2 = p2.extraction2 group.size_pool = C.Pool - extraction1 - extraction2 group.additional_payoff1 = C.Account + extraction1 group.additional_payoff2 = C.Account + extraction2 group.pool = group.size_pool * C.MULTIPLIER group.payoff_per_group = group.pool / 2 p1.possible_payoff = group.payoff_per_group + group.additional_payoff1 p2.possible_payoff = group.payoff_per_group + group.additional_payoff2 class MyWaitPage(WaitPage): wait_for_all_groups = True after_all_players_arrive = 'creating_session' class Introduction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Examples(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Instruction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Intro2(Page): timeout_seconds = 10 @staticmethod def is_displayed(player): return player.round_number >= 2 class RuleQuizPage(Page): form_model = 'player' form_fields = ['Frage1', 'Frage2', 'Frage3', 'Frage4', 'Frage5', 'Frage6', 'Frage7', 'Frage8', 'Frage9'] @staticmethod def is_displayed(player): return player.round_number == 1 @staticmethod def error_message(player: Player, values): solutions = dict(Frage1='2', Frage2=True, Frage3='wachsen auf das Anderthalbfache an und werden dann auf beide Teilnehmer aufgeteilt.', Frage4='20', Frage5='30', Frage6='15', Frage7='35', Frage8='Keine Taler aus dem Gemeinschaftsprojekt nehmen.', Frage9='Alle Taler aus dem Gemeinschaftsprojekt nehmen.') errors = {f: 'Diese Antwort war nicht richtig.' for f in solutions if values[f] != solutions[f]} if errors: for name in errors: response = values[name] IncorrectResponse.create(player=player, field_name=name, response=str(response)) return errors class RulesWaitPage(WaitPage): @staticmethod def is_displayed(player): return player.round_number == 1 class Start(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Strategy1(Page): form_model = 'player' form_fields = ['Strategy_Q1'] @staticmethod def is_displayed(player): return player.round_number == 1 class Extraction1(Page): form_model = 'player' form_fields = ['extraction1'] @staticmethod def is_displayed(player): return player.id_in_group == 1 class Extraction2(Page): form_model = 'player' form_fields = ['extraction2'] @staticmethod def is_displayed(player): return player.id_in_group == 2 class ResultsWaitPage(WaitPage): after_all_players_arrive = set_possible_payoffs class Results(Page): timeout_seconds = 30 @staticmethod def vars_for_template(player): group = player.group p1 = group.get_player_by_id(1) p2 = group.get_player_by_id(2) return dict( g=player.group.get_players(), p1=p1, p2=p2, earning=format(float(player.possible_payoff), '.2f').replace(".", ","), ) @staticmethod def before_next_page(player: Player, timeout_happened): import random participant = player.participant # if it's the last round if player.round_number == C.NUM_ROUNDS: random_round = random.randint(1, C.NUM_ROUNDS) participant.selected_round = random_round player_in_selected_round = player.in_round(random_round) player.payoff = player_in_selected_round.possible_payoff participant.vars['app1_payoff'] = player.payoff participant.vars['app1_round'] = random_round class Ende(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS class BlankWaitPage(WaitPage): wait_for_all_groups = True @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS class Blank(Page): @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS page_sequence = [MyWaitPage, Introduction, Examples, Intro2, RuleQuizPage, RulesWaitPage, Start, Strategy1, Extraction1, Extraction2, ResultsWaitPage, Results, Ende, BlankWaitPage, Blank] def custom_export(players): """For data export page""" yield ['participant_code', 'id_in_session', 'round_number', 'field_name', 'response'] responses = IncorrectResponse.filter() for resp in responses: player = resp.player participant = player.participant yield [participant.code, participant.id_in_session, player.round_number, resp.field_name, resp.response]