import random import numpy from otree.api import * doc = """ One player decides how to divide a certain amount between himself and the other player. See: Kahneman, Daniel, Jack L. Knetsch, and Richard H. Thaler. "Fairness and the assumptions of economics." Journal of business (1986): S285-S300. """ # FUNCTIONS FOR CLASSES def asignar_turnos(NUM_PARTICIPANTS, NUM_ROUNDS): turnos = numpy.random.randint(1, 3, (NUM_PARTICIPANTS, NUM_ROUNDS)) return turnos def asignar_evento1(TURNOS, Ni, Nf): evento = list([]) for p in range(len(TURNOS)): t2 = [i for i in range(Ni-1, Nf) if TURNOS[p, i] == 2] if len(t2) > 0: evento.append(random.choice(t2)+1) else: evento.append(0) return evento def asignar_evento2(TURNOS, Ni, Nf): evento = list([]) for p in range(len(TURNOS)): t2 = [i for i in range(Ni-1, Nf) if TURNOS[p, i] == 2] if len(t2) > 0: evento.append(random.choice(t2)+1) else: evento.append(0) return evento # CLASES class C(BaseConstants): NAME_IN_URL = 'agua2' PLAYERS_PER_GROUP = None NUM_ROUNDS = 18 RONDA_FIN_PRUEBA = 3 RONDA_INICIO_ESCASEZ = 9 NUM_PARTICIPANTS = 2 ENDOWMENT = 24 # Initial amount allocated to the dictator VALOR_TOKEN = 500 # Pesos chilenos TURNOS = asignar_turnos(NUM_PARTICIPANTS, NUM_ROUNDS) EVENTO1 = asignar_evento1(TURNOS, RONDA_FIN_PRUEBA+1, RONDA_INICIO_ESCASEZ-1) EVENTO2 = asignar_evento2(TURNOS, RONDA_INICIO_ESCASEZ, NUM_ROUNDS) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): demand = models.IntegerField(initial=12) kept = models.IntegerField( doc="""Amount dictator decided to keep for himself""", min=0, max=C.ENDOWMENT, label="", ) left = models.IntegerField(initial=0) turno = models.IntegerField(initial=0) deficit = models.IntegerField(initial=0) vecino = models.IntegerField(initial=0) kept_vecino = models.IntegerField(initial=0) finalpayment = models.CurrencyField() evento_externo1 = models.IntegerField(initial=0) evento_externo2 = models.IntegerField(initial=0) # FUNCTIONS FOR PAGES def update_demand(group: Group): ronda = group.round_number players = group.get_players() d_pri_min = 10 d_pri_max = 14 d_ver_min = 12 d_ver_max = 22 for p in players: if ronda <= C.RONDA_FIN_PRUEBA: p.demand = random.randint(12, 18) elif ronda <= (C.RONDA_INICIO_ESCASEZ-1): p.demand = random.randint(d_pri_min, d_pri_max) else: p.demand = random.randint(d_ver_min, d_ver_max) def set_payoffs(group: Group): players = group.get_players() ronda = group.round_number kepts = [p.kept for p in players] for p in players: id = p.id_in_group p.turno = C.TURNOS[id-1,ronda-1] # 1:J1 2:J2 p.evento_externo1 = C.EVENTO1[id - 1] p.evento_externo2 = C.EVENTO2[id - 1] if ronda == C.EVENTO1[id-1]: p.kept_vecino = 12 left_vecino = random.randint(5, 9) p.payoff = min(left_vecino, p.demand) * C.VALOR_TOKEN # pago como J2 p.deficit = int(max(0, p.demand - left_vecino)) elif ronda == C.EVENTO2[id-1]: p.kept_vecino = 12 left_vecino = random.randint(5, 11) p.payoff = min(left_vecino, p.demand) * C.VALOR_TOKEN # pago como J2 p.deficit = int(max(0, p.demand - left_vecino)) else: if p.turno == 1: p.payoff = min(p.kept, p.demand) * C.VALOR_TOKEN # pago como J1 p.deficit = int(max(0, p.demand - p.kept)) else: v = int(random.randint(0, len(players) - 1)) p.kept_vecino = kepts[v] p.vecino = v + 1 # numero del jugador asignado como vecino left_vecino = C.ENDOWMENT - p.kept_vecino p.payoff = min(left_vecino, p.demand) * C.VALOR_TOKEN # pago como J2 p.deficit = int(max(0, p.demand - left_vecino)) # PAGES class Introduction(Page): @staticmethod def is_displayed(player): return player.round_number == 1 class Demand(WaitPage): after_all_players_arrive = update_demand title_text = "Esperando al otro jugador" body_text = "" @staticmethod def is_displayed(player): return True class Offer(Page): form_model = 'player' form_fields = ['kept'] @staticmethod def vars_for_template(player: Player): demandrect = round(400 * player.demand / 24) ronda = int(player.round_number) return dict(demandrect=demandrect, ronda=ronda, rondatitle=ronda-3) class Pagos(WaitPage): title_text = "Calculando Pagos" body_text = "Esperando que los otros jugadores tomen su decisión" after_all_players_arrive = set_payoffs class Results(Page): @staticmethod def vars_for_template(player: Player): group = player.group ronda = int(group.round_number) if player.turno == 1: left = 24 - player.kept # ancho rectangulos hriegorect = round(400 * player.kept / 24) demandrect = round(400 * player.demand / 24) offshriego = 0 # no se usa en player 1 offsetrect = 0 # no se usa en player 1 # posiciones textos en eje x texthriego = round(hriegorect / 2) + 5 texthrvecino = round((400 - hriegorect) / 2) + 5 + hriegorect textdeficit = round(400 * (player.kept + round(player.deficit/2)) / 24) + 5 # linea de decision riego (fin del rectangulo hriegorect) linehriego = hriegorect + 10 else: left=C.ENDOWMENT-player.kept_vecino # ancho rectangulos hriegorect = round(400 * left / 24) offshriego = round(400 - hriegorect) + 10 demandrect = round(400 * player.demand / 24) offsetrect = round(400 - demandrect) + 10 # posiciones textos en eje x texthriego = round(400 - hriegorect / 2) + 5 texthrvecino = round(400 * player.kept_vecino / 24 / 2) + 5 textdeficit = 400 - round(400 * (left + player.deficit / 2) / 24) + 5 # linea de decision riego (fin del rectangulo hriegorect) linehriego = offshriego return dict(left=left, ronda=ronda, rondatitle=ronda - 3, demandrect=demandrect, offsetrect=offsetrect, hriegorect=hriegorect, offshriego=offshriego, textdeficit=textdeficit, texthriego=texthriego, linehriego=linehriego, texthrvecino=texthrvecino) class PagoFinal(Page): #after_all_players_arrive = update_pagos #title_text = "Esperando al otro jugador" #body_text = "" @staticmethod def vars_for_template(player: Player): Nrondapago = random.randint(4, C.NUM_ROUNDS-1) player_in_selected_round = player.in_round(Nrondapago) player.finalpayment = player_in_selected_round.payoff return dict(pagofinal=player.finalpayment, Nrondapago=Nrondapago-3) @staticmethod def is_displayed(player): return player.round_number == C.NUM_ROUNDS # SECUENCIA DE PAGES page_sequence = [Introduction, Demand, Offer, Pagos, Results, PagoFinal]