#!/usr/bin/env python
# coding: utf-8
#
QRE analysis of a sender-receiver game
# Valeria Burdea, December 2016
#
# This is a 2-player sequential game the structure of which is inspired by Glazer and Rubinstein (2004, 2006). In the first stage, the sender is dealt 2 cards - one card orange, one card blue. Each card can take a value between 1 and 9; each combination of values is equally likely. A hand is good if the sum of the two cards is at least 9; a hand is bad otherwise. Upon observing the two cards, the sender chooses one to reveal to the receiver. The receiver observes the revealed card and chooses an action between 'Accept' and 'Reject'. The incentives are such that the sender would always want the receiver to accept, while the receiver would only want to accept if the hand is good and reject otherwise.
#
# This game is studied experimentally in a working paper, "Communication with partially verifiable information: An experiment" by Valeria Burdea, Maria Montero, and Martin Sefton.
# In[1]:
import gambit
# In[2]:
g=gambit.Game.new_tree()
# In[3]:
g.title="9x9"
# Adding the two players:
# In[4]:
sender=g.players.add("Sender")
receiver=g.players.add("Receiver")
# Adding the chance moves. There are 81 such moves, as there are 81 (9x9) possible combinations of card values:
# In[5]:
move=g.root.append_move(g.players.chance, 81)
# In[6]:
i=0
b=1
while i<81 and b<10:
for o in range(1, 10):
move.actions[i].label=str(b)+str(o)
i=i+1
b=b+1
# For each of the 81 states, the sender has two actions: reveal the value on the orange card (action 0) or the value on the blue card (action 1). We add these actions at different information sets as the sender has perfect information about the state of the world:
# In[7]:
for j in range(0,81):
moves=g.root.children[j].append_move(sender,2)
moves.label='s'+move.actions[j].label
moves.actions[0].label=move.actions[j].label[0]
moves.actions[1].label=move.actions[j].label[1]
# For each value revealed the receiver has two actions: 'Accept' and 'Reject'. We assume the receiver is colour blind, so she only has 9 information sets corresponding to the 9 possible values on either card. To do this iteratively, we define the move for the first time that card value is observed and then, every other time we append the same previously defined move. We repeat this process for each information set of the receiver..
# In[8]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='1':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='1':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='1':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='1'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='1':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[9]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='2':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='2':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='2':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='2'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='2':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[10]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='3':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='3':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='3':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='3'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='3':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[11]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='4':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='4':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='4':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='4'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='4':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[12]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='5':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='5':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='5':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='5'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='5':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[13]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='6':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='6':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='6':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='6'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='6':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[14]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='7':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='7':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='7':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='7'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='7':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[15]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='8':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='8':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='8':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='8'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='8':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# In[16]:
first=0
for i in range(0,81):
if first>0:
if g.root.children[i].infoset.actions[0].label=='9':
g.root.children[i].children[0].append_move(mover)
if g.root.children[i].infoset.actions[1].label=='9':
g.root.children[i].children[1].append_move(mover)
t=0
while first<1 and t<2:
if g.root.children[i].infoset.actions[t].label=='9':
mover=g.root.children[i].children[t].append_move(receiver,2)
mover.label='9'
mover.actions[0].label="Accept"
mover.actions[1].label="Reject"
if t==0 and g.root.children[i].infoset.actions[1].label=='9':
g.root.children[i].children[1].append_move(mover)
t=t+2
first=1
else:
t=t+1
# We now define the outcomes. There are 4 such possible outcomes depending on whether the receiver accepts or rejects and whether the state is good or bad.
# In[17]:
accept_good=g.outcomes.add("R accepts good hand")
accept_good[0]=1
accept_good[1]=1
# In[18]:
reject_good=g.outcomes.add("R rejects good hand")
reject_good[0]=0
reject_good[1]=0
# In[19]:
accept_bad=g.outcomes.add("R accepts bad hand")
accept_bad[0]=1
accept_bad[1]=0
# In[20]:
reject_bad=g.outcomes.add("R rejects bad hand")
reject_bad[0]=0
reject_bad[1]=1
# We proceed by appending the previously defined outcome pairs to the corresonding leafs.
# In[21]:
for i in range(0,81):
hand=int(g.root.children[i].infoset.actions[0].label)+int(g.root.children[i].infoset.actions[1].label)
if hand>8:
g.root.children[i].children[0].children[0].outcome=accept_good
g.root.children[i].children[0].children[1].outcome=reject_good
g.root.children[i].children[1].children[0].outcome=accept_good
g.root.children[i].children[1].children[1].outcome=reject_good
else:
g.root.children[i].children[0].children[0].outcome=accept_bad
g.root.children[i].children[0].children[1].outcome=reject_bad
g.root.children[i].children[1].children[0].outcome=accept_bad
g.root.children[i].children[1].children[1].outcome=reject_bad
# We write the game out to disk in order to be able to use the Gambit command-line tools to compute the principle branch of the QRE.
# In[22]:
with file("extensive9x9.efg", "w") as f:
f.write(g.write('efg'))
# Computing the principal branch of the QRE:
# In[24]:
get_ipython().system('gambit-logit extensive9x9.efg')
# In[ ]: