Bunty and Dolly are playing a game, described as follows: There are two boxes having A and B number of chocolates respectively. Both can eat L (L >= 1) chocolates from any one box or L chocolates from both boxes in one move. They play the game alternatively and the last one to eat the chocolate will be the winner.
You have to help Bunty in deciding who should play first such that Dolly is always the winner. Assume that both players play optimally.
Note: This game is also known as Wythoff's Game.
Examples:
Input: A = 1 and B = 2 Output: Bunty Explanation: If Bunty starts first, all the possible states after Bunty eats chocolates are (0, 2), (1, 1), (1, 0). These are all wining states for Dolly
Input: A = 1 and B = 3 Output: Dolly Explanation: If Dolly starts first, all the possible states after Dolly eats chocolates are (0, 3), (1, 2), (1, 1), (1, 0), (0, 2). Out of these, (1, 2) is the winning state for Dolly.
[Naive Approach] Using Recursion and Memoization - O(A * B) Time and O(A * B) Space
All states of chocolates can be uniquely identified using two integers (n, m) where n and m are number of chocolates in the first and second box respectively. Now each state can be classified into two categories:
Cold State - State from which the current player will always lose the game. This is a state where all the possible moves will result in losing of the current player. Example: (1, 2), (2, 4)
Hot State - State from which the current player can win the game. This is a state where at least one of the moves will result in winning of the current player.
The task is to check if the given state (A, B) is a hot state or cold state and if it is a hot state, Dolly should start otherwise Bunty should start the game. In the recursive function, try for all the possible combinations by eating chocolates from the first box or the second box or from both the boxes simultaneously.
We can use Dynamic Programming and memoize the solution using a dp[][] table such that dp[i][j] stores the result for state (i, j).
Below is the implementation of the algorithm:
C++
// C++ Code for Wythoff's Game#include<bits/stdc++.h>usingnamespacestd;intisHotState(intA,intB,vector<vector<int>>&dp){// If there are no chocolates, then the current player// losesif(A==0&&B==0)return0;// If one box is empty and other box is not empty, the// current player wins by eating all the remaining// chocolates from the boxif(A==0||B==0)return1;// Check if the result has been already calculated previouslyif(dp[A][B]!=-1)returndp[A][B];// Try all combinations by eating chocolates from the// first boxfor(inteaten=1;eaten<=A;eaten++){if(!isHotState(A-eaten,B,dp))returndp[A][B]=1;}// Try all combinations by eating chocolates from the// second boxfor(inteaten=1;eaten<=B;eaten++){if(!isHotState(A,B-eaten,dp))returndp[A][B]=1;}// Try all the combinations by eating chocolates from// both the boxes simultaneouslyfor(inteaten=1;eaten<=min(A,B);eaten++){if(!isHotState(A-eaten,B-eaten,dp))returndp[A][B]=1;}returndp[A][B]=0;}boolgame(intA,intB){vector<vector<int>>dp(A+1,vector<int>(B+1,-1));returnisHotState(A,B,dp)==1;}intmain(){// Sample InputintA=1,B=3;// Function callif(game(A,B))cout<<"Dolly";elsecout<<"Bunty";return0;}
Java
// Java Program for Wythoff’s Gameimportjava.util.Arrays;publicclassGFG{// Function to determine if the current state is a "hot// state" (winning position for the current player)publicstaticintisHotState(intA,intB,int[][]dp){// If there are no chocolates, then the current// player losesif(A==0&&B==0){return0;}// If one box is empty and other box is not empty,// the current player wins by eating all the// remaining chocolates from the boxif(A==0||B==0){return1;}// Check if the result has been already calculated// previouslyif(dp[A][B]!=-1){returndp[A][B];}// Try all combinations by eating chocolates from// the first boxfor(inteaten=1;eaten<=A;eaten++){if(isHotState(A-eaten,B,dp)==0){returndp[A][B]=1;}}// Try all combinations by eating chocolates from// the second boxfor(inteaten=1;eaten<=B;eaten++){if(isHotState(A,B-eaten,dp)==0){returndp[A][B]=1;}}// Try all the combinations by eating chocolates// from both the boxes simultaneouslyfor(inteaten=1;eaten<=Math.min(A,B);eaten++){if(isHotState(A-eaten,B-eaten,dp)==0){returndp[A][B]=1;}}returndp[A][B]=0;}// Main game function that initializes the DP table and// determines the winnerpublicstaticbooleangame(intA,intB){int[][]dp=newint[A+1][B+1];for(int[]row:dp){Arrays.fill(row,-1);}returnisHotState(A,B,dp)==1;}publicstaticvoidmain(String[]args){// Sample InputintA=1,B=3;// Function callif(game(A,B)){System.out.println("Dolly");}else{System.out.println("Bunty");}}}
Python
# Python Code for Wythoff's Gamedefis_hot_state(A,B,dp):# If there are no chocolates, then the current player losesifA==0andB==0:return0# If one box is empty and the other box is not empty, the# current player wins by eating all the remaining chocolates from the boxifA==0orB==0:return1# Check if the result has been already calculated previouslyifdp[A][B]!=-1:returndp[A][B]# Try all combinations by eating chocolates from the first boxforeateninrange(1,A+1):ifis_hot_state(A-eaten,B,dp)==0:dp[A][B]=1returndp[A][B]# Try all combinations by eating chocolates from the second boxforeateninrange(1,B+1):ifis_hot_state(A,B-eaten,dp)==0:dp[A][B]=1returndp[A][B]# Try all the combinations by eating chocolates from both the boxes simultaneouslyforeateninrange(1,min(A,B)+1):ifis_hot_state(A-eaten,B-eaten,dp)==0:dp[A][B]=1returndp[A][B]dp[A][B]=0returndp[A][B]defgame(A,B):# Initialize the DP tabledp=[[-1for_inrange(B+1)]for_inrange(A+1)]# Check the initial statereturnis_hot_state(A,B,dp)==1# Sample InputA=1B=3# Function callifgame(A,B):print("Dolly")else:print("Bunty")
C#
usingSystem;classGFG{// Function to determine if the current state is a "hot state" (winning position for the current player)staticintIsHotState(intA,intB,int[,]dp){// If there are no chocolates, then the current player losesif(A==0&&B==0)return0;// If one box is empty and the other box is not empty, the current player wins by eating all the remaining chocolates from the boxif(A==0||B==0)return1;// Check if the result has been already calculated previouslyif(dp[A,B]!=-1)returndp[A,B];// Try all combinations by eating chocolates from the first boxfor(inteaten=1;eaten<=A;eaten++){if(IsHotState(A-eaten,B,dp)==0){dp[A,B]=1;returndp[A,B];}}// Try all combinations by eating chocolates from the second boxfor(inteaten=1;eaten<=B;eaten++){if(IsHotState(A,B-eaten,dp)==0){dp[A,B]=1;returndp[A,B];}}// Try all the combinations by eating chocolates from both the boxes simultaneouslyfor(inteaten=1;eaten<=Math.Min(A,B);eaten++){if(IsHotState(A-eaten,B-eaten,dp)==0){dp[A,B]=1;returndp[A,B];}}dp[A,B]=0;returndp[A,B];}// Main game function that initializes the DP table and determines the winnerstaticboolGame(intA,intB){// Initialize the DP table with -1 for uncomputed statesint[,]dp=newint[A+1,B+1];for(inti=0;i<=A;i++){for(intj=0;j<=B;j++){dp[i,j]=-1;}}// Check the initial statereturnIsHotState(A,B,dp)==1;}staticvoidMain(){// Sample InputintA=1,B=3;// Function callif(Game(A,B))Console.WriteLine("Dolly");elseConsole.WriteLine("Bunty");}}
JavaScript
// JavaScript Code for Wythoff's GamefunctionisHotState(A,B,dp){// If there are no chocolates, then the current player losesif(A===0&&B===0)return0;// If one box is empty and the other box is not empty, the current player wins by eating all the remaining chocolates from the boxif(A===0||B===0)return1;// Check if the result has been already calculated previouslyif(dp[A][B]!==-1)returndp[A][B];// Try all combinations by eating chocolates from the first boxfor(leteaten=1;eaten<=A;eaten++){if(isHotState(A-eaten,B,dp)===0){dp[A][B]=1;returndp[A][B];}}// Try all combinations by eating chocolates from the second boxfor(leteaten=1;eaten<=B;eaten++){if(isHotState(A,B-eaten,dp)===0){dp[A][B]=1;returndp[A][B];}}// Try all the combinations by eating chocolates from both the boxes simultaneouslyfor(leteaten=1;eaten<=Math.min(A,B);eaten++){if(isHotState(A-eaten,B-eaten,dp)===0){dp[A][B]=1;returndp[A][B];}}dp[A][B]=0;returndp[A][B];}functiongame(A,B){// Initialize the DP table with -1 for uncomputed statesconstdp=Array.from({length:A+1},()=>Array(B+1).fill(-1));// Check the initial statereturnisHotState(A,B,dp)===1;}// Sample InputconstA=1,B=3;// Function callif(game(A,B)){console.log("Dolly");}else{console.log("Bunty");}
Output
Dolly
[Expected Approach] Using Golden Ratio - O(1) Time and O(1) Space
On observing carefully, if we plot all cold states in a graph then the ratio of the lines come out to be Φ and 1/Φ, where Φ is the golden ratio (which is (1 + sqrt(5))/2). It is also observed that all the coordinates of cold positions are unique and their x and y coordinates differ by k where k >= 1. So, the cold positions can be calculated by floor value of (k*Φ, k*Φ*Φ) where k>=1. For example:
If k = 1, cold state = (floor(1 * Φ), floor(1 * Φ * Φ)) = (floor(1.618), floor(2.618)) = (1, 2) and difference between coordinates = k = 1.
If k = 2, cold state = (floor(2 * Φ), floor(2 * Φ * Φ)) = (floor(3.236), floor(5.236)) = (3, 5) and difference between coordinates = k = 2.
If k = 3, cold state = (floor(3 * Φ), floor(3 * Φ * Φ)) = (floor(4.854), floor(7.854)) = (4, 7) and the difference between coordinates = k = 3. And so on...
So, we can check whether (A, B) is a cold state by finding value of k = abs(A - B) and then finding the floor value of (k*Φ, k*Φ*Φ). If A = k*Φ and B = k*Φ*Φ, then (A, B) is a cold state, so Bunty should start the game. Otherwise, (A, B) is a hot state and Dolly should start the game.
Below is the implementation of the above approach:
C++
// C++ code to solve Wythoff’s Game#include<bits/stdc++.h>usingnamespacestd;// Function to decide who should play firstboolgame(intA,intB){// Swap the value if A > Bif(A>B)swap(A,B);intk=B-A;longdoublegoldenRatio=(1+sqrt(5))/2;intC=(int)(goldenRatio*k);// Return answerreturn(A==C)?0:1;}// Driver Codeintmain(){intA=1,B=3;// Function callcout<<(game(A,B)?"Dolly":"Bunty")<<endl;return0;}
Java
// Java code to solve Wythoff’s GamepublicclassWythoffGame{// Function to decide who should play firstpublicstaticbooleangame(intA,intB){// Swap the value if A > Bif(A>B){inttemp=A;A=B;B=temp;}intk=B-A;doublegoldenRatio=(1+Math.sqrt(5))/2;intC=(int)(goldenRatio*k);// Return answerreturn(A==C)?false:true;}publicstaticvoidmain(String[]args){// Sample InputintA=1,B=3;// Function callSystem.out.println(game(A,B)?"Dolly":"Bunty");}}
Python
# Python Program to find solve Wythoff's Gameimportmath# Function to decide who should play firstdefgame(A,B):# Swap the value if A > BifA>B:A,B=B,Ak=B-Agolden_ratio=(1+math.sqrt(5))/2C=int(golden_ratio*k)return0ifA==Celse1# Driver CodeA=1B=3# Function callprint("Dolly"ifgame(A,B)==1else"Bunty")
C#
// C# code to solve Wythoff’s GameusingSystem;classGFG{// Function to decide who should play firststaticintGame(intA,intB){// Swap the values if A > Bif(A>B){inttemp=A;A=B;B=temp;}intk=B-A;doublegoldenRatio=(1+Math.Sqrt(5))/2;intC=(int)(goldenRatio*k);// Return answerreturn(A==C)?0:1;}// Driver CodestaticvoidMain(){intA=1;intB=3;// Function callConsole.WriteLine(Game(A,B)==1?"Dolly":"Bunty");}}
JavaScript
// JavaScript code to solve Wythoff’s Game// Function to decide who should play firstfunctiongame(A,B){if(A>B){[A,B]=[B,A];}constk=B-A;constgoldenRatio=(1+Math.sqrt(5))/2;constC=Math.floor(goldenRatio*k);// Return answer return(A===C)?0:1;}// Driver CodeconstA=1;constB=3;// Function call and outputconsole.log(game(A,B)?"Dolly":"Bunty");