Game Theory
Game Theory
2 Choice of Area 9
Source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1
Contents
2
Chapter 1
Input :
No. of Games : 4
Winner of the Game Gi : 1 1 2 3
Output : YES
Explanation :
Game1 : P1 vs P2 : P1 wins
Game2 : P1 vs P3 : P1 wins
Game3 : P1 vs P2 : P2 wins
Game4 : P3 vs P2 : P3 wins
None of the winners were invalid
Input :
No. of Games : 2
Winner of the Game Gi : 2 1
Output : NO
Explanation :
Game1 : P1 vs P2 : P2 wins
Game2 : P2 vs P3 : P1 wins (Invalid winner)
In Game2 P1 is spectator
Approach :
3
Chapter 1. Check if the game is valid or not
Start with P1 and P2 and continue the game while making the loser new spectator by
subtracting the current spectator and winner from total sum of three players i.e. 6. An
invalid entry will halt the process.
Below is the implementation for the above approach:
C++
Java
4
Chapter 1. Check if the game is valid or not
// is valid
import java.io.*;
class GFG {
static String check_valid(int a[], int n)
{
// starting with player P1 and P2
// so making P3 spectator
int spec = 3;
for (int i = 0; i < n; i++) {
// If spectator wins a game
// then its not valid
if (a[i] == spec) {
return "Invalid";
}
// subtracting the current spectator
// and winner from total sum 6 which
// makes losing player spectator
spec = 6 - a[i] - spec;
}
// None of the winner is found spectator.
return "Valid";
}
// Driver program to test above functions
public static void main (String[] args) {
int a[] = {1, 1, 2, 3};
int n = a.length;
System.out.println(check_valid(a, n));
}
}
// This code is contributed by vt_m
Python3
5
Chapter 1. Check if the game is valid or not
def check_valid( a , n ):
# starting with player P1 and P2
# so making P3 spectator
spec = 3
for i in range(n):
# If spectator wins a game
# then its not valid
if a[i] == spec:
return "Invalid"
# subtracting the current spectator
# and winner from total sum 6 which
# makes losing player spectator
spec = 6 - a[i] - spec
# None of the winner is found spectator.
return "Valid"
# Driver code to test above functions
n = 4
a = [1, 1, 2, 3]
print(check_valid(a, n))
# This code is contributed by "Sharad_Bhardwaj".
C#
6
Chapter 1. Check if the game is valid or not
}
// subtracting the current spectator
// and winner from total sum 6 which
// makes losing player spectator
spec = 6 - a[i] - spec;
}
// None of the winner is found spectator.
return "Valid";
}
// Driver program
public static void Main ()
{
int []a = {1, 1, 2, 3};
int n = a.Length;
Console.WriteLine(check_valid(a, n));
}
}
// This code is contributed by vt_m
PHP
<?php
// PHP program to check if
// the game is valid
function check_valid( $a, $n)
{
// starting with player P1 and P2
// so making P3 spectator
$spec = 3;
for ($i = 0; $i < $n; $i++)
{
// If spectator wins a game
// then its not valid
if ($a[$i] == $spec)
{
return "Invalid";
}
// subtracting the current
// spectator and winner from
// total sum 6 which makes
7
Chapter 1. Check if the game is valid or not
Output :
Valid
Improved By : vt_m
Source
https://www.geeksforgeeks.org/check-game-valid-not/
8
Chapter 2
Choice of Area
This problem can be solved using recursion, after each time unit we can go to any of the
area but we will choose that area which ultimately leads to maximum survival time. As
9
Chapter 2. Choice of Area
recursion can lead to solving same subproblem many time, we will memoize the result on
basis of power A and B, if we reach to same pair of power A and B, we won’t solve it again
instead we will take the previously calculated result.
Given below is the simple implementation of above approach.
CPP
10
Chapter 2. Choice of Area
X, Y, Z, 3, memo));
break;
case 2:
temp = 1 + max(maxSurvival(A + X.a, B + X.b,
X, Y, Z, 1, memo),
maxSurvival(A + Z.a, B + Z.b,
X, Y, Z, 3, memo));
break;
case 3:
temp = 1 + max(maxSurvival(A + X.a, B + X.b,
X, Y, Z, 1, memo),
maxSurvival(A + Y.a, B + Y.b,
X, Y, Z, 2, memo));
break;
}
// store the result into map
memo[cur] = temp;
return temp;
}
// method returns maximum survival time
int getMaxSurvivalTime(int A, int B, area X, area Y, area Z)
{
if (A <= 0 || B <= 0)
return 0;
map< pair<int, int>, int > memo;
// At first, we can step into any of the area
return
max(maxSurvival(A + X.a, B + X.b, X, Y, Z, 1, memo),
maxSurvival(A + Y.a, B + Y.b, X, Y, Z, 2, memo),
maxSurvival(A + Z.a, B + Z.b, X, Y, Z, 3, memo));
}
// Driver code to test above method
int main()
{
area X(3, 2);
area Y(-5, -10);
area Z(-20, 5);
int A = 20;
int B = 8;
cout << getMaxSurvivalTime(A, B, X, Y, Z);
return 0;
11
Chapter 2. Choice of Area
Python3
12
Chapter 2. Choice of Area
Output:
Source
https://www.geeksforgeeks.org/game-theory-choice-area/
13
Chapter 3
Note that the strategy to pick maximum of two corners may not work. In the following
14
Chapter 3. Coin game of two corners (Greedy Approach)
example, first player looses the game when he/she uses strategy to pick maximum of two
corners.
Example:
18 20 15 30 10 14
First Player picks 18, now row of coins is
20 15 30 10 14
Second player picks 20, now row of coins is
15 30 10 14
First Player picks 15, now row of coins is
30 10 14
Second player picks 30, now row of coins is
10 14
First Player picks 14, now row of coins is
10
Second player picks 10, game over.
Note that this problem is different from Optimal Strategy for a Game | DP-31. There the
target is to get maximum value. Here the target is to not loose. We have a Greedy Strategy
here. The idea is to count sum of values of all even coins and odd coins, compare the two
values. The player that makes the first move can always make sure that the other player is
never able to choose an even coin if sum of even coins is higher. Similarly, he/she can make
sure that the other player is never able to choose an odd coin if sum of odd coins is higher.
Example:
18 20 15 30 10 14
Sum of odd coins = 18 + 15 + 10 = 43
Sum of even coins = 20 + 30 + 14 = 64.
Since the sum of even coins is more, the first
player decides to collect all even coins. He first
picks 14, now the other player can only pick a coin
(10 or 18). Whichever is picked the other player,
the first player again gets an opportunity to pick
an even coin and block all even coins.
C++
15
Chapter 3. Coin game of two corners (Greedy Approach)
Java
// Java program to find coins to be
// picked to make sure that we never loose.
class GFG
{
16
Chapter 3. Coin game of two corners (Greedy Approach)
17
Chapter 3. Coin game of two corners (Greedy Approach)
for i in range(start, n) :
print(arr[i], end = " ")
# Driver code
if __name__ == "__main__" :
arr1 = [8, 15, 3, 7]
n = len(arr1)
printCoins(arr1, n)
print()
arr2 = [2, 2, 2, 2]
n = len(arr2)
printCoins(arr2, n)
print()
arr3 = [20, 30, 2, 2, 2, 10]
n = len(arr3)
printCoins(arr3, n)
# This code is contributed by ANKITRAI1
C#
// C# program to find coins to be
// picked to make sure that we never loose.
using System;
class GFG
{
// Returns optimal value possible
// that a player can collect from
// an array of coins of size n.
// Note than n must be even
static void printCoins(int[] arr, int n)
{
// Find sum of odd positioned coins
int oddSum = 0;
for (int i = 0; i < n; i += 2) oddSum += arr[i]; // Find sum of even positioned coins int
evenSum = 0; for (int i = 0; i < n; i += 2) evenSum += arr[i]; // Print even or odd coins
depending // upon which sum is greater. int start = ((oddSum > evenSum) ? 0 : 1);
for (int i = start; i < n; i++) Console.Write(arr[i]+” ”); } // Driver Code public static
void Main() { int[] arr1 = { 8, 15, 3, 7 }; int n = arr1.Length; printCoins(arr1, n); Con-
sole.Write(”\n”); int[] arr2 = { 2, 2, 2, 2 }; n = arr2.Length; printCoins(arr2, n); Con-
sole.Write(”\n”); int[] arr3 = { 20, 30, 2, 2, 2, 10 }; n = arr3.Length; printCoins(arr3, n); }
} // This code is contributed by ChitraNayal [tabby title=”PHP”] $evenSum) ? 0 : 1);
for ($i = $start; $i < $n; $i++) echo $arr[$i].” ”; } // Driver Code $arr1 = array( 8, 15, 3,
7 ); $n = sizeof($arr1); printCoins($arr1, $n); echo ”\n”; $arr2 = array( 2, 2, 2, 2 ); $n =
18
Chapter 3. Coin game of two corners (Greedy Approach)
15 3 7
2 2 2
30 2 2 2 10
Source
https://www.geeksforgeeks.org/coin-game-of-two-corners-greedy-approach/
19
Chapter 4
20
Chapter 4. Combinatorial Game Theory | Set 1 (Introduction)
The difference between them is that in Impartial Games all the possible moves from any
position of game are the same for the players, whereas in Partisan Games the moves for
all the players are not the same.
Consider a game like below :
Given a number of piles in which each pile contains some numbers of stones/coins. In each
turn, player choose one pile and remove any number of stones (at least one) from that pile.
The player who cannot move is considered to lose the game (ie., one who take the last stone
is the winner).
As it can be clearly seen from the rules of the above game that the moves are same for both
the players. There is no restriction on one player over the other. Such a game is considered
to be impartial.
The above mentioned game is famous by the name- Game of Nim which will be discussed
in next sections.
In contrast to the above game, let us take an example of chess. In this game, one player
can only move the black pieces and the other one can only move the white ones. Thus, there
is a restriction on both the players. Their set of moves are different and hence such a game
is classified under the category of Partisan Games.
Partisan Games are much harder to analyze than Impartial Games as in such games Sprague-
Grundy Theoremfails.
In the next sections, we will see mostly about Impartial games, like- Game of Nim and its
variations, Sprague-Grundy Theorem and many more.
Exercise:
Readers may try solving below simple combinatorial Game Theory problems.
Cycle Race
Game of Chocolates
Sources:
http://www.cs.cmu.edu/afs/cs/academic/class/15859-f01/www/notes/comb.pdf
21
Chapter 4. Combinatorial Game Theory | Set 1 (Introduction)
https://en.wikipedia.org/wiki/Combinatorial_game_theory
https://en.wikipedia.org/wiki/Impartial_game
https://en.wikipedia.org/wiki/Partisan_game
Source
https://www.geeksforgeeks.org/introduction-to-combinatorial-game-theory/
22
Chapter 5
23
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
24
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
In fact, we can predict the winner of the game before even playing the game !
Nim-Sum : The cumulative XOR value of the number of coins/stones in each piles/heaps
at any point of the game is called Nim-Sum at that point.
“If both A and B play optimally (i.e- they don’t make any mistakes),
then the player starting first is guaranteed to win if the Nim-Sum at the
beginning of the game is non-zero. Otherwise, if the Nim-Sum evaluates to
zero, then player A will lose definitely.”
25
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
26
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
27
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
28
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
29
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
else
printf("HUMAN will win\n");
}
else
{
if (whoseTurn == COMPUTER)
printf("HUMAN will win\n");
else
printf("COMPUTER will win\n");
}
return;
}
// Driver program to test above functions
int main()
{
// Test Case 1
int piles[] = {3, 4, 5};
int n = sizeof(piles)/sizeof(piles[0]);
// We will predict the results before playing
// The COMPUTER starts first
knowWinnerBeforePlaying(piles, n, COMPUTER);
// Let us play the game with COMPUTER starting first
// and check whether our prediction was right or not
playGame(piles, n, COMPUTER);
/*
Test Case 2
int piles[] = {3, 4, 7};
int n = sizeof(piles)/sizeof(piles[0]);
// We will predict the results before playing
// The HUMAN(You) starts first
knowWinnerBeforePlaying (piles, n, COMPUTER);
// Let us play the game with COMPUTER starting first
// and check whether our prediction was right or not
playGame (piles, n, HUMAN); */
return(0);
}
Output : May be different on different runs as random numbers are used to decide next
move (for the loosing player).
30
Chapter 5. Combinatorial Game Theory | Set 2 (Game of Nim)
GAME STARTS
COMPUTER won
References :
https://en.wikipedia.org/wiki/Nim
Source
https://www.geeksforgeeks.org/combinatorial-game-theory-set-2-game-nim/
31
Chapter 6
32
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
immediately by the first player, and is equal to Mex of the nimbers of all possible next
positions for any other game.
Below are three example games and programs to calculate Grundy Number and Mex for
each of them. Calculation of Grundy Numbers is done basically by a recursive function
called as calculateGrundy() function which uses calculateMex() function as its sub-routine.
Example 1
The game starts with a pile of n stones, and the player to move may take any positive
number of stones. Calculate the Grundy Numbers for this game. The last player to move
wins. Which player wins the game?
Since if the first player has 0 stones, he will lose immediately, so Grundy(0) = 0
If a player has 1 stones, then he can take all the stones and win. So the next possible
position of the game (for the other player) is (0) stones
Hence, Grundy(1) = Mex(0) = 1 [According to the definition of Mex]
Similarly, If a player has 2 stones, then he can take only 1 stone or he can take all the stones
and wins. So the next possible position of the game (for the other player) is (1, 0) stones
respectively.
Hence, Grundy(2) = Mex(0, 1) = 2 [According to the definition of Mex]
Similarly, If a player has ‘n’ stones, then he can take only 1 stone, or he can take 2 stones……..
or he can take all the stones and win. So the next possible position of the game (for the
other player) is (n-1, n-2,….1) stones respectively.
Hence, Grundy(n) = Mex (0, 1, 2, ….n-1) = n [According to the definition of Mex]
We summarize the first the Grundy Value from 0 to 10 in the below table-
33
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
Output :
10
The above solution can be optimized using Dynamic Programming as there are overlapping
subproblems. The Dynamic programming based implementation can be found here.
Example 2
The game starts with a pile of n stones, and the player to move may take any positive
number of stones upto 3 only. The last player to move wins. Which player wins the game?
This game is 1 pile version of Nim.
Since if the first player has 0 stones, he will lose immediately, so Grundy(0) = 0
If a player has 1 stones, then he can take all the stones and win. So the next possible
position of the game (for the other player) is (0) stones
Hence, Grundy(1) = Mex(0) = 1 [According to the definition of Mex]
34
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
Similarly, if a player has 2 stones, then he can take only 1 stone or he can take 2 stones
and win. So the next possible position of the game (for the other player) is (1, 0) stones
respectively.
Hence, Grundy(2) = Mex(0, 1) = 2 [According to the definition of Mex]
Similarly, Grundy(3) = Mex(0, 1, 2) = 3 [According to the definition of Mex]
But what about 4 stones ?
If a player has 4 stones, then he can take 1 stone or he can take 2 stones or 3 stones, but he
can’t take 4 stones (see the constraints of the game). So the next possible position of the
game (for the other player) is (3, 2, 1) stones respectively.
Hence, Grundy(4) = Mex (1, 2, 3) = 0 [According to the definition of Mex]
So we can define Grundy Number of any n >= 4 recursively as-
Grundy(n) = Mex[Grundy (n-1), Grundy (n-2), Grundy (n-3)]
We summarize the first the Grundy Value from 0 to 10 in the below table-
35
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
if (n == 0)
return (0);
if (n == 1)
return (1);
if (n == 2)
return (2);
if (n == 3)
return (3);
unordered_set<int> Set; // A Hash Table
for (int i=1; i<=3; i++)
Set.insert(calculateGrundy(n - i));
return (calculateMex(Set));
}
// Driver program to test above functions
int main()
{
int n = 10;
printf("%d", calculateGrundy(n));
return (0);
}
Output :
The above solution can be optimized using Dynamic Programming as there are overlapping
subproblems. The Dynamic programming based implementation can be found here.
Example 3
The game starts with a number- ‘n’ and the player to move divides the number- ‘n’ with 2,
3 or 6 and then takes the floor. If the integer becomes 0, it is removed. The last player to
move wins. Which player wins the game?
We summarize the first the Grundy Value from 0 to 10 in the below table:
36
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
a game.
Game Description : The game starts with a number- 'n'
and the player to move divides the number- 'n' with 2, 3
or 6 and then takes the floor. If the integer becomes 0,
it is removed. The last player to move wins. */
#include<bits/stdc++.h>
using namespace std;
// A Function to calculate Mex of all the values in
// that set.
int calculateMex(unordered_set<int> Set)
{
int Mex = 0;
while (Set.find(Mex) != Set.end())
Mex++;
return (Mex);
}
// A function to Compute Grundy Number of 'n'
// Only this function varies according to the game
int calculateGrundy (int n)
{
if (n == 0)
return (0);
unordered_set<int> Set; // A Hash Table
Set.insert(calculateGrundy(n/2));
Set.insert(calculateGrundy(n/3));
Set.insert(calculateGrundy(n/6));
return (calculateMex(Set));
}
// Driver program to test above functions
int main()
{
int n = 10;
printf("%d", calculateGrundy (n));
return (0);
}
Output :
37
Chapter 6. Combinatorial Game Theory | Set 3 (Grundy Numbers/Nimbers and Mex)
The above solution can be optimized using Dynamic Programming as there are overlapping
subproblems. The Dynamic programming based implementation can be found here.
References-
https://en.wikipedia.org/wiki/Mex_(mathematics)
https://en.wikipedia.org/wiki/Nimber
In the next post, we will be discussing solutions of Impartial Games using Grundy Numbers
or Nimbers.
Improved By : ozym4nd145
Source
https://www.geeksforgeeks.org/combinatorial-game-theory-set-3-grundy-numbersnimbers-and-mex/
38
Chapter 7
39
Chapter 7. Combinatorial Game Theory | Set 4 (Sprague – Grundy Theorem)
4. If the XOR value is non-zero, then the player who is going to make the turn (First
Player) will win else he is destined to lose, no matter what.
Example Game : The game starts with 3 piles having 3, 4 and 5 stones, and the player
to move may take any positive number of stones upto 3 only from any of the piles [Provided
that the pile has that much amount of stones]. The last player to move wins. Which player
wins the game assuming that both players play optimally?
How to tell who will win by applying Sprague-Grundy Theorem?
As, we can see that this game is itself composed of several sub-games.
First Step : The sub-games can be considered as each piles.
Second Step : We see from the below table that
Grundy(3) = 3
Grundy(4) = 0
Grundy(5) = 1
We have already seen how to calculate the Grundy Numbers of this game in the previous
article.
Third Step : The XOR of 3, 4, 5 = 2
Fourth Step : Since XOR is a non-zero number, so we can say that the first player will
win.
Below is C++ program that implements above 4 steps.
40
Chapter 7. Combinatorial Game Theory | Set 4 (Sprague – Grundy Theorem)
/* piles[] -> Array having the initial count of stones/coins
in each piles before the game has started.
n -> Number of piles
Grundy[] -> Array having the Grundy Number corresponding to
the initial position of each piles in the game
The piles[] and Grundy[] are having 0-based indexing*/
#define PLAYER1 1
#define PLAYER2 2
// A Function to calculate Mex of all the values in that set
int calculateMex(unordered_set<int> Set)
{
int Mex = 0;
while (Set.find(Mex) != Set.end())
Mex++;
return (Mex);
}
// A function to Compute Grundy Number of 'n'
int calculateGrundy(int n, int Grundy[])
{
Grundy[0] = 0;
Grundy[1] = 1;
Grundy[2] = 2;
Grundy[3] = 3;
if (Grundy[n] != -1)
return (Grundy[n]);
unordered_set<int> Set; // A Hash Table
for (int i=1; i<=3; i++)
Set.insert (calculateGrundy (n-i, Grundy));
// Store the result
Grundy[n] = calculateMex (Set);
return (Grundy[n]);
}
// A function to declare the winner of the game
void declareWinner(int whoseTurn, int piles[],
41
Chapter 7. Combinatorial Game Theory | Set 4 (Sprague – Grundy Theorem)
42
Chapter 7. Combinatorial Game Theory | Set 4 (Sprague – Grundy Theorem)
Output :
References :
https://en.wikipedia.org/wiki/Sprague%E2%80%93Grundy_theorem
Exercise to the Readers: Consider the below game.
“A game is played by two players with N integers A1, A2, .., AN. On his/her turn, a player
selects an integer, divides it by 2, 3, or 6, and then takes the floor. If the integer becomes
0, it is removed. The last player to move wins. Which player wins the game if both players
play optimally?”
Hint : See the example 3 of previous article.
Improved By : vinayb21
Source
https://www.geeksforgeeks.org/combinatorial-game-theory-set-4-sprague-grundy-theorem/
43
Chapter 8
Let’s start the solution step by step. We have total of three option for the XOR of array
and this game.
1. XOR of array is already 0: In this case Alice will unable to make a move and
hence Alice is winner.
2. XOR of array is not zero: Now, in this case we have two options, either size of
array will be odd or even.
• CASE A: If the array size is odd then for sure Bob will win the game.
• CASE B: If the array size is even then Alice will win the game.
44
Chapter 8. Find the winner in nim-game
int res = 0;
for (int i = 1; i <= N; i++) {
res ^= a[i];
}
if (res == 0)
return "ALice";
if (N%2 == 0)
return "Alice";
else
return "Bob";
C++
45
Chapter 8. Find the winner in nim-game
res ^= A[i];
// case when Alice is winner
if (res == 0 || n % 2 == 0)
return "Alice";
// when Bob is winner
else
return "Bob";
}
// driver program
int main()
{
int A[] = { 1, 4, 3, 5 };
int n = siseof(A) / sizeof(A[0]);
cout << "Winner = " << findWinner(A, n);
return 0;
}
Java
46
Chapter 8. Find the winner in nim-game
System.out.print("Winner = "
+ findWinner(A, n));
}
}
// This code is contributed by Anant Agarwal.
Python3
C#
47
Chapter 8. Find the winner in nim-game
// case when Alice is winner
if (res == 0 || n % 2 == 0)
return "Alice";
// when Bob is winner
else
return "Bob";
}
//Driver code
public static void Main ()
{
int []A = { 1, 4, 3, 5 };
int n =A.Length;
Console.WriteLine("Winner = "
+ findWinner(A, n));
}
}
// This code is contributed by vt_m.
PHP
<?php
// PHP to find nim-game winner
// function to find
// winner of NIM-game
function findWinner($A, $n)
{
$res = 0;
for ($i = 0; $i < $n; $i++)
$res ^= $A[$i];
// case when Alice is winner
if ($res == 0 or $n % 2 == 0)
return "Alice";
// when Bob is winner
else
return "Bob";
}
// Driver Code
$A = array(1, 4, 3, 5 );
$n = count($A);
48
Chapter 8. Find the winner in nim-game
Output :
Winner = Alice
Improved By : vt_m
Source
https://www.geeksforgeeks.org/find-winner-nim-game/
49
Chapter 9
Input : 4
Output : player 1
Input : 7
Output : player 2
To solve this problem, we need to find each possible value of n as a winning or losing position.
Since above game is one of the impartial combinatorial games, therefore the characterization
of losing and winning position is valid.
The characteristic properties of winning and losing states are:
If a player is able to make a move such that the next move is the losing state than the player
is at winning state. Find the state of player 1, if player1 is in winning state then player 1
wins the game otherwise player 2 will win.
Consider the following base positions:
50
Chapter 9. Game of N stones where each player can remove 1, 3 or 4
1. position 0 is the losing state, if the number of stones is 0 than the player1 will unable
to make a move therefore player1 loses.
2. position 1 is the winning state, if the number of stones is 1 than the player1 will
remove the stone and win the game.
3. position 2 is the losing state, if the number of stones is 2 than the player1 will remove
1 stone and then player2 will remove the second stone and win the game.
4. position 3 is the winning state, if the player is able to take a move such that the next
move is the losing state than the player is at winning state, the palyer1 will remove
all the 3 stones
5. position 4 is the winning state, if the player is able to take a move such that the next
move is the losing state than the player is at winning state, the palyer1 will remove
all the 4 stones
6. position 5 is the winning state, if the player is able to take a move such that the next
move is the losing state than the player is at winning state, the palyer1 will remove 3
stones leaving 2 stones, which is the losing state
7. position 6 is the winning state, if the player is able to take a move such that the next
move is the losing state than the player is at winning state, the palyer1 will remove 4
stones leaving 2 stones, which is the losing state
8. position 7 is the losing state, if the number of stones is 7 than the player1 can remove
1, 3 or 4 stones which all leads to the losing state, therefore player1 will lose.
CPP
51
Chapter 9. Game of N stones where each player can remove 1, 3 or 4
Java
52
Chapter 9. Game of N stones where each player can remove 1, 3 or 4
position[7] = 0;
// find states for other positions
for (int i = 8; i < MAX; i++) {
if (position[i - 1]!=1 ||
position[i - 3]!=1
|| position[i - 4]!=1)
position[i] = 1;
else
position[i] = 0;
}
}
//Driver code
public static void main (String[] args)
{
int N = 100;
int position[]=new int[MAX];
findStates(position);
if (position[N] == 1)
System.out.print("Player 1");
else
System.out.print("Player 2");
}
}
// This code is contributed by Anant Agarwal.
Python3
53
Chapter 9. Game of N stones where each player can remove 1, 3 or 4
position[3] = 1;
position[4] = 1;
position[5] = 1;
position[6] = 1;
position[7] = 0
# find states for other positions
for i in range(8,MAX+1):
if not(position[i - 1]) or not(position[i - 3]) or not(position[i - 4]):
position[i] = 1;
else:
position[i] = 0;
#driver function
N = 100
position = [0] * (MAX+1)
findStates(position)
if (position[N] == 1):
print("Player 1")
else:
print("Player 2")
# This code is contributed by
# Smitha Dinesh Semwal
C#
54
Chapter 9. Game of N stones where each player can remove 1, 3 or 4
position[3] = 1;
position[4] = 1;
position[5] = 1;
position[6] = 1;
position[7] = 0;
// find states for other positions
for (int i = 8; i < MAX; i++)
{
if (position[i - 1] != 1
|| position[i - 3] != 1
|| position[i - 4]!=1)
position[i] = 1;
else
position[i] = 0;
}
}
// Driver code
public static void Main ()
{
int N = 100;
int []position = new int[MAX];
findStates(position);
if (position[N] == 1)
Console.WriteLine("Player 1");
else
Console.WriteLine("Player 2");
}
}
// This code is contributed by vt_m.
Output:
Player 2
Improved By : vt_m
Source
https://www.geeksforgeeks.org/game-of-n-stones-where-each-player-can-remove-1-3-or-4/
55
Chapter 10
Input : N = 3.
Output : Player A
Player A remove stone 1 which is at the top, then Player B remove stone 2
and finally player A removes the last stone.
Input : N = 15.
Output : Player A
For N = 1, player A will remove the only stone from the pile and wins the game.
For N = 2, player A will remove the first stone and then player B remove the second or the
last stone. So player B will win the game.
So, we can observe player A wins when N is odd and player B wins when N is even.
Below is the implementation of this approach:
C++
56
Chapter 10. Game of Nim with removal of one stone allowed
Java
57
Chapter 10. Game of Nim with removal of one stone allowed
// This code is contributed by Arnav Kr. Mandal.
Python3
C#
58
Chapter 10. Game of Nim with removal of one stone allowed
}
}
// This code is contributed by vt_m.
PHP
<?php
// PHP program for Game of
// Nim with removal of one
// stone allowed.
// Return true if player A wins,
// return false if player B wins.
function findWinner($N)
{
// Checking the last bit of N.
return $N&1;
}
// Driver Code
$N = 15;
if(findWinner($N))
echo "Player A";
else
echo "Player B";
// This code is contributed by vt_m.
?>
Output :
Player A
Source
https://www.geeksforgeeks.org/game-nim-removal-one-stone-allowed/
59
Chapter 11
Input : arr[] = { 1, 2, 1, 2 }
Output : Player 1 wins
From above examples, we can observe that if number of count of distinct element is even,
first player always wins. Else second player wins.
Lets take an another example :
60
Chapter 11. Game of replacing array elements
int arr[] = 1, 2, 3, 4, 5, 6
Here number of distinct element is even(n). If player 1 pick any two number lets say (4, 1),
then we left with n-1 distinct element. So player second left with n-1 distinct element. This
precess go on until distinct element become 1. Here n = 6
Player : P1 p2 P1 p2 P1 P2
distinct : [n, n-1, n-2, n-3, n-4, n-5 ]
Output:
Player 1 Wins
61
Chapter 11. Game of replacing array elements
Source
https://www.geeksforgeeks.org/game-replacing-array-elements/
62
Chapter 12
Implementation of Tic-Tac-Toe
game
• The game is to be played between two people (in this program between HUMAN and
COMPUTER).
• One of the player chooses ‘O’ and the other ‘X’ to mark their respective cells.
• The game starts with one of the players and the game ends when one of the players
has one whole row/ column/ diagonal filled with his/her respective character (‘O’ or
‘X’).
• If no one wins, then the game is said to be draw.
63
Chapter 12. Implementation of Tic-Tac-Toe game
Implementation
In our program the moves taken by the computer and the human are chosen randomly.
We use rand() function for this.
What more can be done in the program?
The program is in not played optimally by both sides because the moves are chosen
randomly. The program can be easily modified so that both players play optimally
(which will fall under the category of Artificial Intelligence). Also the program can be
modified such that the user himself gives the input (using scanf() or cin).
The above changes are left as an exercise to the readers.
Winning Strategy – An Interesting Fact
If both the players play optimally then it is destined that you will never lose (“although
the match can still be drawn”). It doesn’t matter whether you play first or second.In
another ways – “ Two expert players will always draw ”.
Isn’t this interesting ?
64
Chapter 12. Implementation of Tic-Tac-Toe game
65
Chapter 12. Implementation of Tic-Tac-Toe game
else
printf("HUMAN has won\n");
return;
}
// A function that returns true if any of the row
// is crossed with the same player's move
bool rowCrossed(char board[][SIDE])
{
for (int i=0; i<SIDE; i++)
{
if (board[i][0] == board[i][1] &&
board[i][1] == board[i][2] &&
board[i][0] != ' ')
return (true);
}
return(false);
}
// A function that returns true if any of the column
// is crossed with the same player's move
bool columnCrossed(char board[][SIDE])
{
for (int i=0; i<SIDE; i++)
{
if (board[0][i] == board[1][i] &&
board[1][i] == board[2][i] &&
board[0][i] != ' ')
return (true);
}
return(false);
}
// A function that returns true if any of the diagonal
// is crossed with the same player's move
bool diagonalCrossed(char board[][SIDE])
{
if (board[0][0] == board[1][1] &&
board[1][1] == board[2][2] &&
board[0][0] != ' ')
return(true);
if (board[0][2] == board[1][1] &&
board[1][1] == board[2][0] &&
board[0][2] != ' ')
return(true);
return(false);
66
Chapter 12. Implementation of Tic-Tac-Toe game
}
// A function that returns true if the game is over
// else it returns a false
bool gameOver(char board[][SIDE])
{
return(rowCrossed(board) || columnCrossed(board)
|| diagonalCrossed(board) );
}
// A function to play Tic-Tac-Toe
void playTicTacToe(int whoseTurn)
{
// A 3*3 Tic-Tac-Toe board for playing
char board[SIDE][SIDE];
int moves[SIDE*SIDE];
// Initialise the game
initialise(board, moves);
// Show the instructions before playing
showInstructions();
int moveIndex = 0, x, y;
// Keep playing till the game is over or it is a draw
while (gameOver(board) == false &&
moveIndex != SIDE*SIDE)
{
if (whoseTurn == COMPUTER)
{
x = moves[moveIndex] / SIDE;
y = moves[moveIndex] % SIDE;
board[x][y] = COMPUTERMOVE;
printf("COMPUTER has put a %c in cell %d\n",
COMPUTERMOVE, moves[moveIndex]+1);
showBoard(board);
moveIndex ++;
whoseTurn = HUMAN;
}
else if (whoseTurn == HUMAN)
{
x = moves[moveIndex] / SIDE;
y = moves[moveIndex] % SIDE;
board[x][y] = HUMANMOVE;
printf ("HUMAN has put a %c in cell %d\n",
67
Chapter 12. Implementation of Tic-Tac-Toe game
HUMANMOVE, moves[moveIndex]+1);
showBoard(board);
moveIndex ++;
whoseTurn = COMPUTER;
}
}
// If the game has drawn
if (gameOver(board) == false &&
moveIndex == SIDE * SIDE)
printf("It's a draw\n");
else
{
// Toggling the user to declare the actual
// winner
if (whoseTurn == COMPUTER)
whoseTurn = HUMAN;
else if (whoseTurn == HUMAN)
whoseTurn = COMPUTER;
// Declare the winner
declareWinner(whoseTurn);
}
return;
}
// Driver program
int main()
{
// Let us play the game with COMPUTER starting first
playTicTacToe(COMPUTER);
return (0);
}
Output:
Tic-Tac-Toe
1 | 2 | 3
--------------
4 | 5 | 6
--------------
7 | 8 | 9
68
Chapter 12. Implementation of Tic-Tac-Toe game
- - - - - - - - - -
| |
--------------
| | O
--------------
| |
| |
--------------
| | O
--------------
X | |
| |
--------------
| O | O
--------------
X | |
X | |
--------------
| O | O
--------------
X | |
X | |
--------------
| O | O
--------------
X | | O
69
Chapter 12. Implementation of Tic-Tac-Toe game
X | |
--------------
| O | O
--------------
X | X | O
X | |
--------------
O | O | O
--------------
X | X | O
Source
https://www.geeksforgeeks.org/implementation-of-tic-tac-toe-game/
70
Chapter 13
Input : N = 5, K = 2
Output : 3
Firstly, the child at position 2 is out,
then position 4 goes out, then position 1
Finally, the child at position 5 is out.
So the position 3 survives.
Input : 7 4
Output : 2
We have discussed a recursive solution for Josephus Problem. The given solution is better
than the recursive solution of Josephus Solution which is not suitable for large inputs as it
gives stack overflow. The time complexity is O(N).
Approach – In the algorithm, we use sum variable to find out the chair to be removed. The
current chair position is calculated by adding the chair count K to the previous position i.e.
sum and modulus of the sum. At last we return sum+1 as numbering starts from 1 to N.
71
Chapter 13. Josephus Problem | (Iterative Solution)
#include <bits/stdc++.h>
using namespace std;
// Function for finding the winning child.
long long int find(long long int n, long long int k)
{
long long int sum = 0, i;
// For finding out the removed
// chairs in each iteration
for (i = 2; i <= n; i++)
sum = (sum + k) % i;
return sum + 1;
}
// Driver function to find the winning child
int main()
{
int n = 14, k = 2;
cout << find(n, k);
return 0;
}
Output:
13
Source
https://www.geeksforgeeks.org/josephus-problem-iterative-solution/
72
Chapter 14
73
Chapter 14. Minimax Algorithm in Game Theory | Set 1 (Introduction)
Since this is a backtracking based algorithm, it tries all possible moves, then backtracks and
makes a decision.
• Maximizer goes LEFT : It is now the minimizers turn. The minimizer now has a
choice between 3 and 5. Being the minimizer it will definitely choose the least among
both, that is 3
• Maximizer goes RIGHT : It is now the minimizers turn. The minimizer now has a
choice between 2 and 9. He will choose 2 as it is the least among the two values.
Being the maximizer you would choose the larger value that is 3. Hence the optimal move
for the maximizer is to go LEFT and the optimal value is 3.
74
Chapter 14. Minimax Algorithm in Game Theory | Set 1 (Introduction)
75
Chapter 14. Minimax Algorithm in Game Theory | Set 1 (Introduction)
int h = log2(n);
int res = minimax(0, 0, true, scores, h);
cout << "The optimal value is : " << res << endl;
return 0;
}
Java
76
Chapter 14. Minimax Algorithm in Game Theory | Set 1 (Introduction)
// Driver code
public static void main (String[] args) {
// The number of elements in scores must be
// a power of 2.
int scores[] = {3, 5, 2, 9, 12, 5, 23, 23};
int n = scores.length;
int h = log2(n);
int res = minimax(0, 0, true, scores, h);
System.out.println( "The optimal value is : " +res);
}
}
// This code is contributed by vt_m
Python3
77
Chapter 14. Minimax Algorithm in Game Theory | Set 1 (Introduction)
Output:
• In the above example, there are only two choices for a player. In general, there
can be more choices. In that case we need to recur for all possible moves and find
maximum/minimum. For example, in Tic-Tax-Toe, the first player can make 9 possible
moves.
• In above example, the scores (leaves of Game Tree) are given to us. For a typical
game, we need to derive these values
Source
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-1-introduction/
78
Chapter 15
79
Chapter 15. Minimax Algorithm in Game Theory | Set 2 (Introduction to Evaluation
Function)
3. If no one has won or the game results in a draw then we give a value of +0.
We could have chosen any positive / negative value other than 10. For the sake of simplicity
we chose 10 for the sake of simplicity we shall use lower case ‘x’ and lower case ‘o’ to represent
the players and an underscore ‘_’ to represent a blank space on the board.
If we represent our board as a 3×3 2D character matrix, like char board[3][3]; then we have
80
Chapter 15. Minimax Algorithm in Game Theory | Set 2 (Introduction to Evaluation
Function)
to check each row, each column and the diagonals to check if either of the players have
gotten 3 in a row.
81
Chapter 15. Minimax Algorithm in Game Theory | Set 2 (Introduction to Evaluation
Function)
return +10;
else if (b[0][2]=='o')
return -10;
}
// Else if none of them have won then return 0
return 0;
}
// Driver code
int main()
{
char board[3][3] =
{
{ 'x', '_', 'o'},
{ '_', 'x', 'o'},
{ '_', '_', 'x'}
};
int value = evaluate(board);
printf("The value of this board is %d\n", value);
return 0;
}
Output :
The idea of this article is to understand how to write a simple evaluation function for the
game Tic-Tac-Toe. In the next article we shall see how to combine this evaluation function
with the minimax function. Stay Tuned.
Source
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-2-evaluation-function/
82
Chapter 16
function findBestMove(board):
bestMove = NULL
for each move in board :
if current move is better than bestMove
bestMove = current move
return bestMove
Minimax :
To check whether or not the current move is better than the best move we take the help of
minimax() function which will consider all the possible ways the game can go and returns
83
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
the best value for that move, assuming the opponent also plays optimally
The code for the maximizer and minimizer in the minimax() function is similar to find-
BestMove() , the only difference is, instead of returning a move, it will return a value.
Here is the pseudocode :
if isMaximizingPlayer :
bestVal = -INFINITY
for each move in board :
value = minimax(board, depth+1, false)
bestVal = max( bestVal, value)
return bestVal
else :
bestVal = +INFINITY
for each move in board :
value = minimax(board, depth+1, true)
bestVal = min( bestVal, value)
return bestVal
To check whether the game is over and to make sure there are no moves left we use is-
MovesLeft() function. It is a simple straightforward function which checks whether a
move is available or not and returns true or false respectively. Pseudocode is as follows :
function isMovesLeft(board):
for each cell in board:
if current cell is empty:
return true
return false
One final step is to make our AI a little bit smarter. Even though the following AI plays
perfectly, it might choose to make a move which will result in a slower victory or a faster
loss. Lets take an example and explain it.
Assume that there are 2 possible ways for X to win the game from a give board state.
84
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
Our evaluation function will return a value of +10 for both moves A and B. Even though
the move A is better because it ensures a faster victory, our AI may choose B sometimes.
To overcome this problem we subtract the depth value from the evaluated score. This means
that in case of a victory it will choose a the victory which takes least number of moves and
in case of a loss it will try to prolong the game and play as many moves as possible. So the
new evaluated value will be
Now since move A has a higher score compared to move B our AI will choose move A over
move B. The same thing must be applied to the minimizer. Instead of subtracting the depth
we add the depth value as the minimizer always tries to get, as negative a value as possible.
We can subtract the depth either inside the evaluation function or outside it. Anywhere is
fine. I have chosen to do it outside the function. Pseudocode implementation is as follows.
85
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
if (board[i][j]=='_')
return true;
return false;
}
// This is the evaluation function as discussed
// in the previous article ( http://goo.gl/sJgv68 )
int evaluate(char b[3][3])
{
// Checking for Rows for X or O victory.
for (int row = 0; row<3; row++)
{
if (b[row][0]==b[row][1] &&
b[row][1]==b[row][2])
{
if (b[row][0]==player)
return +10;
else if (b[row][0]==opponent)
return -10;
}
}
// Checking for Columns for X or O victory.
for (int col = 0; col<3; col++)
{
if (b[0][col]==b[1][col] &&
b[1][col]==b[2][col])
{
if (b[0][col]==player)
return +10;
else if (b[0][col]==opponent)
return -10;
}
}
// Checking for Diagonals for X or O victory.
if (b[0][0]==b[1][1] && b[1][1]==b[2][2])
{
if (b[0][0]==player)
return +10;
else if (b[0][0]==opponent)
return -10;
}
if (b[0][2]==b[1][1] && b[1][1]==b[2][0])
{
if (b[0][2]==player)
86
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
return +10;
else if (b[0][2]==opponent)
return -10;
}
// Else if none of them have won then return 0
return 0;
}
// This is the minimax function. It considers all
// the possible ways the game can go and returns
// the value of the board
int minimax(char board[3][3], int depth, bool isMax)
{
int score = evaluate(board);
// If Maximizer has won the game return his/her
// evaluated score
if (score == 10)
return score;
// If Minimizer has won the game return his/her
// evaluated score
if (score == -10)
return score;
// If there are no more moves and no winner then
// it is a tie
if (isMovesLeft(board)==false)
return 0;
// If this maximizer's move
if (isMax)
{
int best = -1000;
// Traverse all cells
for (int i = 0; i<3; i++)
{
for (int j = 0; j<3; j++)
{
// Check if cell is empty
if (board[i][j]=='_')
{
// Make the move
board[i][j] = player;
// Call minimax recursively and choose
87
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
88
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
bestMove.col = -1;
// Traverse all cells, evalutae minimax function for
// all empty cells. And return the cell with optimal
// value.
for (int i = 0; i<3; i++)
{
for (int j = 0; j<3; j++)
{
// Check if celll is empty
if (board[i][j]=='_')
{
// Make the move
board[i][j] = player;
// compute evaluation function for this
// move.
int moveVal = minimax(board, 0, false);
// Undo the move
board[i][j] = '_';
// If the value of the current move is
// more than the best value, then update
// best/
if (moveVal > bestVal)
{
bestMove.row = i;
bestMove.col = j;
bestVal = moveVal;
}
}
}
}
printf("The value of the best Move is : %d\n\n",
bestVal);
return bestMove;
}
// Driver code
int main()
{
char board[3][3] =
{
{ 'x', 'o', 'x' },
{ 'o', 'o', 'x' },
89
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
Output :
This image depicts all the possible paths that the game can take from the root board state.
It is often called the Game Tree.
The 3 possible scenarios in the above example are :
• Left Move : If X plays [2,0]. Then O will play [2,1] and win the game. The value of
this move is -10
90
Chapter 16. Minimax Algorithm in Game Theory | Set 3 (Tic-Tac-Toe AI – Finding
optimal move)
• Middle Move : If X plays [2,1]. Then O will play [2,2] which draws the game. The
value of this move is 0
• Right Move : If X plays [2,2]. Then he will win the game. The value of this move is
+10;
Source
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-3-tic-tac-toe-ai-finding-optimal-move/
91
Chapter 17
Pseudocode :
if isMaximizingPlayer :
bestVal = -INFINITY
for each child node :
value = minimax(node, depth+1, false, alpha, beta)
92
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
else :
bestVal = +INFINITY
for each child node :
value = minimax(node, depth+1, true, alpha, beta)
bestVal = min( bestVal, value)
beta = min( beta, bestVal)
if beta <= alpha:
break
return bestVal
• The initial call starts from A. The value of alpha here is -INFINITY and the value
of beta is +INFINITY. These values are passed down to subsequent nodes in the
tree. At A the maximizer must choose max of B and C, so A calls B first
• At B it the minimizer must choose min of D and E and hence calls D first.
• At D, it looks at its left child which is a leaf node. This node returns a value of 3.
Now the value of alpha at D is max( -INF, 3) which is 3.
• To decide whether its worth looking at its right node or not, it checks the condition
beta<=alpha. This is false since beta = +INF and alpha = 3. So it continues the
search.
• D now looks at its right child which returns a value of 5.At D, alpha = max(3, 5)
which is 5. Now the value of node D is 5
93
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
So far this is how our game tree looks. The 9 is crossed out because it was never computed.
94
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
can see that it did not matter what those last 2 values were. We also saved a lot of
computation by skipping a whole sub tree.
• C now returns a value of 2 to A. Therefore the best value at A is max( 5, 2) which is
a 5.
• Hence the optimal value that the maximizer can get is 5
This is how our final game tree looks like. As you can see G has been crossed out as it was
never computed.
CPP
95
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
if (maximizingPlayer)
{
int best = MIN;
// Recur for left and
// right children
for (int i = 0; i < 2; i++)
{
int val = minimax(depth + 1, nodeIndex * 2 + i,
false, values, alpha, beta);
best = max(best, val);
alpha = max(alpha, best);
// Alpha Beta Pruning
if (beta <= alpha)
break;
}
return best;
}
else
{
int best = MAX;
// Recur for left and
// right children
for (int i = 0; i < 2; i++)
{
int val = minimax(depth + 1, nodeIndex * 2 + i,
true, values, alpha, beta);
best = min(best, val);
beta = min(beta, best);
// Alpha Beta Pruning
if (beta <= alpha)
break;
}
return best;
}
}
// Driver Code
int main()
{
int values[8] = { 3, 5, 6, 9, 1, 2, 0, -1 };
cout <<"The optimal value is : "<< minimax(0, 0, true, values, MIN, MAX);;
return 0;
96
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
Java
97
Chapter 17. Minimax Algorithm in Game Theory | Set 4 (Alpha-Beta Pruning)
{
int best = MAX;
// Recur for left and
// right children
for (int i = 0; i < 2; i++)
{
int val = minimax(depth + 1, nodeIndex * 2 + i,
true, values, alpha, beta);
best = Math.min(best, val);
beta = Math.min(beta, best);
// Alpha Beta Pruning
if (beta <= alpha)
break;
}
return best;
}
}
// Driver Code
public static void main (String[] args)
{
int values[] = {3, 5, 6, 9, 1, 2, 0, -1};
System.out.println("The optimal value is : " +
minimax(0, 0, true, values, MIN, MAX));
}
}
// This code is contributed by vt_m.
Output :
Source
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-4-alpha-beta-pruning/
98
Chapter 18
Pseudocode :
99
Chapter 18. Minimax Algorithm in Game Theory | Set 5 (Zobrist Hashing)
Explanation :
The idea behind Zobrist Hashing is that for a given board state, if there is a piece on a given
cell, we use the random number of that piece from the corresponding cell in the table.
If more bits are there in the random number the lesser chance of a hash collision. Therefore
64 bit numbers are commonly used as the standard and it is highly unlikely for a hash
collision to occur with such large numbers. The table has to be initialized only once during
the programs execution.
Also the reason why Zobrist Hashing is widely used in board games is because when a player
makes a move, it is not necessary to recalculate the hash value from scratch. Due to the
nature of XOR operation we can simply use few XOR operations to recalculate the hash
value.
Implementation :
We shall try to find a hash value for the given board configuration.
100
Chapter 18. Minimax Algorithm in Game Theory | Set 5 (Zobrist Hashing)
if (piece=='K')
return 5;
if (piece=='p')
return 6;
if (piece=='n')
return 7;
if (piece=='b')
return 8;
if (piece=='r')
return 9;
if (piece=='q')
return 10;
if (piece=='k')
return 11;
else
return -1;
}
// Initializes the table
void initTable()
{
for (int i = 0; i<8; i++)
for (int j = 0; j<8; j++)
for (int k = 0; k<12; k++)
ZobristTable[i][j][k] = randomInt();
}
// Computes the hash value of a given board
unsigned long long int computeHash(char board[8][9])
{
unsigned long long int h = 0;
for (int i = 0; i<8; i++)
{
for (int j = 0; j<8; j++)
{
if (board[i][j]!='-')
{
int piece = indexOf(board[i][j]);
h ^= ZobristTable[i][j][piece];
}
}
}
return h;
}
// Main Function
int main()
{
101
Chapter 18. Minimax Algorithm in Game Theory | Set 5 (Zobrist Hashing)
102
Chapter 18. Minimax Algorithm in Game Theory | Set 5 (Zobrist Hashing)
Output :
Source
https://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-5-zobrist-hashing/
103
Chapter 19
104
Chapter 19. Optimal Strategy for a Game | DP-31
So if the user follows the second game state, maximum value can be collected although the
first move is not the best.
There are two choices:
1. The user chooses the ith coin with value Vi: The opponent either chooses (i+1)th coin
or jth coin. The opponent intends to choose the coin which leaves the user with minimum
value.
i.e. The user can collect the value Vi + min(F(i+2, j), F(i+1, j-1) )
2. The user chooses the jth coin with value Vj: The opponent either chooses ith coin or
(j-1)th coin. The opponent intends to choose the coin which leaves the user with minimum
value.
i.e. The user can collect the value Vj + min(F(i+1, j-1), F(i, j-2) )
Following is recursive solution that is based on above two choices. We take the maximum
of two choices.
F(i, j) represents the maximum value the user can collect from
i'th coin to j'th coin.
105
Chapter 19. Optimal Strategy for a Game | DP-31
calculated twice.
C++
106
Chapter 19. Optimal Strategy for a Game | DP-31
Java
107
Chapter 19. Optimal Strategy for a Game | DP-31
// Driver program
public static void main(String[] args)
{
int arr1[] = { 8, 15, 3, 7 };
int n = arr1.length;
System.out.println("" + optimalStrategyOfGame(arr1, n));
int arr2[] = { 2, 2, 2, 2 };
n = arr2.length;
System.out.println("" + optimalStrategyOfGame(arr2, n));
int arr3[] = { 20, 30, 2, 2, 2, 10 };
n = arr3.length;
System.out.println("" + optimalStrategyOfGame(arr3, n));
}
}
// This code is contributed by vt_m
Output:
22
4
42
Exercise
Your thoughts on the strategy when the user wishes to only win instead of winning with the
maximum value. Like above problem, number of coins is even.
Can Greedy approach work quite well and give an optimal solution? Will your answer
change if number of coins is odd? Please see Coin game of two corners
This article is compiled by Aashish Barnwal. Please write comments if you find anything
incorrect, or you want to share more information about the topic discussed above
Source
https://www.geeksforgeeks.org/optimal-strategy-for-a-game-dp-31/
108
Chapter 20
• If A and B each betray the other, each of them serves 2 years in prison
• If A betrays B but B remains silent, A will be set free and B will serve 3 years in
prison (and vice versa)
• If A and B both remain silent, both of them will only serve 1 year in prison (on the
lesser charge)
109
Chapter 20. The prisoner’s dilemma in Game theory
Let’s analyze the nature of the dilemma assuming that both understand the nature of the
game, and that despite being members of the same gang, they have no loyalty to each other
and will have no opportunity for retribution or reward outside the game.
Please try to think over the solution for a while and analyze each case yourself.
By analyzing the table we can see that:
You are always punished less for choosing to betray the other person. However,
as a group, both of you fare better by cooperating(remaining silent).
Think over the above statement for a while.
If you have problem in analyzing this then you can watch this video: Khan Academy’s
explaination
This is the dilemma both the prisoner’s face. Should one cooperate or betray?
Even if the best solution would be both the prisoners cooperating with each other but due
to uncertainty on each other both of them betray each other getting a lesser optimum
solution.
This can be observed in may real-life cases like:
• A pair working on a project. You do best if your competitor does all the work, since
you get the same grade. But if neither of you do the work, you both fail.
• Advertising. If both companies spend money on advertising, their market share won’t
110
Chapter 20. The prisoner’s dilemma in Game theory
change from if neither does. But if one company outspends the other, they will receive
a benefit.
The prisoner’s dilemma demonstrates that two rational people might not cooperate even if
it is in their best interest to do so. Just keep looking around in this beautiful world. Who
knows you can find yourself in a prisoner’s dilemma one day!
Source
https://www.geeksforgeeks.org/prisoners-dilemma-game-theory/
111
Chapter 21
Approach:
Grundy number for each pile is calculated based on the number of stones.To compensate
112
Chapter 21. Variation in Nim Game
the zero move we will have to modify grundy values we used in standard nim game.
If pile size is odd; grundy number is size+1 and
if pile size is even; grundy number is size-1.
We XOR all the grundy number values to check if final Grundy number(G) of game is non
zero or not to decide who is winner of game.
Explanation:
Grundy number of a state is the smallest positive integer that cannot be reached in
one valid move.
So, we need to calculate mex value for each n, bottom up wise so that we can induce the
grundy number for each n. where n is the pile size and valid move is the move that will lead
the current player to winning state.
Winning state: A tuple of values from where the current player will win the game no
matter what opponent does. (If G!=0)
Losing state: A tuple of values from where the current player will loose the game no matter
what opponent does. (If G=0)
113
Chapter 21. Variation in Nim Game
C++
114
Chapter 21. Variation in Nim Game
Java
115
Chapter 21. Variation in Nim Game
// This code is contributed by Anant Agarwal.
Python3
C#
116
Chapter 21. Variation in Nim Game
117
Chapter 21. Variation in Nim Game
// This code is contributed by vt_m.
PHP
<?php
// php program for the variation
// in nim game
// Function to return final
// grundy Number(G) of game
function solve($p,$n)
{
$G = 0;
for ($i = 0; $i < $n; $i++)
{
// if pile size is odd
if ($p[$i] & 1)
// We XOR pile size+1
$G ^= ($p[$i] + 1);
else // if pile size is even
// We XOR pile size-1
$G ^= ($p[$i] - 1);
}
return $G;
}
// Driver Code
// Game with 3 piles
$n = 3;
// pile with different sizes
$p= array( 32, 49, 58 );
// Function to return result of game
$res = solve($p, $n);
if ($res == 0) // if G is zero
echo "Player 2 wins";
else // if G is non zero
echo "Player 1 wins";
// This code is contributed by mits
?>
118
Chapter 21. Variation in Nim Game
Output:
Player 1 wins
Source
https://www.geeksforgeeks.org/variation-nim-game/
119