Parte 2: Juego de bienes públicos
(Un video de este tutorial está en YouTube )
Ahora crearemos un simple juego de bienes públicos. El juego de bienes públicos es un juego clásico en economía.
Este es un juego para tres jugadores donde cada jugador comienza con 100 puntos. Cada jugador decide individualmente cuántos de sus puntos quiere contribuir al grupo. Las contribuciones combinadas se multiplican por 2, y luego se dividen equitativamente en tres partes y se redistribuyen a los jugadores.
El código completo para la aplicación que escribiremos está aquí.
Crear la aplicación
Al igual que en la parte anterior del tutorial, crea otra aplicación, llamada my_public_goods.
Constantes
Ve a la clase de constantes de tu aplicación (C). (Para más información, consulta Constantes.)
Establece
PLAYERS_PER_GROUPen 3. oTree dividirá automáticamente a los jugadores en grupos de 3.La dotación para cada jugador es de 1000 puntos. Así que definamos
ENDOWMENTy establezcámoslo en un valor monetario de1000.Cada contribución se multiplica por 2. Así que define una constante entera llamada
MULTIPLIER = 2:
Ahora tenemos las siguientes constantes:
PLAYERS_PER_GROUP = 3
NUM_ROUNDS = 1
ENDOWMENT = cu(1000)
MULTIPLIER = 2
Modelos
Después de que se juegue el juego, ¿qué puntos de datos necesitaremos sobre cada jugador? Es importante registrar cuánto contribuyó cada persona. Así que, ve al modelo Player y define una columna contribution:
class Player(BasePlayer):
contribution = models.CurrencyField(
min=0,
max=C.ENDOWMENT,
label="How much will you contribute?"
)
También necesitamos registrar el pago que el usuario realiza al final del juego, pero no necesitamos definir explícitamente un campo payoff, porque en oTree, el Player ya contiene una columna payoff.
¿Qué puntos de datos nos interesa registrar sobre cada grupo? Podríamos estar interesados en conocer las contribuciones totales al grupo y la parte individual devuelta a cada jugador. Así que, definimos esos 2 campos en el Group:
class Group(BaseGroup):
total_contribution = models.CurrencyField()
individual_share = models.CurrencyField()
Páginas
Este juego tiene 3 páginas:
Página 1: los jugadores deciden cuánto contribuir
Página 2: Página de espera: los jugadores esperan a que otros en su grupo terminen
Página 3: se les informa a los jugadores los resultados
Página 1: Contribute
Primero definamos Contribute. Esta página contiene un formulario, así que necesitamos definir form_model y form_fields. Específicamente, este formulario debe permitirte establecer el campo contribution en el jugador. (Para más información, consulta Formularios.)
class Contribute(Page):
form_model = 'player'
form_fields = ['contribution']
Ahora, creamos la plantilla HTML.
Establezca el bloque title a Contribute, y el bloque content a:
<p>
This is a public goods game with
{{ C.PLAYERS_PER_GROUP }} players per group,
an endowment of {{ C.ENDOWMENT }},
and a multiplier of {{ C.MULTIPLIER }}.
</p>
{{ formfields }}
{{ next_button }}
Página 2: ResultsWaitPage
Cuando todos los jugadores hayan completado la página Contribute, se pueden calcular los pagos de los jugadores. Agregue una función de grupo llamada set_payoffs:
def set_payoffs(group):
players = group.get_players()
contributions = [p.contribution for p in players]
group.total_contribution = sum(contributions)
group.individual_share = group.total_contribution * C.MULTIPLIER / C.PLAYERS_PER_GROUP
for player in players:
player.payoff = C.ENDOWMENT - player.contribution + group.individual_share
Después de que un jugador haga una contribución, no puede ver la página de resultados de inmediato; primero necesita esperar a que los otros jugadores contribuyan. Por lo tanto, necesita agregar un WaitPage. Llamémoslo ResultsWaitPage. Cuando un jugador llega a una página de espera, debe esperar hasta que todos los demás jugadores del grupo hayan llegado. Luego, todos pueden proceder a la siguiente página. (Para más información, consulte Páginas de espera.)
Agrega after_all_players_arrive a ResultsWaitPage, y configúralo para activar set_payoffs:
after_all_players_arrive = 'set_payoffs'
Página 3: Results
Ahora creamos una página llamada Results. Establece el contenido de la plantilla en:
<p>
You started with an endowment of {{ C.ENDOWMENT }},
of which you contributed {{ player.contribution }}.
Your group contributed {{ group.total_contribution }},
resulting in an individual share of {{ group.individual_share }}.
Your profit is therefore {{ player.payoff }}.
</p>
{{ next_button }}
Secuencia de páginas
Asegúrate de que tu page_sequence sea correcto:
page_sequence = [
Contribute,
ResultsWaitPage,
Results
]
Define la configuración de la sesión
Agregamos otra configuración de sesión con my_public_goods en la secuencia de la aplicación.
Ejecuta el código
Carga el proyecto nuevamente y luego abre tu navegador en http://localhost:8000.
Soluciona problemas con print()
A menudo leo mensajes en foros de programación como: «Mi programa no funciona. No puedo encontrar el error, aunque he pasado horas mirando mi código».
La solución no es volver a leer el código hasta que encuentres un error; es probar tu programa de manera interactiva.
La forma más sencilla es usar declaraciones print(). Si no aprendes esta técnica, no podrás programar juegos de manera efectiva.
Solo necesitas insertar una línea en tu código como esta:
print('group.total_contribution is', group.total_contribution)
Coloca esta línea en la parte de tu código que no está funcionando, como la función de pagos definida arriba. Cuando juegues el juego en tu navegador y ese código se ejecute, tu declaración de print se mostrará en la ventana de tu terminal (no en tu navegador web).
Puedes añadir muchos prints en tu código.
print('in payoff function')
contributions = [p.contribution for p in players]
print('contributions:', contributions)
group.total_contribution = sum(contributions)
group.individual_share = group.total_contribution * C.MULTIPLIER / C.PLAYERS_PER_GROUP
print('individual share', group.individual_share)
if group.individual_share > 100:
print('inside if statement')
for player in players:
player.payoff = C.ENDOWMENT - p.contribution + group.individual_share
print('payoff after', p.payoff)
la declaración print no se muestra en la consola/logs
Si no ves la salida de la declaración print en tu ventana de consola, ¡eso significa que esa línea no se está ejecutando! (Por eso no está funcionando.)
Quizás sea porque tu código está en algún lugar inalcanzable, como después de una declaración return, o dentro de una declaración «if» que siempre es False. Comienza a colocar declaraciones print desde la parte superior de la función y luego observa dónde dejan de mostrarse.
O tal vez tu código está en una función que nunca se llama (ejecuta). Los métodos integrados de oTree, como creating_session y before_next_page, se ejecutan automáticamente, pero si defines una función personalizada como set_payoffs, debes recordar llamar a esa función desde una función integrada.