Game Theory and Applications
LAB RECORD
Submitted By:
Name: Mayank Choradia
Roll Number: 2023UCM2305
Course/Batch: MAC’27
Department of [Your Department]
[Your University/College Name]
April 13, 2026
Contents
1 Experiment 1 & 2: Prisoner’s Dilemma 2
1.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Python Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2 Experiment 3 & 4: Battle of the Sexes & Hunting Game 4
2.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Python Code (Battle of Sexes) . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Experiment 5: Matching Pennies 6
3.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Python Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4 Experiment 6 & 7: Routing Congestion & Senate Race 8
4.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Python Code (Senate Race Backward Induction) . . . . . . . . . . . . . . 8
4.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5 Experiment 8 & 9: Backward Induction (Stone Game) 10
5.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.2 Python Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
6 Experiment 10 & 11: Centipede Game 12
6.1 Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.2 Python Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.3 Output Screenshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1
1 Experiment 1 & 2: Prisoner’s Dilemma
1.1 Theory
The Prisoner’s Dilemma is a standard example of a game analyzed in game theory that
shows why two completely rational individuals might not cooperate, even if it appears
that it is in their best interests to do so. In this game, betraying the partner (defecting)
yields a higher individual payoff than cooperating. The unique Nash Equilibrium is for
both players to defect.
1.2 Python Code
1 import nashpy as nash
2 import numpy as np
3
4 # Payoff matrices for Player 1 and Player 2
5 # Strategies : [ Confess ( C ) , Silent ( S ) ]
6 A = np . array ([[ -2 , 0] , [ -3 , -1]]) # Player 1
7 B = np . array ([[ -2 , -3] , [0 , -1]]) # Player 2
8
9 print ( " === USING NASHPY === " )
10 game = nash . Game (A , B )
11 equilibria = game . s up p o rt _ e nu m e ra t i on ()
12 for eq in equilibria :
13 print ( f " Nash Equilibrium : Player 1: { eq [0]} , Player 2: { eq [1]} " )
14
15 print ( " \ n === WITHOUT USING NASHPY ( Pure Strategy ) === " )
16 # Find pure strategy Nash Equilibrium manually
17 p1_ best_ respon ses = np . argmax (A , axis =0)
18 p2_ best_ respon ses = np . argmax (B , axis =1)
19
20 for j , i in enumerate ( p1 _best_ respon ses ) :
21 if p2_ best_ respon ses [ i ] == j :
22 print ( f " Pure Nash Equilibrium found at index : ( P1 : { i } , P2 : { j
}) " )
1.3 Output Screenshot
2
3
2 Experiment 3 & 4: Battle of the Sexes & Hunting
Game
2.1 Theory
Battle of the Sexes: A coordination game where a couple wishes to engage in an
activity together, but have different preferences. It features multiple pure strategy Nash
equilibria.
Hunting Game (Stag Hunt): A game describing a conflict between safety and social
cooperation. It has two pure strategy equilibria: one that is risk-dominant (Hunting
Hare) and one that is payoff-dominant (Hunting Stag).
2.2 Python Code (Battle of Sexes)
1 import nashpy as nash
2 import numpy as np
3
4 # Battle of Sexes Payoffs : [ Opera , Football ]
5 A = np . array ([[3 , 0] , [0 , 2]])
6 B = np . array ([[2 , 0] , [0 , 3]])
7
8 game = nash . Game (A , B )
9 print ( " === Battle of Sexes : NASHPY === " )
10 for eq in game . s up p o rt _ e nu m e ra t i on () :
11 print ( eq )
12
13 print ( " \ n === Battle of Sexes : WITHOUT NASHPY === " )
14 for i in range ( A . shape [0]) :
15 for j in range ( A . shape [1]) :
16 if A [i , j ] == np . max ( A [: , j ]) and B [i , j ] == np . max ( B [i , :]) :
17 print ( f " Pure NE at indices ({ i } , { j }) " )
2.3 Output Screenshot
4
5
3 Experiment 5: Matching Pennies
3.1 Theory
Matching Pennies is a zero-sum game. Two players simultaneously place a penny on the
table. If the coins match, Player 1 wins Player 2’s penny. If they do not match, Player 2
wins Player 1’s penny. This game has no pure strategy Nash equilibrium, only a mixed
strategy equilibrium.
3.2 Python Code
1 import nashpy as nash
2 import numpy as np
3
4 # Matching Pennies : [ Heads , Tails ]
5 A = np . array ([[1 , -1] , [ -1 , 1]])
6 B = np . array ([[ -1 , 1] , [1 , -1]])
7
8 game = nash . Game (A , B )
9 print ( " === Matching Pennies : NASHPY === " )
10 for eq in game . s up p o rt _ e nu m e ra t i on () :
11 print ( " Mixed Strategy NE : " , eq )
12
13 print ( " \ n === WITHOUT NASHPY === " )
14 # Checking pure NE ( Will return none )
15 found_pure = False
16 for i in range ( A . shape [0]) :
17 for j in range ( A . shape [1]) :
18 if A [i , j ] == np . max ( A [: , j ]) and B [i , j ] == np . max ( B [i , :]) :
19 print ( f " Pure NE at ({ i } , { j }) " )
20 found_pure = True
21 if not found_pure :
22 print ( " No pure strategy Nash Equilibrium exists . Players must
randomize . " )
3.3 Output Screenshot
6
7
4 Experiment 6 & 7: Routing Congestion & Senate
Race
4.1 Theory
Routing Congestion: Similar to matching pennies, one player seeks differentiation
while the other seeks matching routes.
Senate Race: A sequential game where the incumbent moves first. The payoffs combine
the value of winning (10) and the value of compromising views (5). We solve this via
Backward Induction.
4.2 Python Code (Senate Race Backward Induction)
1 # Incumbent ( P1 ) chooses L or R . Challenger ( P2 ) chooses L or R .
2 # P1 moving first .
3 def senate_race () :
4 # Format : Payoffs [ P1_choice ][ P2_choice ] = ( P1_payoff , P2_payoff )
5 # Win =10 , Compromise =5
6 payoffs = {
7 ’L ’: { ’L ’: (15 , 0) , ’R ’: (5 , 15) } ,
8 ’R ’: { ’L ’: (0 , 10) , ’R ’: (10 , 5) }
9 }
10
11 # Backward Induction : P2 chooses best response for each of P1 ’s
moves
12 p2_responses = {}
13 for p1_move in payoffs :
14 best_p2_payoff = -1
15 best_p2_move = None
16 for p2_move in payoffs [ p1_move ]:
17 if payoffs [ p1_move ][ p2_move ][1] > best_p2_payoff :
18 best_p2_payoff = payoffs [ p1_move ][ p2_move ][1]
19 best_p2_move = p2_move
20 p2_responses [ p1_move ] = best_p2_move
21
22 # P1 chooses maximizing their payoff given P2 ’s predicted response
23 best_p1_payoff = -1
24 best_p1_move = None
25 for p1_move in p2_responses :
26 pre dicte d_p2_m ove = p2_responses [ p1_move ]
27 p1_payoff = payoffs [ p1_move ][ pr edicte d_p2_m ove ][0]
28 if p1_payoff > best_p1_payoff :
29 best_p1_payoff = p1_payoff
30 best_p1_move = p1_move
31
32 print ( " Senate Race SPNE ( Subgame Perfect Nash Equilibrium ) : " )
33 print ( f " Incumbent plays { best_p1_move } , Challenger plays {
p2_responses [ best_p1_move ]} " )
34 print ( f " Payoffs -> { payoffs [ best_p1_move ][ p2_responses [ best_p1_move
]]} " )
35
36 senate_race ()
8
4.3 Output Screenshot
9
5 Experiment 8 & 9: Backward Induction (Stone
Game)
5.1 Theory
Six stones lie on a board. Players alternate removing 1 or 2 stones. The player facing
an empty board loses. Using backward induction, we can map the winning/losing states
starting from 0 stones up to 6 stones to find the optimal strategy.
5.2 Python Code
1 def solve_stone_game ( n_stones ) :
2 # state represents if the person facing ’i ’ stones will Win ( True )
or Lose ( False )
3 dp = [ False ] * ( n_stones + 1)
4 dp [0] = False # Facing 0 stones means you already lost
5
6 best_moves = [0] * ( n_stones + 1)
7
8 for i in range (1 , n_stones + 1) :
9 # We can remove 1 or 2 stones .
10 # If any move leaves the opponent in a ’ False ’ ( Losing ) state ,
this state is a Win .
11 if i >= 1 and not dp [i -1]:
12 dp [ i ] = True
13 best_moves [ i ] = 1
14 elif i >= 2 and not dp [i -2]:
15 dp [ i ] = True
16 best_moves [ i ] = 2
17 else :
18 dp [ i ] = False
19 best_moves [ i ] = 1 # Doesn ’t matter , will lose against
perfect play
20
21 return dp , best_moves
22
23 dp , moves = solve_stone_game (6)
24 print ( " === Stone Game Backward Induction === " )
25 for i in range (7) :
26 status = " Win " if dp [ i ] else " Lose "
27 print ( f " Facing { i } stones : { status } ( Optimal Move : Remove { moves [ i
]}) " )
10
5.3 Output Screenshot
11
6 Experiment 10 & 11: Centipede Game
6.1 Theory
The Centipede Game is an extensive form game in which two players alternately get a
chance to take the larger share of a continually increasing pot, or pass to the other player.
Using backward induction, the unique Subgame Perfect Nash Equilibrium is for the first
player to take the pot on the very first move.
6.2 Python Code
1 def c e n t i p e d e _ g a m e _ b a c k w a r d _ i n d u c t i o n ( rounds ) :
2 # We will represent payoffs at the end of the game
3 # Let ’s say pot grows by 2 each round .
4 # If round n is reached and game ends , players share .
5
6 # Working backwards from the last round
7 print ( f " === Centipede Game ({ rounds } rounds ) === " )
8
9 # State tracking : what the payoff will be if we reach this node
10 current_payoff = [ rounds + 1 , rounds + 1] # Assuming equal split at
the end
11
12 for r in range ( rounds , 0 , -1) :
13 player = 1 if r % 2 != 0 else 2
14 opp = 2 if player == 1 else 1
15
16 # Payoff if they TAKE at this round
17 take_payoff = [0 , 0]
18 take_payoff [ player -1] = r + 2 # Gets the larger stack
19 take_payoff [ opp -1] = r - 1 # Opponent gets smaller stack
20
21 # Compare TAKE vs PASS ( which leads to current_payoff )
22 if take_payoff [ player -1] > current_payoff [ player -1]:
23 print ( f " Round { r } ( Player { player }) : Optimal to TAKE . ( Take
yields { take_payoff [ player -1]} , Pass yields { current_payoff [ player
-1]}) " )
24 current_payoff = take_payoff
25 else :
26 print ( f " Round { r } ( Player { player }) : Optimal to PASS . " )
27
28 print ( f " Nash Equilibrium outcome dictates game ends with payoffs : {
current_payoff } " )
29
30 c e n t i p e d e _ g a m e _ b a c k w a r d _ i n d u c t i o n (4)
12
6.3 Output Screenshot
13